xref: /aosp_15_r20/external/tcpdump/print-ip.c (revision 05b00f6010a2396e3db2409989fc67270046269f)
1*05b00f60SXin Li /*
2*05b00f60SXin Li  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3*05b00f60SXin Li  *	The Regents of the University of California.  All rights reserved.
4*05b00f60SXin Li  *
5*05b00f60SXin Li  * Redistribution and use in source and binary forms, with or without
6*05b00f60SXin Li  * modification, are permitted provided that: (1) source code distributions
7*05b00f60SXin Li  * retain the above copyright notice and this paragraph in its entirety, (2)
8*05b00f60SXin Li  * distributions including binary code include the above copyright notice and
9*05b00f60SXin Li  * this paragraph in its entirety in the documentation or other materials
10*05b00f60SXin Li  * provided with the distribution, and (3) all advertising materials mentioning
11*05b00f60SXin Li  * features or use of this software display the following acknowledgement:
12*05b00f60SXin Li  * ``This product includes software developed by the University of California,
13*05b00f60SXin Li  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14*05b00f60SXin Li  * the University nor the names of its contributors may be used to endorse
15*05b00f60SXin Li  * or promote products derived from this software without specific prior
16*05b00f60SXin Li  * written permission.
17*05b00f60SXin Li  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18*05b00f60SXin Li  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19*05b00f60SXin Li  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20*05b00f60SXin Li  */
21*05b00f60SXin Li 
22*05b00f60SXin Li /* \summary: IP printer */
23*05b00f60SXin Li 
24*05b00f60SXin Li #ifdef HAVE_CONFIG_H
25*05b00f60SXin Li #include <config.h>
26*05b00f60SXin Li #endif
27*05b00f60SXin Li 
28*05b00f60SXin Li #include "netdissect-stdinc.h"
29*05b00f60SXin Li 
30*05b00f60SXin Li #include "netdissect.h"
31*05b00f60SXin Li #include "addrtoname.h"
32*05b00f60SXin Li #include "extract.h"
33*05b00f60SXin Li 
34*05b00f60SXin Li #include "ip.h"
35*05b00f60SXin Li #include "ipproto.h"
36*05b00f60SXin Li 
37*05b00f60SXin Li 
38*05b00f60SXin Li static const struct tok ip_option_values[] = {
39*05b00f60SXin Li     { IPOPT_EOL, "EOL" },
40*05b00f60SXin Li     { IPOPT_NOP, "NOP" },
41*05b00f60SXin Li     { IPOPT_TS, "timestamp" },
42*05b00f60SXin Li     { IPOPT_SECURITY, "security" },
43*05b00f60SXin Li     { IPOPT_RR, "RR" },
44*05b00f60SXin Li     { IPOPT_SSRR, "SSRR" },
45*05b00f60SXin Li     { IPOPT_LSRR, "LSRR" },
46*05b00f60SXin Li     { IPOPT_RA, "RA" },
47*05b00f60SXin Li     { IPOPT_RFC1393, "traceroute" },
48*05b00f60SXin Li     { 0, NULL }
49*05b00f60SXin Li };
50*05b00f60SXin Li 
51*05b00f60SXin Li /*
52*05b00f60SXin Li  * print the recorded route in an IP RR, LSRR or SSRR option.
53*05b00f60SXin Li  */
54*05b00f60SXin Li static int
ip_printroute(netdissect_options * ndo,const u_char * cp,u_int length)55*05b00f60SXin Li ip_printroute(netdissect_options *ndo,
56*05b00f60SXin Li               const u_char *cp, u_int length)
57*05b00f60SXin Li {
58*05b00f60SXin Li 	u_int ptr;
59*05b00f60SXin Li 	u_int len;
60*05b00f60SXin Li 
61*05b00f60SXin Li 	if (length < 3) {
62*05b00f60SXin Li 		ND_PRINT(" [bad length %u]", length);
63*05b00f60SXin Li 		return (0);
64*05b00f60SXin Li 	}
65*05b00f60SXin Li 	if ((length + 1) & 3)
66*05b00f60SXin Li 		ND_PRINT(" [bad length %u]", length);
67*05b00f60SXin Li 	ptr = GET_U_1(cp + 2) - 1;
68*05b00f60SXin Li 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
69*05b00f60SXin Li 		ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2));
70*05b00f60SXin Li 
71*05b00f60SXin Li 	for (len = 3; len < length; len += 4) {
72*05b00f60SXin Li 		ND_TCHECK_4(cp + len);	/* Needed to print the IP addresses */
73*05b00f60SXin Li 		ND_PRINT(" %s", GET_IPADDR_STRING(cp + len));
74*05b00f60SXin Li 		if (ptr > len)
75*05b00f60SXin Li 			ND_PRINT(",");
76*05b00f60SXin Li 	}
77*05b00f60SXin Li 	return (0);
78*05b00f60SXin Li 
79*05b00f60SXin Li trunc:
80*05b00f60SXin Li 	return (-1);
81*05b00f60SXin Li }
82*05b00f60SXin Li 
83*05b00f60SXin Li /*
84*05b00f60SXin Li  * If source-routing is present and valid, return the final destination.
85*05b00f60SXin Li  * Otherwise, return IP destination.
86*05b00f60SXin Li  *
87*05b00f60SXin Li  * This is used for UDP and TCP pseudo-header in the checksum
88*05b00f60SXin Li  * calculation.
89*05b00f60SXin Li  */
90*05b00f60SXin Li static uint32_t
ip_finddst(netdissect_options * ndo,const struct ip * ip)91*05b00f60SXin Li ip_finddst(netdissect_options *ndo,
92*05b00f60SXin Li            const struct ip *ip)
93*05b00f60SXin Li {
94*05b00f60SXin Li 	u_int length;
95*05b00f60SXin Li 	u_int len;
96*05b00f60SXin Li 	const u_char *cp;
97*05b00f60SXin Li 
98*05b00f60SXin Li 	cp = (const u_char *)(ip + 1);
99*05b00f60SXin Li 	length = IP_HL(ip) * 4;
100*05b00f60SXin Li 	if (length < sizeof(struct ip))
101*05b00f60SXin Li 		goto trunc;
102*05b00f60SXin Li 	length -= sizeof(struct ip);
103*05b00f60SXin Li 
104*05b00f60SXin Li 	for (; length != 0; cp += len, length -= len) {
105*05b00f60SXin Li 		int tt;
106*05b00f60SXin Li 
107*05b00f60SXin Li 		tt = GET_U_1(cp);
108*05b00f60SXin Li 		if (tt == IPOPT_EOL)
109*05b00f60SXin Li 			break;
110*05b00f60SXin Li 		else if (tt == IPOPT_NOP)
111*05b00f60SXin Li 			len = 1;
112*05b00f60SXin Li 		else {
113*05b00f60SXin Li 			len = GET_U_1(cp + 1);
114*05b00f60SXin Li 			if (len < 2)
115*05b00f60SXin Li 				break;
116*05b00f60SXin Li 		}
117*05b00f60SXin Li 		if (length < len)
118*05b00f60SXin Li 			goto trunc;
119*05b00f60SXin Li 		ND_TCHECK_LEN(cp, len);
120*05b00f60SXin Li 		switch (tt) {
121*05b00f60SXin Li 
122*05b00f60SXin Li 		case IPOPT_SSRR:
123*05b00f60SXin Li 		case IPOPT_LSRR:
124*05b00f60SXin Li 			if (len < 7)
125*05b00f60SXin Li 				break;
126*05b00f60SXin Li 			return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4));
127*05b00f60SXin Li 		}
128*05b00f60SXin Li 	}
129*05b00f60SXin Li trunc:
130*05b00f60SXin Li 	return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst));
131*05b00f60SXin Li }
132*05b00f60SXin Li 
133*05b00f60SXin Li /*
134*05b00f60SXin Li  * Compute a V4-style checksum by building a pseudoheader.
135*05b00f60SXin Li  */
136*05b00f60SXin Li 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)137*05b00f60SXin Li nextproto4_cksum(netdissect_options *ndo,
138*05b00f60SXin Li                  const struct ip *ip, const uint8_t *data,
139*05b00f60SXin Li                  u_int len, u_int covlen, uint8_t next_proto)
140*05b00f60SXin Li {
141*05b00f60SXin Li 	struct phdr {
142*05b00f60SXin Li 		uint32_t src;
143*05b00f60SXin Li 		uint32_t dst;
144*05b00f60SXin Li 		uint8_t mbz;
145*05b00f60SXin Li 		uint8_t proto;
146*05b00f60SXin Li 		uint16_t len;
147*05b00f60SXin Li 	} ph;
148*05b00f60SXin Li 	struct cksum_vec vec[2];
149*05b00f60SXin Li 
150*05b00f60SXin Li 	/* pseudo-header.. */
151*05b00f60SXin Li 	ph.len = htons((uint16_t)len);
152*05b00f60SXin Li 	ph.mbz = 0;
153*05b00f60SXin Li 	ph.proto = next_proto;
154*05b00f60SXin Li 	ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
155*05b00f60SXin Li 	if (IP_HL(ip) == 5)
156*05b00f60SXin Li 		ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
157*05b00f60SXin Li 	else
158*05b00f60SXin Li 		ph.dst = ip_finddst(ndo, ip);
159*05b00f60SXin Li 
160*05b00f60SXin Li 	vec[0].ptr = (const uint8_t *)(void *)&ph;
161*05b00f60SXin Li 	vec[0].len = sizeof(ph);
162*05b00f60SXin Li 	vec[1].ptr = data;
163*05b00f60SXin Li 	vec[1].len = covlen;
164*05b00f60SXin Li 	return (in_cksum(vec, 2));
165*05b00f60SXin Li }
166*05b00f60SXin Li 
167*05b00f60SXin Li static int
ip_printts(netdissect_options * ndo,const u_char * cp,u_int length)168*05b00f60SXin Li ip_printts(netdissect_options *ndo,
169*05b00f60SXin Li            const u_char *cp, u_int length)
170*05b00f60SXin Li {
171*05b00f60SXin Li 	u_int ptr;
172*05b00f60SXin Li 	u_int len;
173*05b00f60SXin Li 	u_int hoplen;
174*05b00f60SXin Li 	const char *type;
175*05b00f60SXin Li 
176*05b00f60SXin Li 	if (length < 4) {
177*05b00f60SXin Li 		ND_PRINT("[bad length %u]", length);
178*05b00f60SXin Li 		return (0);
179*05b00f60SXin Li 	}
180*05b00f60SXin Li 	ND_PRINT(" TS{");
181*05b00f60SXin Li 	hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
182*05b00f60SXin Li 	if ((length - 4) & (hoplen-1))
183*05b00f60SXin Li 		ND_PRINT("[bad length %u]", length);
184*05b00f60SXin Li 	ptr = GET_U_1(cp + 2) - 1;
185*05b00f60SXin Li 	len = 0;
186*05b00f60SXin Li 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
187*05b00f60SXin Li 		ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2));
188*05b00f60SXin Li 	switch (GET_U_1(cp + 3)&0xF) {
189*05b00f60SXin Li 	case IPOPT_TS_TSONLY:
190*05b00f60SXin Li 		ND_PRINT("TSONLY");
191*05b00f60SXin Li 		break;
192*05b00f60SXin Li 	case IPOPT_TS_TSANDADDR:
193*05b00f60SXin Li 		ND_PRINT("TS+ADDR");
194*05b00f60SXin Li 		break;
195*05b00f60SXin Li 	case IPOPT_TS_PRESPEC:
196*05b00f60SXin Li 		ND_PRINT("PRESPEC");
197*05b00f60SXin Li 		break;
198*05b00f60SXin Li 	default:
199*05b00f60SXin Li 		ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF);
200*05b00f60SXin Li 		goto done;
201*05b00f60SXin Li 	}
202*05b00f60SXin Li 
203*05b00f60SXin Li 	type = " ";
204*05b00f60SXin Li 	for (len = 4; len < length; len += hoplen) {
205*05b00f60SXin Li 		if (ptr == len)
206*05b00f60SXin Li 			type = " ^ ";
207*05b00f60SXin Li 		ND_TCHECK_LEN(cp + len, hoplen);
208*05b00f60SXin Li 		ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4),
209*05b00f60SXin Li 			  hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len));
210*05b00f60SXin Li 		type = " ";
211*05b00f60SXin Li 	}
212*05b00f60SXin Li 
213*05b00f60SXin Li done:
214*05b00f60SXin Li 	ND_PRINT("%s", ptr == len ? " ^ " : "");
215*05b00f60SXin Li 
216*05b00f60SXin Li 	if (GET_U_1(cp + 3) >> 4)
217*05b00f60SXin Li 		ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4);
218*05b00f60SXin Li 	else
219*05b00f60SXin Li 		ND_PRINT("}");
220*05b00f60SXin Li 	return (0);
221*05b00f60SXin Li 
222*05b00f60SXin Li trunc:
223*05b00f60SXin Li 	return (-1);
224*05b00f60SXin Li }
225*05b00f60SXin Li 
226*05b00f60SXin Li /*
227*05b00f60SXin Li  * print IP options.
228*05b00f60SXin Li    If truncated return -1, else 0.
229*05b00f60SXin Li  */
230*05b00f60SXin Li static int
ip_optprint(netdissect_options * ndo,const u_char * cp,u_int length)231*05b00f60SXin Li ip_optprint(netdissect_options *ndo,
232*05b00f60SXin Li             const u_char *cp, u_int length)
233*05b00f60SXin Li {
234*05b00f60SXin Li 	u_int option_len;
235*05b00f60SXin Li 	const char *sep = "";
236*05b00f60SXin Li 
237*05b00f60SXin Li 	for (; length > 0; cp += option_len, length -= option_len) {
238*05b00f60SXin Li 		u_int option_code;
239*05b00f60SXin Li 
240*05b00f60SXin Li 		ND_PRINT("%s", sep);
241*05b00f60SXin Li 		sep = ",";
242*05b00f60SXin Li 
243*05b00f60SXin Li 		option_code = GET_U_1(cp);
244*05b00f60SXin Li 
245*05b00f60SXin Li 		ND_PRINT("%s",
246*05b00f60SXin Li 		          tok2str(ip_option_values,"unknown %u",option_code));
247*05b00f60SXin Li 
248*05b00f60SXin Li 		if (option_code == IPOPT_NOP ||
249*05b00f60SXin Li                     option_code == IPOPT_EOL)
250*05b00f60SXin Li 			option_len = 1;
251*05b00f60SXin Li 
252*05b00f60SXin Li 		else {
253*05b00f60SXin Li 			option_len = GET_U_1(cp + 1);
254*05b00f60SXin Li 			if (option_len < 2) {
255*05b00f60SXin Li 				ND_PRINT(" [bad length %u]", option_len);
256*05b00f60SXin Li 				return 0;
257*05b00f60SXin Li 			}
258*05b00f60SXin Li 		}
259*05b00f60SXin Li 
260*05b00f60SXin Li 		if (option_len > length) {
261*05b00f60SXin Li 			ND_PRINT(" [bad length %u]", option_len);
262*05b00f60SXin Li 			return 0;
263*05b00f60SXin Li 		}
264*05b00f60SXin Li 
265*05b00f60SXin Li 		ND_TCHECK_LEN(cp, option_len);
266*05b00f60SXin Li 
267*05b00f60SXin Li 		switch (option_code) {
268*05b00f60SXin Li 		case IPOPT_EOL:
269*05b00f60SXin Li 			return 0;
270*05b00f60SXin Li 
271*05b00f60SXin Li 		case IPOPT_TS:
272*05b00f60SXin Li 			if (ip_printts(ndo, cp, option_len) == -1)
273*05b00f60SXin Li 				goto trunc;
274*05b00f60SXin Li 			break;
275*05b00f60SXin Li 
276*05b00f60SXin Li 		case IPOPT_RR:       /* fall through */
277*05b00f60SXin Li 		case IPOPT_SSRR:
278*05b00f60SXin Li 		case IPOPT_LSRR:
279*05b00f60SXin Li 			if (ip_printroute(ndo, cp, option_len) == -1)
280*05b00f60SXin Li 				goto trunc;
281*05b00f60SXin Li 			break;
282*05b00f60SXin Li 
283*05b00f60SXin Li 		case IPOPT_RA:
284*05b00f60SXin Li 			if (option_len < 4) {
285*05b00f60SXin Li 				ND_PRINT(" [bad length %u]", option_len);
286*05b00f60SXin Li 				break;
287*05b00f60SXin Li 			}
288*05b00f60SXin Li 			ND_TCHECK_1(cp + 3);
289*05b00f60SXin Li 			if (GET_BE_U_2(cp + 2) != 0)
290*05b00f60SXin Li 				ND_PRINT(" value %u", GET_BE_U_2(cp + 2));
291*05b00f60SXin Li 			break;
292*05b00f60SXin Li 
293*05b00f60SXin Li 		case IPOPT_NOP:       /* nothing to print - fall through */
294*05b00f60SXin Li 		case IPOPT_SECURITY:
295*05b00f60SXin Li 		default:
296*05b00f60SXin Li 			break;
297*05b00f60SXin Li 		}
298*05b00f60SXin Li 	}
299*05b00f60SXin Li 	return 0;
300*05b00f60SXin Li 
301*05b00f60SXin Li trunc:
302*05b00f60SXin Li 	return -1;
303*05b00f60SXin Li }
304*05b00f60SXin Li 
305*05b00f60SXin Li #define IP_RES 0x8000
306*05b00f60SXin Li 
307*05b00f60SXin Li static const struct tok ip_frag_values[] = {
308*05b00f60SXin Li         { IP_MF,        "+" },
309*05b00f60SXin Li         { IP_DF,        "DF" },
310*05b00f60SXin Li 	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
311*05b00f60SXin Li         { 0,            NULL }
312*05b00f60SXin Li };
313*05b00f60SXin Li 
314*05b00f60SXin Li 
315*05b00f60SXin Li /*
316*05b00f60SXin Li  * print an IP datagram.
317*05b00f60SXin Li  */
318*05b00f60SXin Li void
ip_print(netdissect_options * ndo,const u_char * bp,u_int length)319*05b00f60SXin Li ip_print(netdissect_options *ndo,
320*05b00f60SXin Li 	 const u_char *bp,
321*05b00f60SXin Li 	 u_int length)
322*05b00f60SXin Li {
323*05b00f60SXin Li 	const struct ip *ip;
324*05b00f60SXin Li 	u_int off;
325*05b00f60SXin Li 	u_int hlen;
326*05b00f60SXin Li 	u_int len;
327*05b00f60SXin Li 	struct cksum_vec vec[1];
328*05b00f60SXin Li 	uint8_t ip_tos, ip_ttl, ip_proto;
329*05b00f60SXin Li 	uint16_t sum, ip_sum;
330*05b00f60SXin Li 	const char *p_name;
331*05b00f60SXin Li 	int truncated = 0;
332*05b00f60SXin Li 
333*05b00f60SXin Li 	ndo->ndo_protocol = "ip";
334*05b00f60SXin Li 	ip = (const struct ip *)bp;
335*05b00f60SXin Li 	if (IP_V(ip) != 4) { /* print version and fail if != 4 */
336*05b00f60SXin Li 	    if (IP_V(ip) == 6)
337*05b00f60SXin Li 	      ND_PRINT("IP6, wrong link-layer encapsulation");
338*05b00f60SXin Li 	    else
339*05b00f60SXin Li 	      ND_PRINT("IP%u", IP_V(ip));
340*05b00f60SXin Li 	    nd_print_invalid(ndo);
341*05b00f60SXin Li 	    return;
342*05b00f60SXin Li 	}
343*05b00f60SXin Li 	if (!ndo->ndo_eflag)
344*05b00f60SXin Li 		ND_PRINT("IP ");
345*05b00f60SXin Li 
346*05b00f60SXin Li 	ND_TCHECK_SIZE(ip);
347*05b00f60SXin Li 	if (length < sizeof (struct ip)) {
348*05b00f60SXin Li 		ND_PRINT("truncated-ip %u", length);
349*05b00f60SXin Li 		return;
350*05b00f60SXin Li 	}
351*05b00f60SXin Li 	hlen = IP_HL(ip) * 4;
352*05b00f60SXin Li 	if (hlen < sizeof (struct ip)) {
353*05b00f60SXin Li 		ND_PRINT("bad-hlen %u", hlen);
354*05b00f60SXin Li 		return;
355*05b00f60SXin Li 	}
356*05b00f60SXin Li 
357*05b00f60SXin Li 	len = GET_BE_U_2(ip->ip_len);
358*05b00f60SXin Li 	if (length < len)
359*05b00f60SXin Li 		ND_PRINT("truncated-ip - %u bytes missing! ",
360*05b00f60SXin Li 			len - length);
361*05b00f60SXin Li 	if (len < hlen) {
362*05b00f60SXin Li #ifdef GUESS_TSO
363*05b00f60SXin Li             if (len) {
364*05b00f60SXin Li                 ND_PRINT("bad-len %u", len);
365*05b00f60SXin Li                 return;
366*05b00f60SXin Li             }
367*05b00f60SXin Li             else {
368*05b00f60SXin Li                 /* we guess that it is a TSO send */
369*05b00f60SXin Li                 len = length;
370*05b00f60SXin Li             }
371*05b00f60SXin Li #else
372*05b00f60SXin Li             ND_PRINT("bad-len %u", len);
373*05b00f60SXin Li             return;
374*05b00f60SXin Li #endif /* GUESS_TSO */
375*05b00f60SXin Li 	}
376*05b00f60SXin Li 
377*05b00f60SXin Li 	/*
378*05b00f60SXin Li 	 * Cut off the snapshot length to the end of the IP payload.
379*05b00f60SXin Li 	 */
380*05b00f60SXin Li 	if (!nd_push_snaplen(ndo, bp, len)) {
381*05b00f60SXin Li 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
382*05b00f60SXin Li 			"%s: can't push snaplen on buffer stack", __func__);
383*05b00f60SXin Li 	}
384*05b00f60SXin Li 
385*05b00f60SXin Li 	len -= hlen;
386*05b00f60SXin Li 
387*05b00f60SXin Li 	off = GET_BE_U_2(ip->ip_off);
388*05b00f60SXin Li 
389*05b00f60SXin Li         ip_proto = GET_U_1(ip->ip_p);
390*05b00f60SXin Li 
391*05b00f60SXin Li         if (ndo->ndo_vflag) {
392*05b00f60SXin Li             ip_tos = GET_U_1(ip->ip_tos);
393*05b00f60SXin Li             ND_PRINT("(tos 0x%x", ip_tos);
394*05b00f60SXin Li             /* ECN bits */
395*05b00f60SXin Li             switch (ip_tos & 0x03) {
396*05b00f60SXin Li 
397*05b00f60SXin Li             case 0:
398*05b00f60SXin Li                 break;
399*05b00f60SXin Li 
400*05b00f60SXin Li             case 1:
401*05b00f60SXin Li                 ND_PRINT(",ECT(1)");
402*05b00f60SXin Li                 break;
403*05b00f60SXin Li 
404*05b00f60SXin Li             case 2:
405*05b00f60SXin Li                 ND_PRINT(",ECT(0)");
406*05b00f60SXin Li                 break;
407*05b00f60SXin Li 
408*05b00f60SXin Li             case 3:
409*05b00f60SXin Li                 ND_PRINT(",CE");
410*05b00f60SXin Li                 break;
411*05b00f60SXin Li             }
412*05b00f60SXin Li 
413*05b00f60SXin Li             ip_ttl = GET_U_1(ip->ip_ttl);
414*05b00f60SXin Li             if (ip_ttl >= 1)
415*05b00f60SXin Li                 ND_PRINT(", ttl %u", ip_ttl);
416*05b00f60SXin Li 
417*05b00f60SXin Li 	    /*
418*05b00f60SXin Li 	     * for the firewall guys, print id, offset.
419*05b00f60SXin Li              * On all but the last stick a "+" in the flags portion.
420*05b00f60SXin Li 	     * For unfragmented datagrams, note the don't fragment flag.
421*05b00f60SXin Li 	     */
422*05b00f60SXin Li 	    ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)",
423*05b00f60SXin Li                          GET_BE_U_2(ip->ip_id),
424*05b00f60SXin Li                          (off & IP_OFFMASK) * 8,
425*05b00f60SXin Li                          bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)),
426*05b00f60SXin Li                          tok2str(ipproto_values, "unknown", ip_proto),
427*05b00f60SXin Li                          ip_proto);
428*05b00f60SXin Li 
429*05b00f60SXin Li             ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
430*05b00f60SXin Li 
431*05b00f60SXin Li             if ((hlen - sizeof(struct ip)) > 0) {
432*05b00f60SXin Li                 ND_PRINT(", options (");
433*05b00f60SXin Li                 if (ip_optprint(ndo, (const u_char *)(ip + 1),
434*05b00f60SXin Li                     hlen - sizeof(struct ip)) == -1) {
435*05b00f60SXin Li                         ND_PRINT(" [truncated-option]");
436*05b00f60SXin Li 			truncated = 1;
437*05b00f60SXin Li                 }
438*05b00f60SXin Li                 ND_PRINT(")");
439*05b00f60SXin Li             }
440*05b00f60SXin Li 
441*05b00f60SXin Li 	    if (!ndo->ndo_Kflag && (const u_char *)ip + hlen <= ndo->ndo_snapend) {
442*05b00f60SXin Li 	        vec[0].ptr = (const uint8_t *)(const void *)ip;
443*05b00f60SXin Li 	        vec[0].len = hlen;
444*05b00f60SXin Li 	        sum = in_cksum(vec, 1);
445*05b00f60SXin Li 		if (sum != 0) {
446*05b00f60SXin Li 		    ip_sum = GET_BE_U_2(ip->ip_sum);
447*05b00f60SXin Li 		    ND_PRINT(", bad cksum %x (->%x)!", ip_sum,
448*05b00f60SXin Li 			     in_cksum_shouldbe(ip_sum, sum));
449*05b00f60SXin Li 		}
450*05b00f60SXin Li 	    }
451*05b00f60SXin Li 
452*05b00f60SXin Li 	    ND_PRINT(")\n    ");
453*05b00f60SXin Li 	    if (truncated) {
454*05b00f60SXin Li 		ND_PRINT("%s > %s: ",
455*05b00f60SXin Li 			 GET_IPADDR_STRING(ip->ip_src),
456*05b00f60SXin Li 			 GET_IPADDR_STRING(ip->ip_dst));
457*05b00f60SXin Li 		nd_print_trunc(ndo);
458*05b00f60SXin Li 		nd_pop_packet_info(ndo);
459*05b00f60SXin Li 		return;
460*05b00f60SXin Li 	    }
461*05b00f60SXin Li 	}
462*05b00f60SXin Li 
463*05b00f60SXin Li 	/*
464*05b00f60SXin Li 	 * If this is fragment zero, hand it to the next higher
465*05b00f60SXin Li 	 * level protocol.  Let them know whether there are more
466*05b00f60SXin Li 	 * fragments.
467*05b00f60SXin Li 	 */
468*05b00f60SXin Li 	if ((off & IP_OFFMASK) == 0) {
469*05b00f60SXin Li 		uint8_t nh = GET_U_1(ip->ip_p);
470*05b00f60SXin Li 
471*05b00f60SXin Li 		if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
472*05b00f60SXin Li 		    nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) {
473*05b00f60SXin Li 			ND_PRINT("%s > %s: ",
474*05b00f60SXin Li 				     GET_IPADDR_STRING(ip->ip_src),
475*05b00f60SXin Li 				     GET_IPADDR_STRING(ip->ip_dst));
476*05b00f60SXin Li 		}
477*05b00f60SXin Li 		/*
478*05b00f60SXin Li 		 * Do a bounds check before calling ip_demux_print().
479*05b00f60SXin Li 		 * At least the header data is required.
480*05b00f60SXin Li 		 */
481*05b00f60SXin Li 		if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
482*05b00f60SXin Li 			ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
483*05b00f60SXin Li 				 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
484*05b00f60SXin Li 				 hlen);
485*05b00f60SXin Li 			nd_trunc_longjmp(ndo);
486*05b00f60SXin Li 		}
487*05b00f60SXin Li 		ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
488*05b00f60SXin Li 			       off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
489*05b00f60SXin Li 	} else {
490*05b00f60SXin Li 		/*
491*05b00f60SXin Li 		 * Ultra quiet now means that all this stuff should be
492*05b00f60SXin Li 		 * suppressed.
493*05b00f60SXin Li 		 */
494*05b00f60SXin Li 		if (ndo->ndo_qflag > 1) {
495*05b00f60SXin Li 			nd_pop_packet_info(ndo);
496*05b00f60SXin Li 			return;
497*05b00f60SXin Li 		}
498*05b00f60SXin Li 
499*05b00f60SXin Li 		/*
500*05b00f60SXin Li 		 * This isn't the first frag, so we're missing the
501*05b00f60SXin Li 		 * next level protocol header.  print the ip addr
502*05b00f60SXin Li 		 * and the protocol.
503*05b00f60SXin Li 		 */
504*05b00f60SXin Li 		ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src),
505*05b00f60SXin Li 		          GET_IPADDR_STRING(ip->ip_dst));
506*05b00f60SXin Li 		if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
507*05b00f60SXin Li 			ND_PRINT(" %s", p_name);
508*05b00f60SXin Li 		else
509*05b00f60SXin Li 			ND_PRINT(" ip-proto-%u", ip_proto);
510*05b00f60SXin Li 	}
511*05b00f60SXin Li 	nd_pop_packet_info(ndo);
512*05b00f60SXin Li 	return;
513*05b00f60SXin Li 
514*05b00f60SXin Li trunc:
515*05b00f60SXin Li 	nd_print_trunc(ndo);
516*05b00f60SXin Li }
517*05b00f60SXin Li 
518*05b00f60SXin Li void
ipN_print(netdissect_options * ndo,const u_char * bp,u_int length)519*05b00f60SXin Li ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
520*05b00f60SXin Li {
521*05b00f60SXin Li 	ndo->ndo_protocol = "ipn";
522*05b00f60SXin Li 	if (length < 1) {
523*05b00f60SXin Li 		ND_PRINT("truncated-ip %u", length);
524*05b00f60SXin Li 		return;
525*05b00f60SXin Li 	}
526*05b00f60SXin Li 
527*05b00f60SXin Li 	switch (GET_U_1(bp) & 0xF0) {
528*05b00f60SXin Li 	case 0x40:
529*05b00f60SXin Li 		ip_print(ndo, bp, length);
530*05b00f60SXin Li 		break;
531*05b00f60SXin Li 	case 0x60:
532*05b00f60SXin Li 		ip6_print(ndo, bp, length);
533*05b00f60SXin Li 		break;
534*05b00f60SXin Li 	default:
535*05b00f60SXin Li 		ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4);
536*05b00f60SXin Li 		break;
537*05b00f60SXin Li 	}
538*05b00f60SXin Li }
539