+
+ if(notify_name) {
+ ND_PRINT(" type=%u(%s)", type, notify_name);
+ }
+
+
+ spi_size = GET_U_1(p->spi_size);
+ if (showspi && spi_size) {
+ ND_PRINT(" spi=");
+ if (!rawprint(ndo, (const uint8_t *)(p + 1), spi_size))
+ goto trunc;
+ }
+
+ cp = (const u_char *)(p + 1) + spi_size;
+
+ if (cp < ep) {
+ if (ndo->ndo_vflag > 3 || (showsomedata && ep-cp < 30)) {
+ ND_PRINT(" data=(");
+ if (!rawprint(ndo, (const uint8_t *)(cp), ep - cp))
+ goto trunc;
+
+ ND_PRINT(")");
+ } else if (showsomedata) {
+ if (!ike_show_somedata(ndo, cp, ep))
+ goto trunc;
+ }
+ }
+
+ return (const u_char *)ext + item_len;
+trunc:
+ ND_PRINT(" [|%s]", NPSTR(ISAKMP_NPTYPE_N));
+ return NULL;
+}
+
+static const u_char *
+ikev2_d_print(netdissect_options *ndo, u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+ uint32_t phase _U_, uint32_t doi _U_,
+ uint32_t proto _U_, int depth _U_)
+{
+ return ikev2_gen_print(ndo, tpay, ext, item_len);
+}
+
+static const u_char *
+ikev2_vid_print(netdissect_options *ndo, u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+ uint32_t phase _U_, uint32_t doi _U_,
+ uint32_t proto _U_, int depth _U_)
+{
+ const u_char *vid;
+ u_int i, len;
+
+ ND_TCHECK_SIZE(ext);
+ ikev2_pay_print(ndo, NPSTR(tpay), GET_U_1(ext->critical));
+
+ /*
+ * Our caller has ensured that the length is >= 4.
+ */
+ ND_PRINT(" len=%u vid=", item_len - 4);
+
+ vid = (const u_char *)(ext+1);
+ len = item_len - 4;
+ ND_TCHECK_LEN(vid, len);
+ for(i=0; i<len; i++) {
+ if(ND_ASCII_ISPRINT(GET_U_1(vid + i)))
+ ND_PRINT("%c", GET_U_1(vid + i));
+ else ND_PRINT(".");
+ }
+ if (2 < ndo->ndo_vflag && 4 < len) {
+ /* Print the entire payload in hex */
+ ND_PRINT(" ");
+ if (!rawprint(ndo, (const uint8_t *)(ext + 1), item_len - 4))
+ goto trunc;
+ }
+ return (const u_char *)ext + item_len;
+trunc:
+ ND_PRINT(" [|%s]", NPSTR(tpay));
+ return NULL;
+}
+
+static const u_char *
+ikev2_TS_print(netdissect_options *ndo, u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+ uint32_t phase _U_, uint32_t doi _U_,
+ uint32_t proto _U_, int depth _U_)
+{
+ return ikev2_gen_print(ndo, tpay, ext, item_len);
+}
+
+static const u_char *
+ikev2_e_print(netdissect_options *ndo,
+#ifndef HAVE_LIBCRYPTO
+ _U_
+#endif
+ const struct isakmp *base,
+ u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+#ifndef HAVE_LIBCRYPTO
+ _U_
+#endif
+ uint32_t phase,
+#ifndef HAVE_LIBCRYPTO
+ _U_
+#endif
+ uint32_t doi,
+#ifndef HAVE_LIBCRYPTO
+ _U_
+#endif
+ uint32_t proto,
+#ifndef HAVE_LIBCRYPTO
+ _U_
+#endif
+ int depth)
+{
+ const u_char *dat;
+ u_int dlen;
+#ifdef HAVE_LIBCRYPTO
+ uint8_t np;
+#endif
+
+ ND_TCHECK_SIZE(ext);
+ ikev2_pay_print(ndo, NPSTR(tpay), GET_U_1(ext->critical));
+
+ dlen = item_len-4;
+
+ ND_PRINT(" len=%u", dlen);
+ if (2 < ndo->ndo_vflag && 4 < dlen) {
+ ND_PRINT(" ");
+ if (!rawprint(ndo, (const uint8_t *)(ext + 1), dlen))
+ goto trunc;
+ }
+
+ dat = (const u_char *)(ext+1);
+ ND_TCHECK_LEN(dat, dlen);
+
+#ifdef HAVE_LIBCRYPTO
+ np = GET_U_1(ext->np);
+
+ /* try to decrypt it! */
+ if(esp_decrypt_buffer_by_ikev2_print(ndo,
+ GET_U_1(base->flags) & ISAKMP_FLAG_I,
+ base->i_ck, base->r_ck,
+ dat, dat+dlen)) {
+
+ ext = (const struct isakmp_gen *)ndo->ndo_packetp;
+
+ /* got it decrypted, print stuff inside. */
+ ikev2_sub_print(ndo, base, np, ext,
+ ndo->ndo_snapend, phase, doi, proto, depth+1);
+
+ /*
+ * esp_decrypt_buffer_by_ikev2_print pushed information
+ * on the buffer stack; we're done with the buffer, so
+ * pop it (which frees the buffer)
+ */
+ nd_pop_packet_info(ndo);
+ }
+#endif
+
+
+ /* always return NULL, because E must be at end, and NP refers
+ * to what was inside.
+ */
+ return NULL;
+trunc:
+ ND_PRINT(" [|%s]", NPSTR(tpay));
+ return NULL;
+}
+
+static const u_char *
+ikev2_cp_print(netdissect_options *ndo, u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+ uint32_t phase _U_, uint32_t doi _U_,
+ uint32_t proto _U_, int depth _U_)
+{
+ return ikev2_gen_print(ndo, tpay, ext, item_len);
+}
+
+static const u_char *
+ikev2_eap_print(netdissect_options *ndo, u_char tpay,
+ const struct isakmp_gen *ext,
+ u_int item_len, const u_char *ep _U_,
+ uint32_t phase _U_, uint32_t doi _U_,
+ uint32_t proto _U_, int depth _U_)
+{
+ return ikev2_gen_print(ndo, tpay, ext, item_len);
+}
+
+static const u_char *
+ike_sub0_print(netdissect_options *ndo,
+ u_char np, const struct isakmp_gen *ext, const u_char *ep,
+
+ uint32_t phase, uint32_t doi, uint32_t proto, int depth)
+{
+ const u_char *cp;
+ u_int item_len;
+
+ cp = (const u_char *)ext;
+ ND_TCHECK_SIZE(ext);
+
+ /*
+ * Since we can't have a payload length of less than 4 bytes,
+ * we need to bail out here if the generic header is nonsensical
+ * or truncated, otherwise we could loop forever processing
+ * zero-length items or otherwise misdissect the packet.
+ */
+ item_len = GET_BE_U_2(ext->len);
+ if (item_len <= 4)
+ return NULL;
+
+ if (NPFUNC(np)) {
+ /*
+ * XXX - what if item_len is too short, or too long,
+ * for this payload type?
+ */
+ cp = (*npfunc[np])(ndo, np, ext, item_len, ep, phase, doi, proto, depth);
+ } else {
+ ND_PRINT("%s", NPSTR(np));
+ cp += item_len;
+ }
+
+ return cp;
+trunc:
+ nd_print_trunc(ndo);
+ return NULL;
+}
+
+static const u_char *
+ikev1_sub_print(netdissect_options *ndo,
+ u_char np, const struct isakmp_gen *ext, const u_char *ep,
+ uint32_t phase, uint32_t doi, uint32_t proto, int depth)
+{
+ const u_char *cp;
+ int i;
+ u_int item_len;
+
+ cp = (const u_char *)ext;
+
+ while (np) {
+ ND_TCHECK_SIZE(ext);
+
+ item_len = GET_BE_U_2(ext->len);
+ ND_TCHECK_LEN(ext, item_len);
+
+ depth++;
+ ND_PRINT("\n");
+ for (i = 0; i < depth; i++)
+ ND_PRINT(" ");
+ ND_PRINT("(");
+ cp = ike_sub0_print(ndo, np, ext, ep, phase, doi, proto, depth);
+ ND_PRINT(")");
+ depth--;
+
+ if (cp == NULL) {
+ /* Zero-length subitem */
+ return NULL;
+ }
+
+ np = GET_U_1(ext->np);
+ ext = (const struct isakmp_gen *)cp;
+ }
+ return cp;
+trunc:
+ ND_PRINT(" [|%s]", NPSTR(np));
+ return NULL;
+}
+
+static char *
+numstr(u_int x)
+{
+ static char buf[20];
+ snprintf(buf, sizeof(buf), "#%u", x);
+ return buf;
+}
+
+static void
+ikev1_print(netdissect_options *ndo,
+ const u_char *bp, u_int length,
+ const u_char *bp2, const struct isakmp *base)
+{
+ const struct isakmp *p;
+ const u_char *ep;
+ u_int flags;
+ u_char np;
+ int i;
+ u_int phase;
+
+ p = (const struct isakmp *)bp;
+ ep = ndo->ndo_snapend;
+
+ phase = (GET_BE_U_4(base->msgid) == 0) ? 1 : 2;
+ if (phase == 1)
+ ND_PRINT(" phase %u", phase);
+ else
+ ND_PRINT(" phase %u/others", phase);
+
+ i = cookie_find(&base->i_ck);
+ if (i < 0) {
+ if (iszero(ndo, base->r_ck, sizeof(base->r_ck))) {
+ /* the first packet */
+ ND_PRINT(" I");
+ if (bp2)
+ cookie_record(ndo, &base->i_ck, bp2);
+ } else
+ ND_PRINT(" ?");
+ } else {
+ if (bp2 && cookie_isinitiator(ndo, i, bp2))
+ ND_PRINT(" I");
+ else if (bp2 && cookie_isresponder(ndo, i, bp2))
+ ND_PRINT(" R");
+ else
+ ND_PRINT(" ?");
+ }
+
+ ND_PRINT(" %s", ETYPESTR(GET_U_1(base->etype)));
+ flags = GET_U_1(base->flags);
+ if (flags) {
+ ND_PRINT("[%s%s]", flags & ISAKMP_FLAG_E ? "E" : "",
+ flags & ISAKMP_FLAG_C ? "C" : "");
+ }
+
+ if (ndo->ndo_vflag) {
+ const struct isakmp_gen *ext;
+
+ ND_PRINT(":");
+
+ np = GET_U_1(base->np);
+
+ /* regardless of phase... */
+ if (flags & ISAKMP_FLAG_E) {
+ /*
+ * encrypted, nothing we can do right now.
+ * we hope to decrypt the packet in the future...
+ */
+ ND_PRINT(" [encrypted %s]", NPSTR(np));
+ goto done;
+ }
+
+ CHECKLEN(p + 1, np);
+ ext = (const struct isakmp_gen *)(p + 1);
+ ikev1_sub_print(ndo, np, ext, ep, phase, 0, 0, 0);
+ }
+
+done:
+ if (ndo->ndo_vflag) {
+ if (GET_BE_U_4(base->len) != length) {
+ ND_PRINT(" (len mismatch: isakmp %u/ip %u)",
+ GET_BE_U_4(base->len), length);
+ }
+ }
+}
+
+static const u_char *
+ikev2_sub0_print(netdissect_options *ndo, const struct isakmp *base,
+ u_char np,
+ const struct isakmp_gen *ext, const u_char *ep,
+ uint32_t phase, uint32_t doi, uint32_t proto, int depth)
+{
+ const u_char *cp;
+ u_int item_len;
+
+ cp = (const u_char *)ext;
+ ND_TCHECK_SIZE(ext);
+
+ /*
+ * Since we can't have a payload length of less than 4 bytes,
+ * we need to bail out here if the generic header is nonsensical
+ * or truncated, otherwise we could loop forever processing
+ * zero-length items or otherwise misdissect the packet.
+ */
+ item_len = GET_BE_U_2(ext->len);
+ if (item_len <= 4)
+ return NULL;
+
+ if (np == ISAKMP_NPTYPE_v2E) {
+ cp = ikev2_e_print(ndo, base, np, ext, item_len,
+ ep, phase, doi, proto, depth);
+ } else if (NPFUNC(np)) {
+ /*
+ * XXX - what if item_len is too short, or too long,
+ * for this payload type?
+ */
+ cp = (*npfunc[np])(ndo, np, ext, item_len,
+ ep, phase, doi, proto, depth);
+ } else {
+ ND_PRINT("%s", NPSTR(np));
+ cp += item_len;
+ }
+
+ return cp;
+trunc:
+ nd_print_trunc(ndo);
+ return NULL;
+}
+
+static const u_char *
+ikev2_sub_print(netdissect_options *ndo,
+ const struct isakmp *base,
+ u_char np, const struct isakmp_gen *ext, const u_char *ep,
+ uint32_t phase, uint32_t doi, uint32_t proto, int depth)
+{
+ const u_char *cp;
+ int i;
+
+ cp = (const u_char *)ext;
+ while (np) {
+ ND_TCHECK_SIZE(ext);
+
+ ND_TCHECK_LEN(ext, GET_BE_U_2(ext->len));
+
+ depth++;
+ ND_PRINT("\n");
+ for (i = 0; i < depth; i++)
+ ND_PRINT(" ");
+ ND_PRINT("(");
+ cp = ikev2_sub0_print(ndo, base, np,
+ ext, ep, phase, doi, proto, depth);
+ ND_PRINT(")");
+ depth--;
+
+ if (cp == NULL) {
+ /* Zero-length subitem */
+ return NULL;
+ }
+
+ np = GET_U_1(ext->np);
+ ext = (const struct isakmp_gen *)cp;
+ }
+ return cp;
+trunc:
+ ND_PRINT(" [|%s]", NPSTR(np));
+ return NULL;
+}
+
+static void
+ikev2_print(netdissect_options *ndo,
+ const u_char *bp, u_int length,
+ const u_char *bp2 _U_, const struct isakmp *base)
+{
+ const struct isakmp *p;
+ const u_char *ep;
+ uint8_t flags;
+ u_char np;
+ u_int phase;
+
+ p = (const struct isakmp *)bp;
+ ep = ndo->ndo_snapend;
+
+ phase = (GET_BE_U_4(base->msgid) == 0) ? 1 : 2;
+ if (phase == 1)
+ ND_PRINT(" parent_sa");
+ else
+ ND_PRINT(" child_sa ");
+
+ ND_PRINT(" %s", ETYPESTR(GET_U_1(base->etype)));
+ flags = GET_U_1(base->flags);
+ if (flags) {
+ ND_PRINT("[%s%s%s]",
+ flags & ISAKMP_FLAG_I ? "I" : "",
+ flags & ISAKMP_FLAG_V ? "V" : "",
+ flags & ISAKMP_FLAG_R ? "R" : "");
+ }
+
+ if (ndo->ndo_vflag) {
+ const struct isakmp_gen *ext;
+
+ ND_PRINT(":");
+
+ np = GET_U_1(base->np);
+
+ /* regardless of phase... */
+ if (flags & ISAKMP_FLAG_E) {
+ /*
+ * encrypted, nothing we can do right now.
+ * we hope to decrypt the packet in the future...
+ */
+ ND_PRINT(" [encrypted %s]", NPSTR(np));
+ goto done;
+ }
+
+ CHECKLEN(p + 1, np)
+ ext = (const struct isakmp_gen *)(p + 1);
+ ikev2_sub_print(ndo, base, np, ext, ep, phase, 0, 0, 0);
+ }
+
+done:
+ if (ndo->ndo_vflag) {
+ if (GET_BE_U_4(base->len) != length) {
+ ND_PRINT(" (len mismatch: isakmp %u/ip %u)",
+ GET_BE_U_4(base->len), length);
+ }
+ }
+}
+
+void
+isakmp_print(netdissect_options *ndo,
+ const u_char *bp, u_int length,
+ const u_char *bp2)
+{
+ const struct isakmp *p;
+ const u_char *ep;
+ u_int major, minor;
+
+ ndo->ndo_protocol = "isakmp";
+#ifdef HAVE_LIBCRYPTO
+ /* initialize SAs */
+ if (ndo->ndo_sa_list_head == NULL) {
+ if (ndo->ndo_espsecret)
+ esp_decodesecret_print(ndo);
+ }
+#endif
+
+ p = (const struct isakmp *)bp;
+ ep = ndo->ndo_snapend;
+
+ if ((const struct isakmp *)ep < p + 1) {
+ nd_print_trunc(ndo);
+ return;
+ }
+
+ ND_PRINT("isakmp");
+ major = (GET_U_1(p->vers) & ISAKMP_VERS_MAJOR)
+ >> ISAKMP_VERS_MAJOR_SHIFT;
+ minor = (GET_U_1(p->vers) & ISAKMP_VERS_MINOR)
+ >> ISAKMP_VERS_MINOR_SHIFT;
+
+ if (ndo->ndo_vflag) {
+ ND_PRINT(" %u.%u", major, minor);
+ }
+
+ if (ndo->ndo_vflag) {
+ ND_PRINT(" msgid ");
+ hexprint(ndo, p->msgid, sizeof(p->msgid));
+ }
+
+ if (1 < ndo->ndo_vflag) {
+ ND_PRINT(" cookie ");
+ hexprint(ndo, p->i_ck, sizeof(p->i_ck));
+ ND_PRINT("->");
+ hexprint(ndo, p->r_ck, sizeof(p->r_ck));
+ }
+ ND_PRINT(":");
+
+ switch(major) {
+ case IKEv1_MAJOR_VERSION:
+ ikev1_print(ndo, bp, length, bp2, p);
+ break;
+
+ case IKEv2_MAJOR_VERSION:
+ ikev2_print(ndo, bp, length, bp2, p);
+ break;
+ }
+}
+
+void
+isakmp_rfc3948_print(netdissect_options *ndo,
+ const u_char *bp, u_int length,
+ const u_char *bp2, int ver, int fragmented, u_int ttl_hl)
+{
+ ndo->ndo_protocol = "isakmp_rfc3948";
+ if(length == 1 && GET_U_1(bp)==0xff) {
+ ND_PRINT("isakmp-nat-keep-alive");
+ return;
+ }
+
+ if(length < 4) {
+ goto trunc;
+ }
+
+ /*
+ * see if this is an IKE packet
+ */
+ if (GET_BE_U_4(bp) == 0) {
+ ND_PRINT("NONESP-encap: ");
+ isakmp_print(ndo, bp+4, length-4, bp2);
+ return;
+ }
+
+ /* must be an ESP packet */
+ {
+ ND_PRINT("UDP-encap: ");
+
+ esp_print(ndo, bp, length, bp2, ver, fragmented, ttl_hl);
+
+ /*
+ * Either this has decrypted the payload and
+ * printed it, in which case there's nothing more
+ * to do, or it hasn't, in which case there's
+ * nothing more to do.
+ */
+ return;
+ }
+
+trunc:
+ nd_print_trunc(ndo);