xref: /netbsd-src/external/bsd/tcpdump/dist/print-ip.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 #if 0
25 static const char rcsid[] _U_ =
26     "@(#) Header: /tcpdump/master/tcpdump/print-ip.c,v 1.159 2007-09-14 01:29:28 guy Exp  (LBL)";
27 #else
28 __RCSID("$NetBSD: print-ip.c,v 1.6 2013/12/31 17:33:31 christos Exp $");
29 #endif
30 #endif
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <tcpdump-stdinc.h>
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "addrtoname.h"
43 #include "interface.h"
44 #include "extract.h"			/* must come after interface.h */
45 
46 #include "ip.h"
47 #include "ipproto.h"
48 
49 static const struct tok ip_option_values[] = {
50     { IPOPT_EOL, "EOL" },
51     { IPOPT_NOP, "NOP" },
52     { IPOPT_TS, "timestamp" },
53     { IPOPT_SECURITY, "security" },
54     { IPOPT_RR, "RR" },
55     { IPOPT_SSRR, "SSRR" },
56     { IPOPT_LSRR, "LSRR" },
57     { IPOPT_RA, "RA" },
58     { IPOPT_RFC1393, "traceroute" },
59     { 0, NULL }
60 };
61 
62 /*
63  * print the recorded route in an IP RR, LSRR or SSRR option.
64  */
65 static void
66 ip_printroute(register const u_char *cp, u_int length)
67 {
68 	register u_int ptr;
69 	register u_int len;
70 
71 	if (length < 3) {
72 		printf(" [bad length %u]", length);
73 		return;
74 	}
75 	if ((length + 1) & 3)
76 		printf(" [bad length %u]", length);
77 	ptr = cp[2] - 1;
78 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
79 		printf(" [bad ptr %u]", cp[2]);
80 
81 	for (len = 3; len < length; len += 4) {
82 		printf(" %s", ipaddr_string(&cp[len]));
83                 if (ptr > len)
84                         printf(",");
85 	}
86 }
87 
88 /*
89  * If source-routing is present and valid, return the final destination.
90  * Otherwise, return IP destination.
91  *
92  * This is used for UDP and TCP pseudo-header in the checksum
93  * calculation.
94  */
95 static u_int32_t
96 ip_finddst(const struct ip *ip)
97 {
98 	int length;
99 	int len;
100 	const u_char *cp;
101 	u_int32_t retval;
102 
103 	cp = (const u_char *)(ip + 1);
104 	length = (IP_HL(ip) << 2) - sizeof(struct ip);
105 
106 	for (; length > 0; cp += len, length -= len) {
107 		int tt;
108 
109 		TCHECK(*cp);
110 		tt = *cp;
111 		if (tt == IPOPT_EOL)
112 			break;
113 		else if (tt == IPOPT_NOP)
114 			len = 1;
115 		else {
116 			TCHECK(cp[1]);
117 			len = cp[1];
118 			if (len < 2)
119 				break;
120 		}
121 		TCHECK2(*cp, len);
122 		switch (tt) {
123 
124 		case IPOPT_SSRR:
125 		case IPOPT_LSRR:
126 			if (len < 7)
127 				break;
128 			memcpy(&retval, cp + len - 4, 4);
129 			return retval;
130 		}
131 	}
132 trunc:
133 	memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));
134 	return retval;
135 }
136 
137 /*
138  * Compute a V4-style checksum by building a pseudoheader.
139  */
140 int
141 nextproto4_cksum(const struct ip *ip, const u_int8_t *data,
142 		 u_int len, u_int next_proto)
143 {
144 	struct phdr {
145 		u_int32_t src;
146 		u_int32_t dst;
147 		u_char mbz;
148 		u_char proto;
149 		u_int16_t len;
150 	} ph;
151 	struct cksum_vec vec[2];
152 
153 	/* pseudo-header.. */
154 	ph.len = htons((u_int16_t)len);
155 	ph.mbz = 0;
156 	ph.proto = next_proto;
157 	memcpy(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
158 	if (IP_HL(ip) == 5)
159 		memcpy(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
160 	else
161 		ph.dst = ip_finddst(ip);
162 
163 	vec[0].ptr = (const u_int8_t *)(void *)&ph;
164 	vec[0].len = sizeof(ph);
165 	vec[1].ptr = data;
166 	vec[1].len = len;
167 	return (in_cksum(vec, 2));
168 }
169 
170 static void
171 ip_printts(register const u_char *cp, u_int length)
172 {
173 	register u_int ptr;
174 	register u_int len;
175 	int hoplen;
176 	const char *type;
177 
178 	if (length < 4) {
179 		printf("[bad length %u]", length);
180 		return;
181 	}
182 	printf(" TS{");
183 	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
184 	if ((length - 4) & (hoplen-1))
185 		printf("[bad length %u]", length);
186 	ptr = cp[2] - 1;
187 	len = 0;
188 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
189 		printf("[bad ptr %u]", cp[2]);
190 	switch (cp[3]&0xF) {
191 	case IPOPT_TS_TSONLY:
192 		printf("TSONLY");
193 		break;
194 	case IPOPT_TS_TSANDADDR:
195 		printf("TS+ADDR");
196 		break;
197 	/*
198 	 * prespecified should really be 3, but some ones might send 2
199 	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
200 	 * have both values, so we have to hard-code it here.
201 	 */
202 
203 	case 2:
204 		printf("PRESPEC2.0");
205 		break;
206 	case 3:			/* IPOPT_TS_PRESPEC */
207 		printf("PRESPEC");
208 		break;
209 	default:
210 		printf("[bad ts type %d]", cp[3]&0xF);
211 		goto done;
212 	}
213 
214 	type = " ";
215 	for (len = 4; len < length; len += hoplen) {
216 		if (ptr == len)
217 			type = " ^ ";
218 		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
219 		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));
220 		type = " ";
221 	}
222 
223 done:
224 	printf("%s", ptr == len ? " ^ " : "");
225 
226 	if (cp[3]>>4)
227 		printf(" [%d hops not recorded]} ", cp[3]>>4);
228 	else
229 		printf("}");
230 }
231 
232 /*
233  * print IP options.
234  */
235 static void
236 ip_optprint(register const u_char *cp, u_int length)
237 {
238 	register u_int option_len;
239 	const char *sep = "";
240 
241 	for (; length > 0; cp += option_len, length -= option_len) {
242 		u_int option_code;
243 
244 		printf("%s", sep);
245 		sep = ",";
246 
247 		TCHECK(*cp);
248 		option_code = *cp;
249 
250                 printf("%s",
251                         tok2str(ip_option_values,"unknown %u",option_code));
252 
253 		if (option_code == IPOPT_NOP ||
254                     option_code == IPOPT_EOL)
255 			option_len = 1;
256 
257 		else {
258 			TCHECK(cp[1]);
259 			option_len = cp[1];
260 			if (option_len < 2) {
261 		                printf(" [bad length %u]", option_len);
262 				return;
263 			}
264 		}
265 
266 		if (option_len > length) {
267 	                printf(" [bad length %u]", option_len);
268 			return;
269 		}
270 
271                 TCHECK2(*cp, option_len);
272 
273 		switch (option_code) {
274 		case IPOPT_EOL:
275 			return;
276 
277 		case IPOPT_TS:
278 			ip_printts(cp, option_len);
279 			break;
280 
281 		case IPOPT_RR:       /* fall through */
282 		case IPOPT_SSRR:
283 		case IPOPT_LSRR:
284 			ip_printroute(cp, option_len);
285 			break;
286 
287 		case IPOPT_RA:
288 			if (option_len < 4) {
289 				printf(" [bad length %u]", option_len);
290 				break;
291 			}
292                         TCHECK(cp[3]);
293                         if (EXTRACT_16BITS(&cp[2]) != 0)
294                             printf(" value %u", EXTRACT_16BITS(&cp[2]));
295 			break;
296 
297 		case IPOPT_NOP:       /* nothing to print - fall through */
298 		case IPOPT_SECURITY:
299 		default:
300 			break;
301 		}
302 	}
303 	return;
304 
305 trunc:
306 	printf("[|ip]");
307 }
308 
309 #define IP_RES 0x8000
310 
311 static const struct tok ip_frag_values[] = {
312         { IP_MF,        "+" },
313         { IP_DF,        "DF" },
314 	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
315         { 0,            NULL }
316 };
317 
318 struct ip_print_demux_state {
319 	const struct ip *ip;
320 	const u_char *cp;
321 	u_int   len, off;
322 	u_char  nh;
323 	int     advance;
324 };
325 
326 static void
327 ip_print_demux(netdissect_options *ndo,
328 	       struct ip_print_demux_state *ipds)
329 {
330 	struct protoent *proto;
331 	struct cksum_vec vec[1];
332 
333 again:
334 	switch (ipds->nh) {
335 
336 	case IPPROTO_AH:
337 		ipds->nh = *ipds->cp;
338 		ipds->advance = ah_print(ipds->cp);
339 		if (ipds->advance <= 0)
340 			break;
341 		ipds->cp += ipds->advance;
342 		ipds->len -= ipds->advance;
343 		goto again;
344 
345 	case IPPROTO_ESP:
346 	{
347 		int enh, padlen;
348 		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
349 				    (const u_char *)ipds->ip,
350 				    &enh, &padlen);
351 		if (ipds->advance <= 0)
352 			break;
353 		ipds->cp += ipds->advance;
354 		ipds->len -= ipds->advance + padlen;
355 		ipds->nh = enh & 0xff;
356 		goto again;
357 	}
358 
359 	case IPPROTO_IPCOMP:
360 	{
361 		int enh;
362 		ipds->advance = ipcomp_print(ipds->cp, &enh);
363 		if (ipds->advance <= 0)
364 			break;
365 		ipds->cp += ipds->advance;
366 		ipds->len -= ipds->advance;
367 		ipds->nh = enh & 0xff;
368 		goto again;
369 	}
370 
371 	case IPPROTO_SCTP:
372 		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
373 		break;
374 
375 	case IPPROTO_DCCP:
376 		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
377 		break;
378 
379 	case IPPROTO_TCP:
380 		/* pass on the MF bit plus the offset to detect fragments */
381 		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
382 			  ipds->off & (IP_MF|IP_OFFMASK));
383 		break;
384 
385 	case IPPROTO_UDP:
386 		/* pass on the MF bit plus the offset to detect fragments */
387 		udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
388 			  ipds->off & (IP_MF|IP_OFFMASK));
389 		break;
390 
391 	case IPPROTO_ICMP:
392 		/* pass on the MF bit plus the offset to detect fragments */
393 		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
394 			   ipds->off & (IP_MF|IP_OFFMASK));
395 		break;
396 
397 	case IPPROTO_PIGP:
398 		/*
399 		 * XXX - the current IANA protocol number assignments
400 		 * page lists 9 as "any private interior gateway
401 		 * (used by Cisco for their IGRP)" and 88 as
402 		 * "EIGRP" from Cisco.
403 		 *
404 		 * Recent BSD <netinet/in.h> headers define
405 		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
406 		 * We define IP_PROTO_PIGP as 9 and
407 		 * IP_PROTO_EIGRP as 88; those names better
408 		 * match was the current protocol number
409 		 * assignments say.
410 		 */
411 		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
412 		break;
413 
414 	case IPPROTO_EIGRP:
415 		eigrp_print(ipds->cp, ipds->len);
416 		break;
417 
418 	case IPPROTO_ND:
419 		ND_PRINT((ndo, " nd %d", ipds->len));
420 		break;
421 
422 	case IPPROTO_EGP:
423 		egp_print(ipds->cp, ipds->len);
424 		break;
425 
426 	case IPPROTO_OSPF:
427 		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
428 		break;
429 
430 	case IPPROTO_IGMP:
431 		igmp_print(ipds->cp, ipds->len);
432 		break;
433 
434 	case IPPROTO_IPV4:
435 		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
436 		ip_print(ndo, ipds->cp, ipds->len);
437 		if (! vflag) {
438 			ND_PRINT((ndo, " (ipip-proto-4)"));
439 			return;
440 		}
441 		break;
442 
443 #ifdef INET6
444 	case IPPROTO_IPV6:
445 		/* ip6-in-ip encapsulation */
446 		ip6_print(ndo, ipds->cp, ipds->len);
447 		break;
448 #endif /*INET6*/
449 
450 	case IPPROTO_RSVP:
451 		rsvp_print(ipds->cp, ipds->len);
452 		break;
453 
454 	case IPPROTO_GRE:
455 		/* do it */
456 		gre_print(ipds->cp, ipds->len);
457 		break;
458 
459 	case IPPROTO_MOBILE:
460 		mobile_print(ipds->cp, ipds->len);
461 		break;
462 
463 	case IPPROTO_PIM:
464 		vec[0].ptr = ipds->cp;
465 		vec[0].len = ipds->len;
466 		pim_print(ipds->cp, ipds->len, in_cksum(vec, 1));
467 		break;
468 
469 	case IPPROTO_VRRP:
470 		if (packettype == PT_CARP) {
471 			if (vflag)
472 				(void)printf("carp %s > %s: ",
473 					     ipaddr_string(&ipds->ip->ip_src),
474 					     ipaddr_string(&ipds->ip->ip_dst));
475 			carp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
476 		} else {
477 			if (vflag)
478 				(void)printf("vrrp %s > %s: ",
479 					     ipaddr_string(&ipds->ip->ip_src),
480 					     ipaddr_string(&ipds->ip->ip_dst));
481 			vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
482 		}
483 		break;
484 
485 	case IPPROTO_PGM:
486 		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
487 		break;
488 
489 	case IPPROTO_PFSYNC:
490 		pfsync_ip_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
491 		break;
492 
493 	default:
494 		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
495 			ND_PRINT((ndo, " %s", proto->p_name));
496 		else
497 			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
498 		ND_PRINT((ndo, " %d", ipds->len));
499 		break;
500 	}
501 }
502 
503 void
504 ip_print_inner(netdissect_options *ndo,
505 	       const u_char *bp,
506 	       u_int length, u_int nh,
507 	       const u_char *bp2)
508 {
509 	struct ip_print_demux_state  ipd;
510 
511 	ipd.ip = (const struct ip *)bp2;
512 	ipd.cp = bp;
513 	ipd.len  = length;
514 	ipd.off  = 0;
515 	ipd.nh   = nh;
516 	ipd.advance = 0;
517 
518 	ip_print_demux(ndo, &ipd);
519 }
520 
521 
522 /*
523  * print an IP datagram.
524  */
525 void
526 ip_print(netdissect_options *ndo,
527 	 const u_char *bp,
528 	 u_int length)
529 {
530 	struct ip_print_demux_state  ipd;
531 	struct ip_print_demux_state *ipds=&ipd;
532 	const u_char *ipend;
533 	u_int hlen;
534 	struct cksum_vec vec[1];
535 	u_int16_t sum, ip_sum;
536 	struct protoent *proto;
537 
538 	ipds->ip = (const struct ip *)bp;
539 	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
540 	    printf("IP%u ", IP_V(ipds->ip));
541 	    if (IP_V(ipds->ip) == 6)
542 		printf(", wrong link-layer encapsulation");
543 	}
544         else if (!eflag)
545 	    printf("IP ");
546 
547 	if ((u_char *)(ipds->ip + 1) > ndo->ndo_snapend) {
548 		printf("[|ip]");
549 		return;
550 	}
551 	if (length < sizeof (struct ip)) {
552 		(void)printf("truncated-ip %u", length);
553 		return;
554 	}
555 	hlen = IP_HL(ipds->ip) * 4;
556 	if (hlen < sizeof (struct ip)) {
557 		(void)printf("bad-hlen %u", hlen);
558 		return;
559 	}
560 
561 	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
562 	if (length < ipds->len)
563 		(void)printf("truncated-ip - %u bytes missing! ",
564 			ipds->len - length);
565 	if (ipds->len < hlen) {
566 #ifdef GUESS_TSO
567             if (ipds->len) {
568                 (void)printf("bad-len %u", ipds->len);
569                 return;
570             }
571             else {
572                 /* we guess that it is a TSO send */
573                 ipds->len = length;
574             }
575 #else
576             (void)printf("bad-len %u", ipds->len);
577             return;
578 #endif /* GUESS_TSO */
579 	}
580 
581 	/*
582 	 * Cut off the snapshot length to the end of the IP payload.
583 	 */
584 	ipend = bp + ipds->len;
585 	if (ipend < ndo->ndo_snapend)
586 		ndo->ndo_snapend = ipend;
587 
588 	ipds->len -= hlen;
589 
590 	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
591 
592         if (vflag) {
593             (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
594             /* ECN bits */
595             if (ipds->ip->ip_tos & 0x03) {
596                 switch (ipds->ip->ip_tos & 0x03) {
597                 case 1:
598                     (void)printf(",ECT(1)");
599                     break;
600                 case 2:
601                     (void)printf(",ECT(0)");
602                     break;
603                 case 3:
604                     (void)printf(",CE");
605                 }
606             }
607 
608             if (ipds->ip->ip_ttl >= 1)
609                 (void)printf(", ttl %u", ipds->ip->ip_ttl);
610 
611 	    /*
612 	     * for the firewall guys, print id, offset.
613              * On all but the last stick a "+" in the flags portion.
614 	     * For unfragmented datagrams, note the don't fragment flag.
615 	     */
616 
617 	    (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)",
618                          EXTRACT_16BITS(&ipds->ip->ip_id),
619                          (ipds->off & 0x1fff) * 8,
620                          bittok2str(ip_frag_values, "none", ipds->off&0xe000),
621                          tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
622                          ipds->ip->ip_p);
623 
624             (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
625 
626             if ((hlen - sizeof(struct ip)) > 0) {
627                 printf(", options (");
628                 ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
629                 printf(")");
630             }
631 
632 	    if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
633 	        vec[0].ptr = (const u_int8_t *)(void *)ipds->ip;
634 	        vec[0].len = hlen;
635 	        sum = in_cksum(vec, 1);
636 		if (sum != 0) {
637 		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
638 		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
639 			     in_cksum_shouldbe(ip_sum, sum));
640 		}
641 	    }
642 
643             printf(")\n    ");
644 	}
645 
646 	/*
647 	 * If this is fragment zero, hand it to the next higher
648 	 * level protocol.
649 	 */
650 	if ((ipds->off & 0x1fff) == 0) {
651 		ipds->cp = (const u_char *)ipds->ip + hlen;
652 		ipds->nh = ipds->ip->ip_p;
653 
654 		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
655 		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
656 			(void)printf("%s > %s: ",
657 				     ipaddr_string(&ipds->ip->ip_src),
658 				     ipaddr_string(&ipds->ip->ip_dst));
659 		}
660 		ip_print_demux(ndo, ipds);
661 	} else {
662 	    /* Ultra quiet now means that all this stuff should be suppressed */
663 	    if (qflag > 1) return;
664 
665 	    /*
666 	     * if this isn't the first frag, we're missing the
667 	     * next level protocol header.  print the ip addr
668 	     * and the protocol.
669 	     */
670 	    if (ipds->off & 0x1fff) {
671 	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
672 			     ipaddr_string(&ipds->ip->ip_dst));
673 		if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
674 		    (void)printf(" %s", proto->p_name);
675 		else
676 		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
677 	    }
678 	}
679 }
680 
681 void
682 ipN_print(register const u_char *bp, register u_int length)
683 {
684 	struct ip *ip, hdr;
685 
686 	ip = (struct ip *)bp;
687 	if (length < 4) {
688 		(void)printf("truncated-ip %d", length);
689 		return;
690 	}
691 	memcpy (&hdr, (char *)ip, 4);
692 	switch (IP_V(&hdr)) {
693 	case 4:
694 		ip_print (gndo, bp, length);
695 		return;
696 #ifdef INET6
697 	case 6:
698 		ip6_print (gndo, bp, length);
699 		return;
700 #endif
701 	default:
702 		(void)printf("unknown ip %d", IP_V(&hdr));
703 		return;
704 	}
705 }
706 
707 /*
708  * Local Variables:
709  * c-style: whitesmith
710  * c-basic-offset: 8
711  * End:
712  */
713 
714 
715