]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ip.c
add tracefiles for infinite loop testing
[tcpdump] / print-ip.c
index 0536efc91106babd6ad7d8886bdef77b144fe027..745ab3c36649c0e2070227389201305ad6847a30 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.128.2.2 2003-11-16 08:51:26 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.128.2.9 2005-01-12 11:27:07 hannes Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -47,14 +47,19 @@ static const char rcsid[] _U_ =
 static void
 ip_printroute(const char *type, register const u_char *cp, u_int length)
 {
-       register u_int ptr = cp[2] - 1;
+       register u_int ptr;
        register u_int len;
 
+       if (length < 3) {
+               printf(" [bad length %u]", length);
+               return;
+       }
        printf(" %s{", type);
        if ((length + 1) & 3)
-               printf(" [bad length %d]", length);
+               printf(" [bad length %u]", length);
+       ptr = cp[2] - 1;
        if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
-               printf(" [bad ptr %d]", cp[2]);
+               printf(" [bad ptr %u]", cp[2]);
 
        type = "";
        for (len = 3; len < length; len += 4) {
@@ -67,7 +72,7 @@ ip_printroute(const char *type, register const u_char *cp, u_int length)
 }
 
 /*
- * If source-routing is present, return the final destination.
+ * If source-routing is present and valid, return the final destination.
  * Otherwise, return IP destination.
  *
  * This is used for UDP and TCP pseudo-header in the checksum
@@ -85,45 +90,54 @@ ip_finddst(const struct ip *ip)
        length = (IP_HL(ip) << 2) - sizeof(struct ip);
 
        for (; length > 0; cp += len, length -= len) {
-               int tt = *cp;
+               int tt;
 
-               if (tt == IPOPT_NOP || tt == IPOPT_EOL)
+               TCHECK(*cp);
+               tt = *cp;
+               if (tt == IPOPT_EOL)
+                       break;
+               else if (tt == IPOPT_NOP)
                        len = 1;
                else {
-                       if (&cp[1] >= snapend) {
-                               return 0;
-                       }
+                       TCHECK(cp[1]);
                        len = cp[1];
+                       if (len < 2)
+                               break;
                }
-               if (len <= 0) {
-                       return 0;
-               }
-               if (&cp[1] >= snapend || cp + len > snapend) {
-                       return 0;
-               }
+               TCHECK2(*cp, len);
                switch (tt) {
 
                case IPOPT_SSRR:
                case IPOPT_LSRR:
+                       if (len < 7)
+                               break;
                        memcpy(&retval, cp + len - 4, 4);
                        return retval;
                }
        }
-       return ip->ip_dst.s_addr;
+trunc:
+       memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));
+       return retval;
 }
 
 static void
 ip_printts(register const u_char *cp, u_int length)
 {
-       register u_int ptr = cp[2] - 1;
-       register u_int len = 0;
+       register u_int ptr;
+       register u_int len;
        int hoplen;
        const char *type;
 
+       if (length < 4) {
+               printf("[bad length %d]", length);
+               return;
+       }
        printf(" TS{");
        hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
        if ((length - 4) & (hoplen-1))
                printf("[bad length %d]", length);
+       ptr = cp[2] - 1;
+       len = 0;
        if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
                printf("[bad ptr %d]", cp[2]);
        switch (cp[3]&0xF) {
@@ -177,24 +191,20 @@ ip_optprint(register const u_char *cp, u_int length)
        register u_int len;
 
        for (; length > 0; cp += len, length -= len) {
-               int tt = *cp;
+               int tt;
 
+               TCHECK(*cp);
+               tt = *cp;
                if (tt == IPOPT_NOP || tt == IPOPT_EOL)
                        len = 1;
                else {
-                       if (&cp[1] >= snapend) {
-                               printf("[|ip]");
+                       TCHECK(cp[1]);
+                       len = cp[1];
+                       if (len < 2) {
+                               printf("[|ip op len %d]", len);
                                return;
                        }
-                       len = cp[1];
-               }
-               if (len <= 0) {
-                       printf("[|ip op len %d]", len);
-                       return;
-               }
-               if (&cp[1] >= snapend || cp + len > snapend) {
-                       printf("[|ip]");
-                       return;
+                       TCHECK2(*cp, len);
                }
                switch (tt) {
 
@@ -238,8 +248,11 @@ ip_optprint(register const u_char *cp, u_int length)
                        printf(" RA");
                        if (len != 4)
                                printf("{%d}", len);
-                       else if (cp[2] || cp[3])
-                               printf("%d.%d", cp[2], cp[3]);
+                       else {
+                               TCHECK(cp[3]);
+                               if (cp[2] || cp[3])
+                                       printf("%d.%d", cp[2], cp[3]);
+                       }
                        break;
 
                default:
@@ -247,6 +260,10 @@ ip_optprint(register const u_char *cp, u_int length)
                        break;
                }
        }
+       return;
+
+trunc:
+       printf("[|ip]");
 }
 
 /*
@@ -358,6 +375,7 @@ ip_print(register const u_char *bp, register u_int length)
 {
        register const struct ip *ip;
        register u_int hlen, len, len0, off;
+       const u_char *ipend;
        register const u_char *cp;
        u_char nh;
        int advance;
@@ -378,19 +396,31 @@ ip_print(register const u_char *bp, register u_int length)
                return;
        }
        if (length < sizeof (struct ip)) {
-               (void)printf("truncated-ip %d", length);
+               (void)printf("truncated-ip %u", length);
                return;
        }
        hlen = IP_HL(ip) * 4;
        if (hlen < sizeof (struct ip)) {
-               (void)printf("bad-hlen %d", hlen);
+               (void)printf("bad-hlen %u", hlen);
                return;
        }
 
        len = EXTRACT_16BITS(&ip->ip_len);
        if (length < len)
-               (void)printf("truncated-ip - %d bytes missing! ",
+               (void)printf("truncated-ip - %u bytes missing! ",
                        len - length);
+       if (len < hlen) {
+               (void)printf("bad-len %u", len);
+               return;
+       }
+
+       /*
+        * Cut off the snapshot length to the end of the IP payload.
+        */
+       ipend = bp + len;
+       if (ipend < snapend)
+               snapend = ipend;
+
        len -= hlen;
        len0 = len;
 
@@ -465,6 +495,8 @@ again:
                case IPPROTO_AH:
                        nh = *cp;
                        advance = ah_print(cp);
+                       if (advance <= 0)
+                               break;
                        cp += advance;
                        len -= advance;
                        goto again;
@@ -473,10 +505,10 @@ again:
                    {
                        int enh, padlen;
                        advance = esp_print(cp, (const u_char *)ip, &enh, &padlen);
+                       if (advance <= 0)
+                               break;
                        cp += advance;
                        len -= advance + padlen;
-                       if (enh < 0)
-                               break;
                        nh = enh & 0xff;
                        goto again;
                    }
@@ -485,10 +517,10 @@ again:
                    {
                        int enh;
                        advance = ipcomp_print(cp, &enh);
+                       if (advance <= 0)
+                               break;
                        cp += advance;
                        len -= advance;
-                       if (enh < 0)
-                               break;
                        nh = enh & 0xff;
                        goto again;
                    }
@@ -519,7 +551,7 @@ again:
                        break;
 
                case IPPROTO_EGP:
-                       egp_print(cp);
+                       egp_print(cp, len);
                        break;
 
                case IPPROTO_OSPF: