]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ip.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-ip.c
index 3478de172dfa4f7ab39c3abf61b43763f5d7bef9..9621dada32b1821e51ba960f6f722b2d9b86b2c4 100644 (file)
 
 /* \summary: IP printer */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
 
 #include "netdissect-stdinc.h"
 
-#include <string.h>
-
 #include "netdissect.h"
 #include "addrtoname.h"
 #include "extract.h"
@@ -66,14 +62,13 @@ ip_printroute(netdissect_options *ndo,
        }
        if ((length + 1) & 3)
                ND_PRINT(" [bad length %u]", length);
-       ND_TCHECK_1(cp + 2);
        ptr = GET_U_1(cp + 2) - 1;
        if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
                ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2));
 
        for (len = 3; len < length; len += 4) {
-               ND_TCHECK_4(cp + len);
-               ND_PRINT(" %s", ipaddr_string(ndo, cp + len));
+               ND_TCHECK_4(cp + len);  /* Needed to print the IP addresses */
+               ND_PRINT(" %s", GET_IPADDR_STRING(cp + len));
                if (ptr > len)
                        ND_PRINT(",");
        }
@@ -107,14 +102,12 @@ ip_finddst(netdissect_options *ndo,
        for (; length != 0; cp += len, length -= len) {
                int tt;
 
-               ND_TCHECK_1(cp);
                tt = GET_U_1(cp);
                if (tt == IPOPT_EOL)
                        break;
                else if (tt == IPOPT_NOP)
                        len = 1;
                else {
-                       ND_TCHECK_1(cp + 1);
                        len = GET_U_1(cp + 1);
                        if (len < 2)
                                break;
@@ -183,16 +176,13 @@ ip_printts(netdissect_options *ndo,
                return (0);
        }
        ND_PRINT(" TS{");
-       ND_TCHECK_1(cp + 3);
        hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
        if ((length - 4) & (hoplen-1))
                ND_PRINT("[bad length %u]", length);
-       ND_TCHECK_1(cp + 2);
        ptr = GET_U_1(cp + 2) - 1;
        len = 0;
        if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
                ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2));
-       ND_TCHECK_1(cp + 3);
        switch (GET_U_1(cp + 3)&0xF) {
        case IPOPT_TS_TSONLY:
                ND_PRINT("TSONLY");
@@ -200,16 +190,7 @@ ip_printts(netdissect_options *ndo,
        case IPOPT_TS_TSANDADDR:
                ND_PRINT("TS+ADDR");
                break;
-       /*
-        * prespecified should really be 3, but some ones might send 2
-        * instead, and the IPOPT_TS_PRESPEC constant can apparently
-        * have both values, so we have to hard-code it here.
-        */
-
-       case 2:
-               ND_PRINT("PRESPEC2.0");
-               break;
-       case 3:                 /* IPOPT_TS_PRESPEC */
+       case IPOPT_TS_PRESPEC:
                ND_PRINT("PRESPEC");
                break;
        default:
@@ -223,7 +204,7 @@ ip_printts(netdissect_options *ndo,
                        type = " ^ ";
                ND_TCHECK_LEN(cp + len, hoplen);
                ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4),
-                         hoplen!=8 ? "" : ipaddr_string(ndo, cp + len));
+                         hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len));
                type = " ";
        }
 
