]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-isakmp.c
Force -t on in TESTonce.
[tcpdump] / print-isakmp.c
index 4b04ccde8119326cc00053cbd9a649510a5a34c3..3dfa171f2bb5d192ba327749dbf5dbe82640b41f 100644 (file)
@@ -28,6 +28,8 @@
  *
  */
 
+/* \summary: Internet Security Association and Key Management Protocol (ISAKMP) printer */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -48,9 +50,7 @@
 #include "extract.h"
 
 #include "ip.h"
-#ifdef INET6
 #include "ip6.h"
-#endif
 
 /* refer to RFC 2408 */
 
@@ -644,14 +644,12 @@ ikev1_print(netdissect_options *ndo,
            const u_char *bp2, struct isakmp *base);
 
 #define MAXINITIATORS  20
-int ninitiator = 0;
+static int ninitiator = 0;
 union inaddr_u {
        struct in_addr in4;
-#ifdef INET6
        struct in6_addr in6;
-#endif
 };
-struct {
+static struct {
        cookie_t initiator;
        u_int version;
        union inaddr_u iaddr;
@@ -781,9 +779,7 @@ cookie_record(cookie_t *in, const u_char *bp2)
 {
        int i;
        const struct ip *ip;
-#ifdef INET6
        const struct ip6_hdr *ip6;
-#endif
 
        i = cookie_find(in);
        if (0 <= i) {
@@ -798,14 +794,12 @@ cookie_record(cookie_t *in, const u_char *bp2)
                UNALIGNED_MEMCPY(&cookiecache[ninitiator].iaddr.in4, &ip->ip_src, sizeof(struct in_addr));
                UNALIGNED_MEMCPY(&cookiecache[ninitiator].raddr.in4, &ip->ip_dst, sizeof(struct in_addr));
                break;
-#ifdef INET6
        case 6:
                ip6 = (const struct ip6_hdr *)bp2;
                cookiecache[ninitiator].version = 6;
                UNALIGNED_MEMCPY(&cookiecache[ninitiator].iaddr.in6, &ip6->ip6_src, sizeof(struct in6_addr));
                UNALIGNED_MEMCPY(&cookiecache[ninitiator].raddr.in6, &ip6->ip6_dst, sizeof(struct in6_addr));
                break;
-#endif
        default:
                return;
        }
@@ -819,9 +813,7 @@ static int
 cookie_sidecheck(int i, const u_char *bp2, int initiator)
 {
        const struct ip *ip;
-#ifdef INET6
        const struct ip6_hdr *ip6;
-#endif
 
        ip = (const struct ip *)bp2;
        switch (IP_V(ip)) {
@@ -836,7 +828,6 @@ cookie_sidecheck(int i, const u_char *bp2, int initiator)
                                return 1;
                }
                break;
-#ifdef INET6
        case 6:
                if (cookiecache[i].version != 6)
                        return 0;
@@ -849,7 +840,6 @@ cookie_sidecheck(int i, const u_char *bp2, int initiator)
                                return 1;
                }
                break;
-#endif /* INET6 */
        default:
                break;
        }
@@ -1406,7 +1396,6 @@ ikev1_id_print(netdissect_options *ndo, u_char tpay _U_,
                        len = 0;
                        break;
                    }
-#ifdef INET6
                case IPSECDOI_ID_IPV6_ADDR:
                        if (len < 16)
                                ND_PRINT((ndo," len=%d [bad: < 16]", len));
@@ -1432,7 +1421,6 @@ ikev1_id_print(netdissect_options *ndo, u_char tpay _U_,
                        len = 0;
                        break;
                    }
-#endif /*INET6*/
                case IPSECDOI_ID_IPV4_ADDR_RANGE:
                        if (len < 8)
                                ND_PRINT((ndo," len=%d [bad: < 8]", len));
@@ -1443,7 +1431,6 @@ ikev1_id_print(netdissect_options *ndo, u_char tpay _U_,
                        }
                        len = 0;
                        break;
-#ifdef INET6
                case IPSECDOI_ID_IPV6_ADDR_RANGE:
                        if (len < 32)
                                ND_PRINT((ndo," len=%d [bad: < 32]", len));
@@ -1454,7 +1441,6 @@ ikev1_id_print(netdissect_options *ndo, u_char tpay _U_,
                        }
                        len = 0;
                        break;
-#endif /*INET6*/
                case IPSECDOI_ID_DER_ASN1_DN:
                case IPSECDOI_ID_DER_ASN1_GN:
                case IPSECDOI_ID_KEY_ID:
@@ -1479,7 +1465,7 @@ trunc:
 
 static const u_char *
 ikev1_cert_print(netdissect_options *ndo, u_char tpay _U_,
-                const struct isakmp_gen *ext, u_int item_len _U_,
+                const struct isakmp_gen *ext, u_int item_len,
                 const u_char *ep _U_, uint32_t phase _U_,
                 uint32_t doi0 _U_,
                 uint32_t proto0 _U_, int depth _U_)
@@ -1512,7 +1498,7 @@ trunc:
 
 static const u_char *
 ikev1_cr_print(netdissect_options *ndo, u_char tpay _U_,
-              const struct isakmp_gen *ext, u_int item_len _U_,
+              const struct isakmp_gen *ext, u_int item_len,
               const u_char *ep _U_, uint32_t phase _U_, uint32_t doi0 _U_,
               uint32_t proto0 _U_, int depth _U_)
 {
@@ -1594,7 +1580,7 @@ static const u_char *
 ikev1_nonce_print(netdissect_options *ndo, u_char tpay _U_,
                  const struct isakmp_gen *ext,
                  u_int item_len _U_,
-                 const u_char *ep _U_,
+                 const u_char *ep,
                  uint32_t phase _U_, uint32_t doi _U_,
                  uint32_t proto _U_, int depth _U_)
 {
@@ -1866,10 +1852,9 @@ trunc:
 }
 
 static const u_char *
-ikev2_t_print(netdissect_options *ndo, u_char tpay _U_, int pcount,
+ikev2_t_print(netdissect_options *ndo, int tcount,
              const struct isakmp_gen *ext, u_int item_len,
-             const u_char *ep, uint32_t phase _U_, uint32_t doi _U_,
-             uint32_t proto _U_, int depth _U_)
+             const u_char *ep)
 {
        const struct ikev2_t *p;
        struct ikev2_t t;
@@ -1919,11 +1904,11 @@ ikev2_t_print(netdissect_options *ndo, u_char tpay _U_, int pcount,
        }
 
        if (idstr)
-               ND_PRINT((ndo," #%u type=%s id=%s ", pcount,
+               ND_PRINT((ndo," #%u type=%s id=%s ", tcount,
                          STR_OR_ID(t.t_type, ikev2_t_type_map),
                          idstr));
        else
-               ND_PRINT((ndo," #%u type=%s id=%u ", pcount,
+               ND_PRINT((ndo," #%u type=%s id=%u ", tcount,
                          STR_OR_ID(t.t_type, ikev2_t_type_map),
                          t.t_id));
        cp = (const u_char *)(p + 1);
@@ -1945,34 +1930,97 @@ trunc:
 
 static const u_char *
 ikev2_p_print(netdissect_options *ndo, u_char tpay _U_, int pcount _U_,
-             const struct isakmp_gen *ext, u_int item_len _U_,
-              const u_char *ep, uint32_t phase, uint32_t doi0,
-              uint32_t proto0 _U_, int depth)
+             const struct isakmp_gen *ext, u_int oprop_length,
+             const u_char *ep, int depth)
 {
        const struct ikev2_p *p;
        struct ikev2_p prop;
+       u_int prop_length;
        const u_char *cp;
+       int i;
+       int tcount;
+       u_char np;
+       struct isakmp_gen e;
+       u_int item_len;
 
        p = (const struct ikev2_p *)ext;
        ND_TCHECK(*p);
        UNALIGNED_MEMCPY(&prop, ext, sizeof(prop));
+
        ikev2_pay_print(ndo, NPSTR(ISAKMP_NPTYPE_P), prop.h.critical);
 
+       /*
+        * ikev2_sa_print() guarantees that this is >= 4.
+        */
+       prop_length = oprop_length - 4;
        ND_PRINT((ndo," #%u protoid=%s transform=%d len=%u",
                  prop.p_no,  PROTOIDSTR(prop.prot_id),
-                 prop.num_t, ntohs(prop.h.len)));
+                 prop.num_t, oprop_length));
+       cp = (const u_char *)(p + 1);
+
        if (prop.spi_size) {
+               if (prop_length < prop.spi_size)
+                       goto toolong;
                ND_PRINT((ndo," spi="));
-               if (!rawprint(ndo, (const uint8_t *)(p + 1), prop.spi_size))
+               if (!rawprint(ndo, (const uint8_t *)cp, prop.spi_size))
                        goto trunc;
+               cp += prop.spi_size;
+               prop_length -= prop.spi_size;
        }
 
-       ext = (const struct isakmp_gen *)((const u_char *)(p + 1) + prop.spi_size);
-       ND_TCHECK(*ext);
+       /*
+        * Print the transforms.
+        */
+       tcount = 0;
+       for (np = ISAKMP_NPTYPE_T; np != 0; np = e.np) {
+               tcount++;
+               ext = (const struct isakmp_gen *)cp;
+               if (prop_length < sizeof(*ext))
+                       goto toolong;
+               ND_TCHECK(*ext);
 
-       cp = ikev2_sub_print(ndo, NULL, ISAKMP_NPTYPE_T, ext, ep, phase, doi0,
-                            prop.prot_id, depth);
+               UNALIGNED_MEMCPY(&e, ext, sizeof(e));
 
+               /*
+                * 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 = ntohs(e.len);
+               if (item_len <= 4)
+                       goto trunc;
+
+               if (prop_length < item_len)
+                       goto toolong;
+               ND_TCHECK2(*cp, item_len);
+
+               depth++;
+               ND_PRINT((ndo,"\n"));
+               for (i = 0; i < depth; i++)
+                       ND_PRINT((ndo,"    "));
+               ND_PRINT((ndo,"("));
+               if (np == ISAKMP_NPTYPE_T) {
+                       cp = ikev2_t_print(ndo, tcount, ext, item_len, ep);
+                       if (cp == NULL) {
+                               /* error, already reported */
+                               return NULL;
+                       }
+               } else {
+                       ND_PRINT((ndo, "%s", NPSTR(np)));
+                       cp += item_len;
+               }
+               ND_PRINT((ndo,")"));
+               depth--;
+               prop_length -= item_len;
+       }
+       return cp;
+toolong:
+       /*
+        * Skip the rest of the proposal.
+        */
+       cp += prop_length;
+       ND_PRINT((ndo," [|%s]", NPSTR(ISAKMP_NPTYPE_P)));
        return cp;
 trunc:
        ND_PRINT((ndo," [|%s]", NPSTR(ISAKMP_NPTYPE_P)));
@@ -1982,26 +2030,86 @@ trunc:
 static const u_char *
 ikev2_sa_print(netdissect_options *ndo, u_char tpay,
                const struct isakmp_gen *ext1,
-               u_int item_len _U_, const u_char *ep _U_,
+               u_int osa_length, const u_char *ep,
                uint32_t phase _U_, uint32_t doi _U_,
-               uint32_t proto _U_, int depth _U_)
+               uint32_t proto _U_, int depth)
 {
+       const struct isakmp_gen *ext;
        struct isakmp_gen e;
-       int    osa_length, sa_length;
+       u_int sa_length;
+       const u_char *cp;
+       int i;
+       int pcount;
+       u_char np;
+       u_int item_len;
 
        ND_TCHECK(*ext1);
        UNALIGNED_MEMCPY(&e, ext1, sizeof(e));
        ikev2_pay_print(ndo, "sa", e.critical);
 
+       /*
+        * ikev2_sub0_print() guarantees that this is >= 4.
+        */
        osa_length= ntohs(e.len);
        sa_length = osa_length - 4;
        ND_PRINT((ndo," len=%d", sa_length));
 
-       ikev2_sub_print(ndo, NULL, ISAKMP_NPTYPE_P,
-                       ext1+1, ep,
-                       0, 0, 0, depth);
+       /*
+        * Print the payloads.
+        */
+       cp = (const u_char *)(ext1 + 1);
+       pcount = 0;
+       for (np = ISAKMP_NPTYPE_P; np != 0; np = e.np) {
+               pcount++;
+               ext = (const struct isakmp_gen *)cp;
+               if (sa_length < sizeof(*ext))
+                       goto toolong;
+               ND_TCHECK(*ext);
+
+               UNALIGNED_MEMCPY(&e, ext, sizeof(e));
 
-       return (const u_char *)ext1 + osa_length;
+               /*
+                * 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 = ntohs(e.len);
+               if (item_len <= 4)
+                       goto trunc;
+
+               if (sa_length < item_len)
+                       goto toolong;
+               ND_TCHECK2(*cp, item_len);
+
+               depth++;
+               ND_PRINT((ndo,"\n"));
+               for (i = 0; i < depth; i++)
+                       ND_PRINT((ndo,"    "));
+               ND_PRINT((ndo,"("));
+               if (np == ISAKMP_NPTYPE_P) {
+                       cp = ikev2_p_print(ndo, np, pcount, ext, item_len,
+                                          ep, depth);
+                       if (cp == NULL) {
+                               /* error, already reported */
+                               return NULL;
+                       }
+               } else {
+                       ND_PRINT((ndo, "%s", NPSTR(np)));
+                       cp += item_len;
+               }
+               ND_PRINT((ndo,")"));
+               depth--;
+               sa_length -= item_len;
+       }
+       return cp;
+toolong:
+       /*
+        * Skip the rest of the SA.
+        */
+       cp += sa_length;
+       ND_PRINT((ndo," [|%s]", NPSTR(tpay)));
+       return cp;
 trunc:
        ND_PRINT((ndo," [|%s]", NPSTR(tpay)));
        return NULL;
@@ -2141,7 +2249,7 @@ ikev2_cr_print(netdissect_options *ndo, u_char tpay,
 static const u_char *
 ikev2_auth_print(netdissect_options *ndo, u_char tpay,
                const struct isakmp_gen *ext,
-               u_int item_len _U_, const u_char *ep _U_,
+               u_int item_len _U_, const u_char *ep,
                uint32_t phase _U_, uint32_t doi _U_,
                uint32_t proto _U_, int depth _U_)
 {
@@ -2177,7 +2285,7 @@ trunc:
 static const u_char *
 ikev2_nonce_print(netdissect_options *ndo, u_char tpay,
                const struct isakmp_gen *ext,
-               u_int item_len _U_, const u_char *ep _U_,
+               u_int item_len _U_, const u_char *ep,
                uint32_t phase _U_, uint32_t doi _U_,
                uint32_t proto _U_, int depth _U_)
 {
@@ -2207,7 +2315,7 @@ trunc:
 static const u_char *
 ikev2_n_print(netdissect_options *ndo, u_char tpay _U_,
                const struct isakmp_gen *ext,
-               u_int item_len _U_, const u_char *ep _U_,
+               u_int item_len, const u_char *ep,
                uint32_t phase _U_, uint32_t doi _U_,
                uint32_t proto _U_, int depth _U_)
 {
@@ -2723,7 +2831,7 @@ done:
 
 static const u_char *
 ikev2_sub0_print(netdissect_options *ndo, struct isakmp *base,
-                u_char np, int pcount,
+                u_char np,
                 const struct isakmp_gen *ext, const u_char *ep,
                 uint32_t phase, uint32_t doi, uint32_t proto, int depth)
 {
@@ -2745,13 +2853,7 @@ ikev2_sub0_print(netdissect_options *ndo, struct isakmp *base,
        if (item_len <= 4)
                return NULL;
 
-       if(np == ISAKMP_NPTYPE_P) {
-               cp = ikev2_p_print(ndo, np, pcount, ext, item_len,
-                                  ep, phase, doi, proto, depth);
-       } else if(np == ISAKMP_NPTYPE_T) {
-               cp = ikev2_t_print(ndo, np, pcount, ext, item_len,
-                                  ep, phase, doi, proto, depth);
-       } else if(np == ISAKMP_NPTYPE_v2E) {
+       if (np == ISAKMP_NPTYPE_v2E) {
                cp = ikev2_e_print(ndo, base, np, ext, item_len,
                                   ep, phase, doi, proto, depth);
        } else if (NPFUNC(np)) {
@@ -2759,7 +2861,7 @@ ikev2_sub0_print(netdissect_options *ndo, struct isakmp *base,
                 * XXX - what if item_len is too short, or too long,
                 * for this payload type?
                 */
-               cp = (*npfunc[np])(ndo, np, /*pcount,*/ ext, item_len,
+               cp = (*npfunc[np])(ndo, np, ext, item_len,
                                   ep, phase, doi, proto, depth);
        } else {
                ND_PRINT((ndo,"%s", NPSTR(np)));
@@ -2780,13 +2882,10 @@ ikev2_sub_print(netdissect_options *ndo,
 {
        const u_char *cp;
        int i;
-       int pcount;
        struct isakmp_gen e;
 
        cp = (const u_char *)ext;
-       pcount = 0;
        while (np) {
-               pcount++;
                ND_TCHECK(*ext);
 
                UNALIGNED_MEMCPY(&e, ext, sizeof(e));
@@ -2798,7 +2897,7 @@ ikev2_sub_print(netdissect_options *ndo,
                for (i = 0; i < depth; i++)
                        ND_PRINT((ndo,"    "));
                ND_PRINT((ndo,"("));
-               cp = ikev2_sub0_print(ndo, base, np, pcount,
+               cp = ikev2_sub0_print(ndo, base, np,
                                      ext, ep, phase, doi, proto, depth);
                ND_PRINT((ndo,")"));
                depth--;