]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ip.c
add tracefiles for infinite loop testing
[tcpdump] / print-ip.c
index 0b94427a58764b648898af8b66c672c344e51e9c..745ab3c36649c0e2070227389201305ad6847a30 100644 (file)
@@ -20,8 +20,8 @@
  */
 
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.118 2002-12-28 17:59:09 hannes Exp $ (LBL)";
+static const char rcsid[] _U_ =
+    "@(#) $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
@@ -39,11 +39,7 @@ static const char rcsid[] =
 #include "extract.h"                   /* must come after interface.h */
 
 #include "ip.h"
-
-/* Compatibility */
-#ifndef        IPPROTO_ND
-#define        IPPROTO_ND      77
-#endif
+#include "ipproto.h"
 
 /*
  * print the recorded route in an IP RR, LSRR or SSRR option.
@@ -51,14 +47,19 @@ static const char rcsid[] =
 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) {
@@ -71,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
@@ -89,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) {
@@ -181,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) {
 
@@ -242,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:
@@ -251,6 +260,10 @@ ip_optprint(register const u_char *cp, u_int length)
                        break;
                }
        }
+       return;
+
+trunc:
+       printf("[|ip]");
 }
 
 /*
@@ -339,6 +352,21 @@ in_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum)
        return shouldbe;
 }
 
+#ifndef IP_MF
+#define IP_MF 0x2000
+#endif /* IP_MF */
+#ifndef IP_DF
+#define IP_DF 0x4000
+#endif /* IP_DF */
+#define IP_RES 0x8000
+
+static struct tok ip_frag_values[] = {
+        { IP_MF,        "+" },
+        { IP_DF,        "DF" },
+       { IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
+        { 0,            NULL }
+};
+
 /*
  * print an IP datagram.
  */
@@ -347,35 +375,55 @@ 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;
        struct protoent *proto;
+       u_int16_t sum, ip_sum;
 
        ip = (const struct ip *)bp;
+       if (IP_V(ip) != 4) { /* print version if != 4 */
+           printf("IP%u ", IP_V(ip));
+           if (IP_V(ip) == 6)
+               printf(", wrong link-layer encapsulation");
+       }
+        else
+           printf("IP ");
+
        if ((u_char *)(ip + 1) > snapend) {
                printf("[|ip]");
                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;
 
-        printf("IP ");
-
        off = EXTRACT_16BITS(&ip->ip_off);
 
         if (vflag) {
@@ -395,18 +443,36 @@ ip_print(register const u_char *bp, register u_int length)
             }
 
             if (ip->ip_ttl >= 1)
-                (void)printf(", ttl %u", ip->ip_ttl);    
+                (void)printf(", ttl %3u", ip->ip_ttl);    
+
+           /*
+            * for the firewall guys, print id, offset.
+             * On all but the last stick a "+" in the flags portion.
+            * For unfragmented datagrams, note the don't fragment flag.
+            */
 
-            if ((off & 0x3fff) != 0)
-                (void)printf(", id %u", EXTRACT_16BITS(&ip->ip_id));
+           (void)printf(", id %u, offset %u, flags [%s]",
+                            EXTRACT_16BITS(&ip->ip_id),
+                            (off & 0x1fff) * 8,
+                            bittok2str(ip_frag_values, "none", off & 0xe000 ));
 
             (void)printf(", length: %u", EXTRACT_16BITS(&ip->ip_len));
 
             if ((hlen - sizeof(struct ip)) > 0) {
-                (void)printf(", optlength: %u (", hlen - sizeof(struct ip));
+                (void)printf(", optlength: %u (", hlen - (u_int)sizeof(struct ip));
                 ip_optprint((u_char *)(ip + 1), hlen - sizeof(struct ip));
                 printf(" )");
             }
+
+           if ((u_char *)ip + hlen <= snapend) {
+               sum = in_cksum((const u_short *)ip, hlen, 0);
+               if (sum != 0) {
+                   ip_sum = EXTRACT_16BITS(&ip->ip_sum);
+                   (void)printf(", bad cksum %x (->%x)!", ip_sum,
+                            in_cksum_shouldbe(ip_sum, sum));
+               }
+           }
+
             printf(") ");
        }
 
@@ -418,9 +484,6 @@ ip_print(register const u_char *bp, register u_int length)
                cp = (const u_char *)ip + hlen;
                nh = ip->ip_p;
 
-#ifndef IPPROTO_SCTP
-#define IPPROTO_SCTP 132
-#endif
                if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
                    nh != IPPROTO_SCTP) {
                        (void)printf("%s > %s: ", ipaddr_string(&ip->ip_src),
@@ -429,42 +492,35 @@ ip_print(register const u_char *bp, register u_int length)
 again:
                switch (nh) {
 
-#ifndef IPPROTO_AH
-#define IPPROTO_AH     51
-#endif
                case IPPROTO_AH:
                        nh = *cp;
                        advance = ah_print(cp);
+                       if (advance <= 0)
+                               break;
                        cp += advance;
                        len -= advance;
                        goto again;
 
-#ifndef IPPROTO_ESP
-#define IPPROTO_ESP    50
-#endif
                case IPPROTO_ESP:
                    {
                        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;
                    }
 
-#ifndef IPPROTO_IPCOMP
-#define IPPROTO_IPCOMP 108
-#endif
                case IPPROTO_IPCOMP:
                    {
                        int enh;
                        advance = ipcomp_print(cp, &enh);
+                       if (advance <= 0)
+                               break;
                        cp += advance;
                        len -= advance;
-                       if (enh < 0)
-                               break;
                        nh = enh & 0xff;
                        goto again;
                    }
@@ -482,12 +538,10 @@ again:
                        break;
 
                case IPPROTO_ICMP:
-                       icmp_print(cp, len, (const u_char *)ip);
+                       /* pass on the MF bit plus the offset to detect fragments */
+                       icmp_print(cp, len, (const u_char *)ip, (off & 0x3fff));
                        break;
 
-#ifndef IPPROTO_IGRP
-#define IPPROTO_IGRP 9
-#endif
                case IPPROTO_IGRP:
                        igrp_print(cp, len, (const u_char *)ip);
                        break;
@@ -497,24 +551,18 @@ again:
                        break;
 
                case IPPROTO_EGP:
-                       egp_print(cp);
+                       egp_print(cp, len);
                        break;
 
-#ifndef IPPROTO_OSPF
-#define IPPROTO_OSPF 89
-#endif
                case IPPROTO_OSPF:
                        ospf_print(cp, len, (const u_char *)ip);
                        break;
 
-#ifndef IPPROTO_IGMP
-#define IPPROTO_IGMP 2
-#endif
                case IPPROTO_IGMP:
                        igmp_print(cp, len);
                        break;
 
-               case 4:
+               case IPPROTO_IPV4:
                        /* DVMRP multicast tunnel (ip-in-ip encapsulation) */
                        ip_print(cp, len);
                        if (! vflag) {
@@ -524,47 +572,29 @@ again:
                        break;
 
 #ifdef INET6
-#ifndef IP6PROTO_ENCAP
-#define IP6PROTO_ENCAP 41
-#endif
-               case IP6PROTO_ENCAP:
+               case IPPROTO_IPV6:
                        /* ip6-in-ip encapsulation */
                        ip6_print(cp, len);
                        break;
 #endif /*INET6*/
 
-#ifndef IPPROTO_RSVP
-#define IPPROTO_RSVP 46
-#endif
                case IPPROTO_RSVP:
                        rsvp_print(cp, len);
                        break;
 
-#ifndef IPPROTO_GRE
-#define IPPROTO_GRE 47
-#endif
                case IPPROTO_GRE:
                        /* do it */
                        gre_print(cp, len);
                        break;
 
-#ifndef IPPROTO_MOBILE
-#define IPPROTO_MOBILE 55
-#endif
                case IPPROTO_MOBILE:
                        mobile_print(cp, len);
                        break;
 
-#ifndef IPPROTO_PIM
-#define IPPROTO_PIM    103
-#endif
                case IPPROTO_PIM:
                        pim_print(cp, len);
                        break;
 
-#ifndef IPPROTO_VRRP
-#define IPPROTO_VRRP   112
-#endif
                case IPPROTO_VRRP:
                        vrrp_print(cp, len, ip->ip_ttl);
                        break;
@@ -577,60 +607,23 @@ again:
                        printf(" %d", len);
                        break;
                }
-       }
-
-       /* Ultra quiet now means that all this stuff should be suppressed */
-       /* res 3-Nov-98 */
-       if (qflag > 1) return;
-
-
-       /*
-        * for fragmented datagrams, print id:size@offset.  On all
-        * but the last stick a "+".  For unfragmented datagrams, note
-        * the don't fragment flag.
-        */
-       len = len0;     /* get the original length */
-       if (off & 0x3fff) {
-               /*
-                * if this isn't the first frag, we're missing the
-                * next level protocol header.  print the ip addr
-                * and the protocol.
-                */
-               if (off & 0x1fff) {
-                       (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
-                                     ipaddr_string(&ip->ip_dst));
-                       if ((proto = getprotobynumber(ip->ip_p)) != NULL)
-                               (void)printf(" %s", proto->p_name);
-                       else
-                               (void)printf(" ip-proto-%d", ip->ip_p);
-               }
-#ifndef IP_MF
-#define IP_MF 0x2000
-#endif /* IP_MF */
-#ifndef IP_DF
-#define IP_DF 0x4000
-#endif /* IP_DF */
-               (void)printf(" (frag %u:%u@%u%s)", EXTRACT_16BITS(&ip->ip_id), len,
-                       (off & 0x1fff) * 8,
-                       (off & IP_MF)? "+" : "");
-
-       } else if (off & IP_DF)
-               (void)printf(" (DF)");
-
-       if (vflag) {
-               u_int16_t sum, ip_sum;
-               const char *sep = "";
-
-               if ((u_char *)ip + hlen <= snapend) {
-                       sum = in_cksum((const u_short *)ip, hlen, 0);
-                       if (sum != 0) {
-                               ip_sum = EXTRACT_16BITS(&ip->ip_sum);
-                               (void)printf("%sbad cksum %x (->%x)!", sep,
-                                            ip_sum,
-                                            in_cksum_shouldbe(ip_sum, sum));
-                               sep = ", ";
-                       }
-               }
+       } else {
+           /* Ultra quiet now means that all this stuff should be suppressed */
+           if (qflag > 1) return;
+
+           /*
+            * if this isn't the first frag, we're missing the
+            * next level protocol header.  print the ip addr
+            * and the protocol.
+            */
+           if (off & 0x1fff) {
+               (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+                            ipaddr_string(&ip->ip_dst));
+               if ((proto = getprotobynumber(ip->ip_p)) != NULL)
+                   (void)printf(" %s", proto->p_name);
+               else
+                   (void)printf(" ip-proto-%d", ip->ip_p);
+           } 
        }
 }