xref: /dflybsd-src/contrib/tcpdump/print-ip.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
141c99275SPeter Avalos /*
241c99275SPeter Avalos  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
341c99275SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
441c99275SPeter Avalos  *
541c99275SPeter Avalos  * Redistribution and use in source and binary forms, with or without
641c99275SPeter Avalos  * modification, are permitted provided that: (1) source code distributions
741c99275SPeter Avalos  * retain the above copyright notice and this paragraph in its entirety, (2)
841c99275SPeter Avalos  * distributions including binary code include the above copyright notice and
941c99275SPeter Avalos  * this paragraph in its entirety in the documentation or other materials
1041c99275SPeter Avalos  * provided with the distribution, and (3) all advertising materials mentioning
1141c99275SPeter Avalos  * features or use of this software display the following acknowledgement:
1241c99275SPeter Avalos  * ``This product includes software developed by the University of California,
1341c99275SPeter Avalos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1441c99275SPeter Avalos  * the University nor the names of its contributors may be used to endorse
1541c99275SPeter Avalos  * or promote products derived from this software without specific prior
1641c99275SPeter Avalos  * written permission.
1741c99275SPeter Avalos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1841c99275SPeter Avalos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1941c99275SPeter Avalos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2041c99275SPeter Avalos  */
2141c99275SPeter Avalos 
22411677aeSAaron LI /* \summary: IP printer */
2341c99275SPeter Avalos 
2441c99275SPeter Avalos #ifdef HAVE_CONFIG_H
25*ed775ee7SAntonio Huete Jimenez #include <config.h>
2641c99275SPeter Avalos #endif
2741c99275SPeter Avalos 
28*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
2941c99275SPeter Avalos 
30411677aeSAaron LI #include "netdissect.h"
3141c99275SPeter Avalos #include "addrtoname.h"
32411677aeSAaron LI #include "extract.h"
3341c99275SPeter Avalos 
3441c99275SPeter Avalos #include "ip.h"
3541c99275SPeter Avalos #include "ipproto.h"
3641c99275SPeter Avalos 
37411677aeSAaron LI 
38411677aeSAaron LI static const struct tok ip_option_values[] = {
3941c99275SPeter Avalos     { IPOPT_EOL, "EOL" },
4041c99275SPeter Avalos     { IPOPT_NOP, "NOP" },
4141c99275SPeter Avalos     { IPOPT_TS, "timestamp" },
4241c99275SPeter Avalos     { IPOPT_SECURITY, "security" },
4341c99275SPeter Avalos     { IPOPT_RR, "RR" },
4441c99275SPeter Avalos     { IPOPT_SSRR, "SSRR" },
4541c99275SPeter Avalos     { IPOPT_LSRR, "LSRR" },
4641c99275SPeter Avalos     { IPOPT_RA, "RA" },
4741c99275SPeter Avalos     { IPOPT_RFC1393, "traceroute" },
4841c99275SPeter Avalos     { 0, NULL }
4941c99275SPeter Avalos };
5041c99275SPeter Avalos 
5141c99275SPeter Avalos /*
5241c99275SPeter Avalos  * print the recorded route in an IP RR, LSRR or SSRR option.
5341c99275SPeter Avalos  */
54411677aeSAaron LI static int
ip_printroute(netdissect_options * ndo,const u_char * cp,u_int length)55411677aeSAaron LI ip_printroute(netdissect_options *ndo,
56*ed775ee7SAntonio Huete Jimenez               const u_char *cp, u_int length)
5741c99275SPeter Avalos {
58*ed775ee7SAntonio Huete Jimenez 	u_int ptr;
59*ed775ee7SAntonio Huete Jimenez 	u_int len;
6041c99275SPeter Avalos 
6141c99275SPeter Avalos 	if (length < 3) {
62*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" [bad length %u]", length);
63411677aeSAaron LI 		return (0);
6441c99275SPeter Avalos 	}
6541c99275SPeter Avalos 	if ((length + 1) & 3)
66*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" [bad length %u]", length);
67*ed775ee7SAntonio Huete Jimenez 	ptr = GET_U_1(cp + 2) - 1;
6841c99275SPeter Avalos 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
69*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2));
7041c99275SPeter Avalos 
7141c99275SPeter Avalos 	for (len = 3; len < length; len += 4) {
72*ed775ee7SAntonio Huete Jimenez 		ND_TCHECK_4(cp + len);	/* Needed to print the IP addresses */
73*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" %s", GET_IPADDR_STRING(cp + len));
7441c99275SPeter Avalos 		if (ptr > len)
75*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(",");
7641c99275SPeter Avalos 	}
77411677aeSAaron LI 	return (0);
78411677aeSAaron LI 
79411677aeSAaron LI trunc:
80411677aeSAaron LI 	return (-1);
8141c99275SPeter Avalos }
8241c99275SPeter Avalos 
8341c99275SPeter Avalos /*
8441c99275SPeter Avalos  * If source-routing is present and valid, return the final destination.
8541c99275SPeter Avalos  * Otherwise, return IP destination.
8641c99275SPeter Avalos  *
8741c99275SPeter Avalos  * This is used for UDP and TCP pseudo-header in the checksum
8841c99275SPeter Avalos  * calculation.
8941c99275SPeter Avalos  */
90411677aeSAaron LI static uint32_t
ip_finddst(netdissect_options * ndo,const struct ip * ip)91411677aeSAaron LI ip_finddst(netdissect_options *ndo,
92411677aeSAaron LI            const struct ip *ip)
9341c99275SPeter Avalos {
94*ed775ee7SAntonio Huete Jimenez 	u_int length;
95*ed775ee7SAntonio Huete Jimenez 	u_int len;
9641c99275SPeter Avalos 	const u_char *cp;
9741c99275SPeter Avalos 
9841c99275SPeter Avalos 	cp = (const u_char *)(ip + 1);
99*ed775ee7SAntonio Huete Jimenez 	length = IP_HL(ip) * 4;
100*ed775ee7SAntonio Huete Jimenez 	if (length < sizeof(struct ip))
101*ed775ee7SAntonio Huete Jimenez 		goto trunc;
102*ed775ee7SAntonio Huete Jimenez 	length -= sizeof(struct ip);
10341c99275SPeter Avalos 
104*ed775ee7SAntonio Huete Jimenez 	for (; length != 0; cp += len, length -= len) {
10541c99275SPeter Avalos 		int tt;
10641c99275SPeter Avalos 
107*ed775ee7SAntonio Huete Jimenez 		tt = GET_U_1(cp);
10841c99275SPeter Avalos 		if (tt == IPOPT_EOL)
10941c99275SPeter Avalos 			break;
11041c99275SPeter Avalos 		else if (tt == IPOPT_NOP)
11141c99275SPeter Avalos 			len = 1;
11241c99275SPeter Avalos 		else {
113*ed775ee7SAntonio Huete Jimenez 			len = GET_U_1(cp + 1);
11441c99275SPeter Avalos 			if (len < 2)
11541c99275SPeter Avalos 				break;
11641c99275SPeter Avalos 		}
117*ed775ee7SAntonio Huete Jimenez 		if (length < len)
118*ed775ee7SAntonio Huete Jimenez 			goto trunc;
119*ed775ee7SAntonio Huete Jimenez 		ND_TCHECK_LEN(cp, len);
12041c99275SPeter Avalos 		switch (tt) {
12141c99275SPeter Avalos 
12241c99275SPeter Avalos 		case IPOPT_SSRR:
12341c99275SPeter Avalos 		case IPOPT_LSRR:
12441c99275SPeter Avalos 			if (len < 7)
12541c99275SPeter Avalos 				break;
126*ed775ee7SAntonio Huete Jimenez 			return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4));
12741c99275SPeter Avalos 		}
12841c99275SPeter Avalos 	}
12941c99275SPeter Avalos trunc:
130*ed775ee7SAntonio Huete Jimenez 	return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst));
13141c99275SPeter Avalos }
13241c99275SPeter Avalos 
13327bfbee1SPeter Avalos /*
13427bfbee1SPeter Avalos  * Compute a V4-style checksum by building a pseudoheader.
13527bfbee1SPeter Avalos  */
136*ed775ee7SAntonio Huete Jimenez uint16_t
nextproto4_cksum(netdissect_options * ndo,const struct ip * ip,const uint8_t * data,u_int len,u_int covlen,uint8_t next_proto)137411677aeSAaron LI nextproto4_cksum(netdissect_options *ndo,
138411677aeSAaron LI                  const struct ip *ip, const uint8_t *data,
139*ed775ee7SAntonio Huete Jimenez                  u_int len, u_int covlen, uint8_t next_proto)
14027bfbee1SPeter Avalos {
14127bfbee1SPeter Avalos 	struct phdr {
142411677aeSAaron LI 		uint32_t src;
143411677aeSAaron LI 		uint32_t dst;
144*ed775ee7SAntonio Huete Jimenez 		uint8_t mbz;
145*ed775ee7SAntonio Huete Jimenez 		uint8_t proto;
146411677aeSAaron LI 		uint16_t len;
14727bfbee1SPeter Avalos 	} ph;
14827bfbee1SPeter Avalos 	struct cksum_vec vec[2];
14927bfbee1SPeter Avalos 
15027bfbee1SPeter Avalos 	/* pseudo-header.. */
151411677aeSAaron LI 	ph.len = htons((uint16_t)len);
15227bfbee1SPeter Avalos 	ph.mbz = 0;
15327bfbee1SPeter Avalos 	ph.proto = next_proto;
154*ed775ee7SAntonio Huete Jimenez 	ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
15527bfbee1SPeter Avalos 	if (IP_HL(ip) == 5)
156*ed775ee7SAntonio Huete Jimenez 		ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
15727bfbee1SPeter Avalos 	else
158411677aeSAaron LI 		ph.dst = ip_finddst(ndo, ip);
15927bfbee1SPeter Avalos 
160411677aeSAaron LI 	vec[0].ptr = (const uint8_t *)(void *)&ph;
16127bfbee1SPeter Avalos 	vec[0].len = sizeof(ph);
16227bfbee1SPeter Avalos 	vec[1].ptr = data;
163411677aeSAaron LI 	vec[1].len = covlen;
16427bfbee1SPeter Avalos 	return (in_cksum(vec, 2));
16527bfbee1SPeter Avalos }
16627bfbee1SPeter Avalos 
167411677aeSAaron LI static int
ip_printts(netdissect_options * ndo,const u_char * cp,u_int length)168411677aeSAaron LI ip_printts(netdissect_options *ndo,
169*ed775ee7SAntonio Huete Jimenez            const u_char *cp, u_int length)
17041c99275SPeter Avalos {
171*ed775ee7SAntonio Huete Jimenez 	u_int ptr;
172*ed775ee7SAntonio Huete Jimenez 	u_int len;
173*ed775ee7SAntonio Huete Jimenez 	u_int hoplen;
17441c99275SPeter Avalos 	const char *type;
17541c99275SPeter Avalos 
17641c99275SPeter Avalos 	if (length < 4) {
177*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("[bad length %u]", length);
178411677aeSAaron LI 		return (0);
17941c99275SPeter Avalos 	}
180*ed775ee7SAntonio Huete Jimenez 	ND_PRINT(" TS{");
181*ed775ee7SAntonio Huete Jimenez 	hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
18241c99275SPeter Avalos 	if ((length - 4) & (hoplen-1))
183*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("[bad length %u]", length);
184*ed775ee7SAntonio Huete Jimenez 	ptr = GET_U_1(cp + 2) - 1;
18541c99275SPeter Avalos 	len = 0;
18641c99275SPeter Avalos 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
187*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2));
188*ed775ee7SAntonio Huete Jimenez 	switch (GET_U_1(cp + 3)&0xF) {
18941c99275SPeter Avalos 	case IPOPT_TS_TSONLY:
190*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("TSONLY");
19141c99275SPeter Avalos 		break;
19241c99275SPeter Avalos 	case IPOPT_TS_TSANDADDR:
193*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("TS+ADDR");
19441c99275SPeter Avalos 		break;
195*ed775ee7SAntonio Huete Jimenez 	case IPOPT_TS_PRESPEC:
196*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("PRESPEC");
19741c99275SPeter Avalos 		break;
19841c99275SPeter Avalos 	default:
199*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF);
20041c99275SPeter Avalos 		goto done;
20141c99275SPeter Avalos 	}
20241c99275SPeter Avalos 
20341c99275SPeter Avalos 	type = " ";
20441c99275SPeter Avalos 	for (len = 4; len < length; len += hoplen) {
20541c99275SPeter Avalos 		if (ptr == len)
20641c99275SPeter Avalos 			type = " ^ ";
207*ed775ee7SAntonio Huete Jimenez 		ND_TCHECK_LEN(cp + len, hoplen);
208*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4),
209*ed775ee7SAntonio Huete Jimenez 			  hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len));
21041c99275SPeter Avalos 		type = " ";
21141c99275SPeter Avalos 	}
21241c99275SPeter Avalos 
21341c99275SPeter Avalos done:
214*ed775ee7SAntonio Huete Jimenez 	ND_PRINT("%s", ptr == len ? " ^ " : "");
21541c99275SPeter Avalos 
216*ed775ee7SAntonio Huete Jimenez 	if (GET_U_1(cp + 3) >> 4)
217*ed775ee7SAntonio Huete Jimenez 		ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4);
21841c99275SPeter Avalos 	else
219*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("}");
220411677aeSAaron LI 	return (0);
221411677aeSAaron LI 
222411677aeSAaron LI trunc:
223411677aeSAaron LI 	return (-1);
22441c99275SPeter Avalos }
22541c99275SPeter Avalos 
22641c99275SPeter Avalos /*
22741c99275SPeter Avalos  * print IP options.
228*ed775ee7SAntonio Huete Jimenez    If truncated return -1, else 0.
22941c99275SPeter Avalos  */
230*ed775ee7SAntonio Huete Jimenez static int
ip_optprint(netdissect_options * ndo,const u_char * cp,u_int length)231411677aeSAaron LI ip_optprint(netdissect_options *ndo,
232*ed775ee7SAntonio Huete Jimenez             const u_char *cp, u_int length)
23341c99275SPeter Avalos {
234*ed775ee7SAntonio Huete Jimenez 	u_int option_len;
23541c99275SPeter Avalos 	const char *sep = "";
23641c99275SPeter Avalos 
23741c99275SPeter Avalos 	for (; length > 0; cp += option_len, length -= option_len) {
23841c99275SPeter Avalos 		u_int option_code;
23941c99275SPeter Avalos 
240*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("%s", sep);
24141c99275SPeter Avalos 		sep = ",";
24241c99275SPeter Avalos 
243*ed775ee7SAntonio Huete Jimenez 		option_code = GET_U_1(cp);
24441c99275SPeter Avalos 
245*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("%s",
246*ed775ee7SAntonio Huete Jimenez 		          tok2str(ip_option_values,"unknown %u",option_code));
24741c99275SPeter Avalos 
24841c99275SPeter Avalos 		if (option_code == IPOPT_NOP ||
24941c99275SPeter Avalos                     option_code == IPOPT_EOL)
25041c99275SPeter Avalos 			option_len = 1;
25141c99275SPeter Avalos 
25241c99275SPeter Avalos 		else {
253*ed775ee7SAntonio Huete Jimenez 			option_len = GET_U_1(cp + 1);
25441c99275SPeter Avalos 			if (option_len < 2) {
255*ed775ee7SAntonio Huete Jimenez 				ND_PRINT(" [bad length %u]", option_len);
256*ed775ee7SAntonio Huete Jimenez 				return 0;
25741c99275SPeter Avalos 			}
25841c99275SPeter Avalos 		}
25941c99275SPeter Avalos 
26041c99275SPeter Avalos 		if (option_len > length) {
261*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" [bad length %u]", option_len);
262*ed775ee7SAntonio Huete Jimenez 			return 0;
26341c99275SPeter Avalos 		}
26441c99275SPeter Avalos 
265*ed775ee7SAntonio Huete Jimenez 		ND_TCHECK_LEN(cp, option_len);
26641c99275SPeter Avalos 
26741c99275SPeter Avalos 		switch (option_code) {
26841c99275SPeter Avalos 		case IPOPT_EOL:
269*ed775ee7SAntonio Huete Jimenez 			return 0;
27041c99275SPeter Avalos 
27141c99275SPeter Avalos 		case IPOPT_TS:
272411677aeSAaron LI 			if (ip_printts(ndo, cp, option_len) == -1)
273411677aeSAaron LI 				goto trunc;
27441c99275SPeter Avalos 			break;
27541c99275SPeter Avalos 
27641c99275SPeter Avalos 		case IPOPT_RR:       /* fall through */
27741c99275SPeter Avalos 		case IPOPT_SSRR:
27841c99275SPeter Avalos 		case IPOPT_LSRR:
279411677aeSAaron LI 			if (ip_printroute(ndo, cp, option_len) == -1)
280411677aeSAaron LI 				goto trunc;
28141c99275SPeter Avalos 			break;
28241c99275SPeter Avalos 
28341c99275SPeter Avalos 		case IPOPT_RA:
28441c99275SPeter Avalos 			if (option_len < 4) {
285*ed775ee7SAntonio Huete Jimenez 				ND_PRINT(" [bad length %u]", option_len);
28641c99275SPeter Avalos 				break;
28741c99275SPeter Avalos 			}
288*ed775ee7SAntonio Huete Jimenez 			ND_TCHECK_1(cp + 3);
289*ed775ee7SAntonio Huete Jimenez 			if (GET_BE_U_2(cp + 2) != 0)
290*ed775ee7SAntonio Huete Jimenez 				ND_PRINT(" value %u", GET_BE_U_2(cp + 2));
29141c99275SPeter Avalos 			break;
29241c99275SPeter Avalos 
29341c99275SPeter Avalos 		case IPOPT_NOP:       /* nothing to print - fall through */
29441c99275SPeter Avalos 		case IPOPT_SECURITY:
29541c99275SPeter Avalos 		default:
29641c99275SPeter Avalos 			break;
29741c99275SPeter Avalos 		}
29841c99275SPeter Avalos 	}
299*ed775ee7SAntonio Huete Jimenez 	return 0;
30041c99275SPeter Avalos 
30141c99275SPeter Avalos trunc:
302*ed775ee7SAntonio Huete Jimenez 	return -1;
30341c99275SPeter Avalos }
30441c99275SPeter Avalos 
30541c99275SPeter Avalos #define IP_RES 0x8000
30641c99275SPeter Avalos 
307411677aeSAaron LI static const struct tok ip_frag_values[] = {
30841c99275SPeter Avalos         { IP_MF,        "+" },
30941c99275SPeter Avalos         { IP_DF,        "DF" },
31041c99275SPeter Avalos 	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
31141c99275SPeter Avalos         { 0,            NULL }
31241c99275SPeter Avalos };
31341c99275SPeter Avalos 
31441c99275SPeter Avalos 
31541c99275SPeter Avalos /*
31641c99275SPeter Avalos  * print an IP datagram.
31741c99275SPeter Avalos  */
31841c99275SPeter Avalos void
ip_print(netdissect_options * ndo,const u_char * bp,u_int length)31941c99275SPeter Avalos ip_print(netdissect_options *ndo,
32041c99275SPeter Avalos 	 const u_char *bp,
32141c99275SPeter Avalos 	 u_int length)
32241c99275SPeter Avalos {
323*ed775ee7SAntonio Huete Jimenez 	const struct ip *ip;
324*ed775ee7SAntonio Huete Jimenez 	u_int off;
32541c99275SPeter Avalos 	u_int hlen;
326*ed775ee7SAntonio Huete Jimenez 	u_int len;
32727bfbee1SPeter Avalos 	struct cksum_vec vec[1];
328*ed775ee7SAntonio Huete Jimenez 	uint8_t ip_tos, ip_ttl, ip_proto;
329411677aeSAaron LI 	uint16_t sum, ip_sum;
330411677aeSAaron LI 	const char *p_name;
331*ed775ee7SAntonio Huete Jimenez 	int truncated = 0;
33241c99275SPeter Avalos 
333*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "ip";
334*ed775ee7SAntonio Huete Jimenez 	ip = (const struct ip *)bp;
335*ed775ee7SAntonio Huete Jimenez 	if (IP_V(ip) != 4) { /* print version and fail if != 4 */
336*ed775ee7SAntonio Huete Jimenez 	    if (IP_V(ip) == 6)
337*ed775ee7SAntonio Huete Jimenez 	      ND_PRINT("IP6, wrong link-layer encapsulation");
338411677aeSAaron LI 	    else
339*ed775ee7SAntonio Huete Jimenez 	      ND_PRINT("IP%u", IP_V(ip));
340*ed775ee7SAntonio Huete Jimenez 	    nd_print_invalid(ndo);
34141c99275SPeter Avalos 	    return;
34241c99275SPeter Avalos 	}
343411677aeSAaron LI 	if (!ndo->ndo_eflag)
344*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("IP ");
345411677aeSAaron LI 
346*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_SIZE(ip);
34741c99275SPeter Avalos 	if (length < sizeof (struct ip)) {
348*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("truncated-ip %u", length);
34941c99275SPeter Avalos 		return;
35041c99275SPeter Avalos 	}
351*ed775ee7SAntonio Huete Jimenez 	hlen = IP_HL(ip) * 4;
35241c99275SPeter Avalos 	if (hlen < sizeof (struct ip)) {
353*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("bad-hlen %u", hlen);
35441c99275SPeter Avalos 		return;
35541c99275SPeter Avalos 	}
35641c99275SPeter Avalos 
357*ed775ee7SAntonio Huete Jimenez 	len = GET_BE_U_2(ip->ip_len);
358*ed775ee7SAntonio Huete Jimenez 	if (length < len)
359*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("truncated-ip - %u bytes missing! ",
360*ed775ee7SAntonio Huete Jimenez 			len - length);
361*ed775ee7SAntonio Huete Jimenez 	if (len < hlen) {
36241c99275SPeter Avalos #ifdef GUESS_TSO
363*ed775ee7SAntonio Huete Jimenez             if (len) {
364*ed775ee7SAntonio Huete Jimenez                 ND_PRINT("bad-len %u", len);
36541c99275SPeter Avalos                 return;
36641c99275SPeter Avalos             }
36741c99275SPeter Avalos             else {
36841c99275SPeter Avalos                 /* we guess that it is a TSO send */
369*ed775ee7SAntonio Huete Jimenez                 len = length;
37041c99275SPeter Avalos             }
37141c99275SPeter Avalos #else
372*ed775ee7SAntonio Huete Jimenez             ND_PRINT("bad-len %u", len);
37341c99275SPeter Avalos             return;
37441c99275SPeter Avalos #endif /* GUESS_TSO */
37541c99275SPeter Avalos 	}
37641c99275SPeter Avalos 
37741c99275SPeter Avalos 	/*
37841c99275SPeter Avalos 	 * Cut off the snapshot length to the end of the IP payload.
37941c99275SPeter Avalos 	 */
380*ed775ee7SAntonio Huete Jimenez 	nd_push_snapend(ndo, bp + len);
38141c99275SPeter Avalos 
382*ed775ee7SAntonio Huete Jimenez 	len -= hlen;
38341c99275SPeter Avalos 
384*ed775ee7SAntonio Huete Jimenez 	off = GET_BE_U_2(ip->ip_off);
385*ed775ee7SAntonio Huete Jimenez 
386*ed775ee7SAntonio Huete Jimenez         ip_proto = GET_U_1(ip->ip_p);
38741c99275SPeter Avalos 
388411677aeSAaron LI         if (ndo->ndo_vflag) {
389*ed775ee7SAntonio Huete Jimenez             ip_tos = GET_U_1(ip->ip_tos);
390*ed775ee7SAntonio Huete Jimenez             ND_PRINT("(tos 0x%x", ip_tos);
39141c99275SPeter Avalos             /* ECN bits */
392*ed775ee7SAntonio Huete Jimenez             switch (ip_tos & 0x03) {
393411677aeSAaron LI 
394411677aeSAaron LI             case 0:
395411677aeSAaron LI                 break;
396411677aeSAaron LI 
39741c99275SPeter Avalos             case 1:
398*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(",ECT(1)");
39941c99275SPeter Avalos                 break;
400411677aeSAaron LI 
40141c99275SPeter Avalos             case 2:
402*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(",ECT(0)");
40341c99275SPeter Avalos                 break;
404411677aeSAaron LI 
40541c99275SPeter Avalos             case 3:
406*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(",CE");
407411677aeSAaron LI                 break;
40841c99275SPeter Avalos             }
40941c99275SPeter Avalos 
410*ed775ee7SAntonio Huete Jimenez             ip_ttl = GET_U_1(ip->ip_ttl);
411*ed775ee7SAntonio Huete Jimenez             if (ip_ttl >= 1)
412*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(", ttl %u", ip_ttl);
41341c99275SPeter Avalos 
41441c99275SPeter Avalos 	    /*
41541c99275SPeter Avalos 	     * for the firewall guys, print id, offset.
41641c99275SPeter Avalos              * On all but the last stick a "+" in the flags portion.
41741c99275SPeter Avalos 	     * For unfragmented datagrams, note the don't fragment flag.
41841c99275SPeter Avalos 	     */
419*ed775ee7SAntonio Huete Jimenez 	    ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)",
420*ed775ee7SAntonio Huete Jimenez                          GET_BE_U_2(ip->ip_id),
421*ed775ee7SAntonio Huete Jimenez                          (off & IP_OFFMASK) * 8,
422*ed775ee7SAntonio Huete Jimenez                          bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)),
423*ed775ee7SAntonio Huete Jimenez                          tok2str(ipproto_values, "unknown", ip_proto),
424*ed775ee7SAntonio Huete Jimenez                          ip_proto);
42541c99275SPeter Avalos 
426*ed775ee7SAntonio Huete Jimenez             ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
42741c99275SPeter Avalos 
42841c99275SPeter Avalos             if ((hlen - sizeof(struct ip)) > 0) {
429*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(", options (");
430*ed775ee7SAntonio Huete Jimenez                 if (ip_optprint(ndo, (const u_char *)(ip + 1),
431*ed775ee7SAntonio Huete Jimenez                     hlen - sizeof(struct ip)) == -1) {
432*ed775ee7SAntonio Huete Jimenez                         ND_PRINT(" [truncated-option]");
433*ed775ee7SAntonio Huete Jimenez 			truncated = 1;
434*ed775ee7SAntonio Huete Jimenez                 }
435*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(")");
43641c99275SPeter Avalos             }
43741c99275SPeter Avalos 
438*ed775ee7SAntonio Huete Jimenez 	    if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) {
439*ed775ee7SAntonio Huete Jimenez 	        vec[0].ptr = (const uint8_t *)(const void *)ip;
44027bfbee1SPeter Avalos 	        vec[0].len = hlen;
44127bfbee1SPeter Avalos 	        sum = in_cksum(vec, 1);
44241c99275SPeter Avalos 		if (sum != 0) {
443*ed775ee7SAntonio Huete Jimenez 		    ip_sum = GET_BE_U_2(ip->ip_sum);
444*ed775ee7SAntonio Huete Jimenez 		    ND_PRINT(", bad cksum %x (->%x)!", ip_sum,
445*ed775ee7SAntonio Huete Jimenez 			     in_cksum_shouldbe(ip_sum, sum));
44641c99275SPeter Avalos 		}
44741c99275SPeter Avalos 	    }
44841c99275SPeter Avalos 
449*ed775ee7SAntonio Huete Jimenez 	    ND_PRINT(")\n    ");
450*ed775ee7SAntonio Huete Jimenez 	    if (truncated) {
451*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("%s > %s: ",
452*ed775ee7SAntonio Huete Jimenez 			 GET_IPADDR_STRING(ip->ip_src),
453*ed775ee7SAntonio Huete Jimenez 			 GET_IPADDR_STRING(ip->ip_dst));
454*ed775ee7SAntonio Huete Jimenez 		nd_print_trunc(ndo);
455*ed775ee7SAntonio Huete Jimenez 		nd_pop_packet_info(ndo);
456*ed775ee7SAntonio Huete Jimenez 		return;
457*ed775ee7SAntonio Huete Jimenez 	    }
45841c99275SPeter Avalos 	}
45941c99275SPeter Avalos 
46041c99275SPeter Avalos 	/*
46141c99275SPeter Avalos 	 * If this is fragment zero, hand it to the next higher
462*ed775ee7SAntonio Huete Jimenez 	 * level protocol.  Let them know whether there are more
463*ed775ee7SAntonio Huete Jimenez 	 * fragments.
46441c99275SPeter Avalos 	 */
465*ed775ee7SAntonio Huete Jimenez 	if ((off & IP_OFFMASK) == 0) {
466*ed775ee7SAntonio Huete Jimenez 		uint8_t nh = GET_U_1(ip->ip_p);
46741c99275SPeter Avalos 
468*ed775ee7SAntonio Huete Jimenez 		if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
469*ed775ee7SAntonio Huete Jimenez 		    nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) {
470*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("%s > %s: ",
471*ed775ee7SAntonio Huete Jimenez 				     GET_IPADDR_STRING(ip->ip_src),
472*ed775ee7SAntonio Huete Jimenez 				     GET_IPADDR_STRING(ip->ip_dst));
47341c99275SPeter Avalos 		}
474*ed775ee7SAntonio Huete Jimenez 		/*
475*ed775ee7SAntonio Huete Jimenez 		 * Do a bounds check before calling ip_demux_print().
476*ed775ee7SAntonio Huete Jimenez 		 * At least the header data is required.
477*ed775ee7SAntonio Huete Jimenez 		 */
478*ed775ee7SAntonio Huete Jimenez 		if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
479*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
480*ed775ee7SAntonio Huete Jimenez 				 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
481*ed775ee7SAntonio Huete Jimenez 				 hlen);
482*ed775ee7SAntonio Huete Jimenez 			nd_trunc_longjmp(ndo);
483*ed775ee7SAntonio Huete Jimenez 		}
484*ed775ee7SAntonio Huete Jimenez 		ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
485*ed775ee7SAntonio Huete Jimenez 			       off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
48641c99275SPeter Avalos 	} else {
487411677aeSAaron LI 		/*
488411677aeSAaron LI 		 * Ultra quiet now means that all this stuff should be
489411677aeSAaron LI 		 * suppressed.
490411677aeSAaron LI 		 */
491*ed775ee7SAntonio Huete Jimenez 		if (ndo->ndo_qflag > 1) {
492*ed775ee7SAntonio Huete Jimenez 			nd_pop_packet_info(ndo);
493411677aeSAaron LI 			return;
494*ed775ee7SAntonio Huete Jimenez 		}
49541c99275SPeter Avalos 
49641c99275SPeter Avalos 		/*
497411677aeSAaron LI 		 * This isn't the first frag, so we're missing the
49841c99275SPeter Avalos 		 * next level protocol header.  print the ip addr
49941c99275SPeter Avalos 		 * and the protocol.
50041c99275SPeter Avalos 		 */
501*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src),
502*ed775ee7SAntonio Huete Jimenez 		          GET_IPADDR_STRING(ip->ip_dst));
503*ed775ee7SAntonio Huete Jimenez 		if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
504*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" %s", p_name);
50541c99275SPeter Avalos 		else
506*ed775ee7SAntonio Huete Jimenez 			ND_PRINT(" ip-proto-%u", ip_proto);
50741c99275SPeter Avalos 	}
508*ed775ee7SAntonio Huete Jimenez 	nd_pop_packet_info(ndo);
509411677aeSAaron LI 	return;
510411677aeSAaron LI 
511411677aeSAaron LI trunc:
512*ed775ee7SAntonio Huete Jimenez 	nd_print_trunc(ndo);
51341c99275SPeter Avalos }
51441c99275SPeter Avalos 
51541c99275SPeter Avalos void
ipN_print(netdissect_options * ndo,const u_char * bp,u_int length)516*ed775ee7SAntonio Huete Jimenez ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
51741c99275SPeter Avalos {
518*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "ipn";
519411677aeSAaron LI 	if (length < 1) {
520*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("truncated-ip %u", length);
521411677aeSAaron LI 		return;
522411677aeSAaron LI 	}
52341c99275SPeter Avalos 
524*ed775ee7SAntonio Huete Jimenez 	switch (GET_U_1(bp) & 0xF0) {
525411677aeSAaron LI 	case 0x40:
526411677aeSAaron LI 		ip_print(ndo, bp, length);
527411677aeSAaron LI 		break;
528411677aeSAaron LI 	case 0x60:
529411677aeSAaron LI 		ip6_print(ndo, bp, length);
530411677aeSAaron LI 		break;
53141c99275SPeter Avalos 	default:
532*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4);
533411677aeSAaron LI 		break;
53441c99275SPeter Avalos 	}
53541c99275SPeter Avalos }
536