@@ -257,7 +238,6 @@ ip_optprint(netdissect_options *ndo,
                ND_PRINT("%s", sep);
                sep = ",";
 
-               ND_TCHECK_1(cp);
                option_code = GET_U_1(cp);
 
                ND_PRINT("%s",
@@ -268,7 +248,6 @@ ip_optprint(netdissect_options *ndo,
                        option_len = 1;
 
                else {
-                       ND_TCHECK_1(cp + 1);
                        option_len = GET_U_1(cp + 1);
                        if (option_len < 2) {
                                ND_PRINT(" [bad length %u]", option_len);
@@ -337,10 +316,9 @@ static const struct tok ip_frag_values[] = {
 void
 ip_print(netdissect_options *ndo,
         const u_char *bp,
-        u_int length)
+        const u_int length)
 {
        const struct ip *ip;
-       const u_char *ipend;
        u_int off;
        u_int hlen;
        u_int len;
@@ -349,57 +327,45 @@ ip_print(netdissect_options *ndo,
        uint16_t sum, ip_sum;
        const char *p_name;
        int truncated = 0;
+       int presumed_tso = 0;
 
        ndo->ndo_protocol = "ip";
        ip = (const struct ip *)bp;
-       if (IP_V(ip) != 4) { /* print version and fail if != 4 */
-           if (IP_V(ip) == 6)
-             ND_PRINT("IP6, wrong link-layer encapsulation");
-           else
-             ND_PRINT("IP%u", IP_V(ip));
-           nd_print_invalid(ndo);
-           return;
-       }
-       if (!ndo->ndo_eflag)
-               ND_PRINT("IP ");
 
-       ND_TCHECK_SIZE(ip);
-       if (length < sizeof (struct ip)) {
-               ND_PRINT("truncated-ip %u", length);
-               return;
+       if (!ndo->ndo_eflag) {
+               nd_print_protocol_caps(ndo);
+               ND_PRINT(" ");
        }
+
+       ND_ICHECK_ZU(length, <, sizeof (struct ip));
+       ND_ICHECKMSG_U("version", IP_V(ip), !=, 4);
+
        hlen = IP_HL(ip) * 4;
-       if (hlen < sizeof (struct ip)) {
-               ND_PRINT("bad-hlen %u", hlen);
-               return;
-       }
+       ND_ICHECKMSG_ZU("header length", hlen, <, sizeof (struct ip));
 
        len = GET_BE_U_2(ip->ip_len);
-       if (length < len)
-               ND_PRINT("truncated-ip - %u bytes missing! ",
-                       len - length);
-       if (len < hlen) {
-#ifdef GUESS_TSO
-            if (len) {
-                ND_PRINT("bad-len %u", len);
-                return;
-            }
-            else {
-                /* we guess that it is a TSO send */
-                len = length;
-            }
-#else
-            ND_PRINT("bad-len %u", len);
-            return;
-#endif /* GUESS_TSO */
+       if (len > length) {
+               ND_PRINT("[total length %u > length %u]", len, length);
+               nd_print_invalid(ndo);
+               ND_PRINT(" ");
        }
+       if (len == 0) {
+               /* we guess that it is a TSO send */
+               len = length;
+               presumed_tso = 1;
+       } else
+               ND_ICHECKMSG_U("total length", len, <, hlen);
 
+       ND_TCHECK_SIZE(ip);
        /*
-        * Cut off the snapshot length to the end of the IP payload.
+        * Cut off the snapshot length to the end of the IP payload
+        * or the end of the data in which it's contained, whichever
+        * comes first.
         */
-       ipend = bp + len;
-       if (ipend < ndo->ndo_snapend)
-               ndo->ndo_snapend = ipend;
+       if (!nd_push_snaplen(ndo, bp, ND_MIN(length, len))) {
+               (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
+                       "%s: can't push snaplen on buffer stack", __func__);
+       }
 
        len -= hlen;
 
@@ -445,9 +411,12 @@ ip_print(netdissect_options *ndo,
                          tok2str(ipproto_values, "unknown", ip_proto),
                          ip_proto);
 
-            ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
+           if (presumed_tso)
+                ND_PRINT(", length %u [was 0, presumed TSO]", length);
+           else
+                ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
 
-            if ((hlen - sizeof(struct ip)) > 0) {
+            if ((hlen > sizeof(struct ip))) {
                 ND_PRINT(", options (");
                 if (ip_optprint(ndo, (const u_char *)(ip + 1),
                     hlen - sizeof(struct ip)) == -1) {
@@ -457,7 +426,7 @@ ip_print(netdissect_options *ndo,
                 ND_PRINT(")");
             }
 
-           if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) {
+           if (!ndo->ndo_Kflag && ND_TTEST_LEN((const u_char *)ip, hlen)) {
                vec[0].ptr = (const uint8_t *)(const void *)ip;
                vec[0].len = hlen;
                sum = in_cksum(vec, 1);
@@ -471,9 +440,11 @@ ip_print(netdissect_options *ndo,
            ND_PRINT(")\n    ");
            if (truncated) {
                ND_PRINT("%s > %s: ",
-                        ipaddr_string(ndo, ip->ip_src),
-                        ipaddr_string(ndo, ip->ip_dst));
-               goto trunc;
+                        GET_IPADDR_STRING(ip->ip_src),
+                        GET_IPADDR_STRING(ip->ip_dst));
+               nd_print_trunc(ndo);
+               nd_pop_packet_info(ndo);
+               return;
            }
        }
 
@@ -488,48 +459,63 @@ ip_print(netdissect_options *ndo,
                if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
                    nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) {
                        ND_PRINT("%s > %s: ",
-                                    ipaddr_string(ndo, ip->ip_src),
-                                    ipaddr_string(ndo, ip->ip_dst));
+                                    GET_IPADDR_STRING(ip->ip_src),
+                                    GET_IPADDR_STRING(ip->ip_dst));
+               }
+               /*
+                * Do a bounds check before calling ip_demux_print().
+                * At least the header data is required.
+                */
+               if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
+                       ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
+                                ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
+                                hlen);
+                       nd_trunc_longjmp(ndo);
                }
-               ip_print_demux(ndo, (const u_char *)ip + hlen, len, 4,
-                   off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
+               ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
+                              off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
        } else {
                /*
                 * Ultra quiet now means that all this stuff should be
                 * suppressed.
                 */
-               if (ndo->ndo_qflag > 1)
+               if (ndo->ndo_qflag > 1) {
+                       nd_pop_packet_info(ndo);
                        return;
+               }
 
                /*
                 * This isn't the first frag, so we're missing the
                 * next level protocol header.  print the ip addr
                 * and the protocol.
                 */
-               ND_PRINT("%s > %s:", ipaddr_string(ndo, ip->ip_src),
-                         ipaddr_string(ndo, ip->ip_dst));
+               ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src),
+                         GET_IPADDR_STRING(ip->ip_dst));
                if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
                        ND_PRINT(" %s", p_name);
                else
                        ND_PRINT(" ip-proto-%u", ip_proto);
        }
+       nd_pop_packet_info(ndo);
        return;
 
 trunc:
        nd_print_trunc(ndo);
        return;
+
+invalid:
+       nd_print_invalid(ndo);
 }
 
 void
 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
 {
-       ndo->ndo_protocol = "ipN";
+       ndo->ndo_protocol = "ipn";
        if (length < 1) {
                ND_PRINT("truncated-ip %u", length);
                return;
        }
 
-       ND_TCHECK_1(bp);
        switch (GET_U_1(bp) & 0xF0) {
        case 0x40:
                ip_print(ndo, bp, length);
@@ -541,9 +527,4 @@ ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
                ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4);
                break;
        }
-       return;
-
-trunc:
-       nd_print_trunc(ndo);
-       return;
 }