X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/38b7ae42d148b79c121dd7032c2319b28b19f145..f5877da285f3e030d59a28236295573f27e344bc:/print-ip.c?ds=sidebyside diff --git a/print-ip.c b/print-ip.c index 0f09b04e..5edc6221 100644 --- a/print-ip.c +++ b/print-ip.c @@ -21,14 +21,10 @@ /* \summary: IP printer */ -#ifdef HAVE_CONFIG_H #include -#endif #include "netdissect-stdinc.h" -#include - #include "netdissect.h" #include "addrtoname.h" #include "extract.h" @@ -53,7 +49,7 @@ static const struct tok ip_option_values[] = { /* * print the recorded route in an IP RR, LSRR or SSRR option. */ -static void +static int ip_printroute(netdissect_options *ndo, const u_char *cp, u_int length) { @@ -62,7 +58,7 @@ ip_printroute(netdissect_options *ndo, if (length < 3) { ND_PRINT(" [bad length %u]", length); - return; + return (0); } if ((length + 1) & 3) ND_PRINT(" [bad length %u]", length); @@ -71,10 +67,15 @@ ip_printroute(netdissect_options *ndo, ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2)); for (len = 3; len < length; len += 4) { + ND_TCHECK_4(cp + len); /* Needed to print the IP addresses */ ND_PRINT(" %s", GET_IPADDR_STRING(cp + len)); if (ptr > len) ND_PRINT(","); } + return (0); + +trunc: + return (-1); } /* @@ -273,7 +274,8 @@ ip_optprint(netdissect_options *ndo, case IPOPT_RR: /* fall through */ case IPOPT_SSRR: case IPOPT_LSRR: - ip_printroute(ndo, cp, option_len); + if (ip_printroute(ndo, cp, option_len) == -1) + goto trunc; break; case IPOPT_RA: @@ -314,7 +316,7 @@ 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; u_int off; @@ -325,55 +327,43 @@ 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. */ - nd_push_snapend(ndo, bp + len); + if (!nd_push_snaplen(ndo, bp, len)) { + (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, + "%s: can't push snaplen on buffer stack", __func__); + } len -= hlen; @@ -419,7 +409,10 @@ 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) { ND_PRINT(", options ("); @@ -467,8 +460,18 @@ ip_print(netdissect_options *ndo, 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_demux_print(ndo, (const u_char *)ip + hlen, len, 4, - off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp); + off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp); } else { /* * Ultra quiet now means that all this stuff should be @@ -497,6 +500,9 @@ ip_print(netdissect_options *ndo, trunc: nd_print_trunc(ndo); return; + +invalid: + nd_print_invalid(ndo); } void