xref: /freebsd/contrib/tcpdump/print-ip.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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 #ifndef lint
23 static const char rcsid[] =
24     "@(#) $Header: print-ip.c,v 1.66 97/05/28 12:51:43 leres Exp $ (LBL)";
25 #endif
26 
27 #include <sys/param.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30 
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <netinet/ip_var.h>
35 #include <netinet/udp.h>
36 #include <netinet/udp_var.h>
37 #include <netinet/tcp.h>
38 #include <netinet/tcpip.h>
39 
40 #ifdef HAVE_MALLOC_H
41 #include <malloc.h>
42 #endif
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include "addrtoname.h"
49 #include "interface.h"
50 #include "extract.h"			/* must come after interface.h */
51 
52 /* Compatibility */
53 #ifndef	IPPROTO_ND
54 #define	IPPROTO_ND	77
55 #endif
56 
57 #ifndef IN_CLASSD
58 #define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000)
59 #endif
60 
61 /* (following from ipmulti/mrouted/prune.h) */
62 
63 /*
64  * The packet format for a traceroute request.
65  */
66 struct tr_query {
67 	u_int  tr_src;			/* traceroute source */
68 	u_int  tr_dst;			/* traceroute destination */
69 	u_int  tr_raddr;		/* traceroute response address */
70 #ifdef WORDS_BIGENDIAN
71 	struct {
72 		u_int   ttl : 8;	/* traceroute response ttl */
73 		u_int   qid : 24;	/* traceroute query id */
74 	} q;
75 #else
76 	struct {
77 		u_int	qid : 24;	/* traceroute query id */
78 		u_int	ttl : 8;	/* traceroute response ttl */
79 	} q;
80 #endif
81 };
82 
83 #define tr_rttl q.ttl
84 #define tr_qid  q.qid
85 
86 /*
87  * Traceroute response format.  A traceroute response has a tr_query at the
88  * beginning, followed by one tr_resp for each hop taken.
89  */
90 struct tr_resp {
91 	u_int tr_qarr;			/* query arrival time */
92 	u_int tr_inaddr;		/* incoming interface address */
93 	u_int tr_outaddr;		/* outgoing interface address */
94 	u_int tr_rmtaddr;		/* parent address in source tree */
95 	u_int tr_vifin;			/* input packet count on interface */
96 	u_int tr_vifout;		/* output packet count on interface */
97 	u_int tr_pktcnt;		/* total incoming packets for src-grp */
98 	u_char  tr_rproto;		/* routing proto deployed on router */
99 	u_char  tr_fttl;		/* ttl required to forward on outvif */
100 	u_char  tr_smask;		/* subnet mask for src addr */
101 	u_char  tr_rflags;		/* forwarding error codes */
102 };
103 
104 /* defs within mtrace */
105 #define TR_QUERY 1
106 #define TR_RESP	2
107 
108 /* fields for tr_rflags (forwarding error codes) */
109 #define TR_NO_ERR	0
110 #define TR_WRONG_IF	1
111 #define TR_PRUNED	2
112 #define TR_OPRUNED	3
113 #define TR_SCOPED	4
114 #define TR_NO_RTE	5
115 #define TR_NO_FWD	7
116 #define TR_NO_SPACE	0x81
117 #define TR_OLD_ROUTER	0x82
118 
119 /* fields for tr_rproto (routing protocol) */
120 #define TR_PROTO_DVMRP	1
121 #define TR_PROTO_MOSPF	2
122 #define TR_PROTO_PIM	3
123 #define TR_PROTO_CBT	4
124 
125 static void print_mtrace(register const u_char *bp, register u_int len)
126 {
127 	register struct tr_query *tr = (struct tr_query *)(bp + 8);
128 
129 	printf("mtrace %d: %s to %s reply-to %s", tr->tr_qid,
130 		ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
131 		ipaddr_string(&tr->tr_raddr));
132 	if (IN_CLASSD(ntohl(tr->tr_raddr)))
133 		printf(" with-ttl %d", tr->tr_rttl);
134 }
135 
136 static void print_mresp(register const u_char *bp, register u_int len)
137 {
138 	register struct tr_query *tr = (struct tr_query *)(bp + 8);
139 
140 	printf("mresp %d: %s to %s reply-to %s", tr->tr_qid,
141 		ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
142 		ipaddr_string(&tr->tr_raddr));
143 	if (IN_CLASSD(ntohl(tr->tr_raddr)))
144 		printf(" with-ttl %d", tr->tr_rttl);
145 }
146 
147 static void
148 igmp_print(register const u_char *bp, register u_int len,
149 	   register const u_char *bp2)
150 {
151 	register const struct ip *ip;
152 
153 	ip = (const struct ip *)bp2;
154         (void)printf("%s > %s: ",
155 		ipaddr_string(&ip->ip_src),
156 		ipaddr_string(&ip->ip_dst));
157 
158 	TCHECK2(bp[0], 8);
159 	switch (bp[0]) {
160 	case 0x11:
161 		(void)printf("igmp %s query", bp[1] ? "v2" : "v1");
162 		if (bp[1] && bp[1] != 100)
163 			(void)printf(" [intvl %d]", bp[1]);
164 		if (*(int *)&bp[4])
165 			(void)printf(" [gaddr %s]", ipaddr_string(&bp[4]));
166 		if (len != 8)
167 			(void)printf(" [len %d]", len);
168 		break;
169 	case 0x12:
170 	case 0x16:
171 		(void)printf("igmp %s report %s",
172 			     (bp[0] & 0x0f) == 6 ? "v2" : "v1",
173 			     ipaddr_string(&bp[4]));
174 		if (len != 8)
175 			(void)printf(" [len %d]", len);
176 		if (bp[1])
177 			(void)printf(" [b1=0x%x]", bp[1]);
178 		break;
179 	case 0x17:
180 		(void)printf("igmp leave %s", ipaddr_string(&bp[4]));
181 		if (len != 8)
182 			(void)printf(" [len %d]", len);
183 		if (bp[1])
184 			(void)printf(" [b1=0x%x]", bp[1]);
185 		break;
186 	case 0x13:
187 		(void)printf("igmp dvmrp");
188 		if (len < 8)
189 			(void)printf(" [len %d]", len);
190 		else
191 			dvmrp_print(bp, len);
192 		break;
193 	case 0x14:
194 		(void)printf("igmp pim");
195 		pim_print(bp, len);
196   		break;
197 	case 0x1e:
198 		print_mresp(bp, len);
199 		break;
200 	case 0x1f:
201 		print_mtrace(bp, len);
202 		break;
203 	default:
204 		(void)printf("igmp-%d", bp[0] & 0xf);
205 		if (bp[1])
206 			(void)printf(" [b1=0x%02x]", bp[1]);
207 		break;
208 	}
209 
210 	TCHECK2(bp[0], len);
211 	if (vflag) {
212 		/* Check the IGMP checksum */
213 		u_int32_t sum = 0;
214 		int count;
215 		const u_short *sp = (u_short *)bp;
216 
217 		for (count = len / 2; --count >= 0; )
218 			sum += *sp++;
219 		if (len & 1)
220 			sum += ntohs(*(u_char *) sp << 8);
221 		while (sum >> 16)
222 			sum = (sum & 0xffff) + (sum >> 16);
223 		sum = 0xffff & ~sum;
224 		if (sum != 0)
225 			printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]));
226 	}
227 	return;
228 trunc:
229 	fputs("[|igmp]", stdout);
230 }
231 
232 /*
233  * print the recorded route in an IP RR, LSRR or SSRR option.
234  */
235 static void
236 ip_printroute(const char *type, register const u_char *cp, u_int length)
237 {
238 	register u_int ptr = cp[2] - 1;
239 	register u_int len;
240 
241 	printf(" %s{", type);
242 	if ((length + 1) & 3)
243 		printf(" [bad length %d]", length);
244 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
245 		printf(" [bad ptr %d]", cp[2]);
246 
247 	type = "";
248 	for (len = 3; len < length; len += 4) {
249 		if (ptr == len)
250 			type = "#";
251 		printf("%s%s", type, ipaddr_string(&cp[len]));
252 		type = " ";
253 	}
254 	printf("%s}", ptr == len? "#" : "");
255 }
256 
257 /*
258  * print IP options.
259  */
260 static void
261 ip_optprint(register const u_char *cp, u_int length)
262 {
263 	register u_int len;
264 
265 	for (; length > 0; cp += len, length -= len) {
266 		int tt = *cp;
267 
268 		len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
269 		if (len <= 0) {
270 			printf("[|ip op len %d]", len);
271 			return;
272 		}
273 		if (&cp[1] >= snapend || cp + len > snapend) {
274 			printf("[|ip]");
275 			return;
276 		}
277 		switch (tt) {
278 
279 		case IPOPT_EOL:
280 			printf(" EOL");
281 			if (length > 1)
282 				printf("-%d", length - 1);
283 			return;
284 
285 		case IPOPT_NOP:
286 			printf(" NOP");
287 			break;
288 
289 		case IPOPT_TS:
290 			printf(" TS{%d}", len);
291 			break;
292 
293 		case IPOPT_SECURITY:
294 			printf(" SECURITY{%d}", len);
295 			break;
296 
297 		case IPOPT_RR:
298 			printf(" RR{%d}=", len);
299 			ip_printroute("RR", cp, len);
300 			break;
301 
302 		case IPOPT_SSRR:
303 			ip_printroute("SSRR", cp, len);
304 			break;
305 
306 		case IPOPT_LSRR:
307 			ip_printroute("LSRR", cp, len);
308 			break;
309 
310 		case IPOPT_RA:
311 			printf(" RA{%d}", len);
312 			if (cp[2] != 0 || cp[3] != 0)
313 				printf(" [b23=0x04%x]", cp[2] << 8 | cp[3]);
314 			break;
315 
316 		default:
317 			printf(" IPOPT-%d{%d}", cp[0], len);
318 			break;
319 		}
320 	}
321 }
322 
323 /*
324  * compute an IP header checksum.
325  * don't modifiy the packet.
326  */
327 static int
328 in_cksum(const struct ip *ip)
329 {
330 	register const u_short *sp = (u_short *)ip;
331 	register u_int32_t sum = 0;
332 	register int count;
333 
334 	/*
335 	 * No need for endian conversions.
336 	 */
337 	for (count = ip->ip_hl * 2; --count >= 0; )
338 		sum += *sp++;
339 	while (sum > 0xffff)
340 		sum = (sum & 0xffff) + (sum >> 16);
341 	sum = ~sum & 0xffff;
342 
343 	return (sum);
344 }
345 
346 /*
347  * print an IP datagram.
348  */
349 void
350 ip_print(register const u_char *bp, register u_int length)
351 {
352 	register const struct ip *ip;
353 	register u_int hlen, len, off;
354 	register const u_char *cp;
355 
356 	ip = (const struct ip *)bp;
357 #ifdef LBL_ALIGN
358 	/*
359 	 * If the IP header is not aligned, copy into abuf.
360 	 * This will never happen with BPF.  It does happen raw packet
361 	 * dumps from -r.
362 	 */
363 	if ((long)ip & 3) {
364 		static u_char *abuf = NULL;
365 		static int didwarn = 0;
366 
367 		if (abuf == NULL) {
368 			abuf = (u_char *)malloc(snaplen);
369 			if (abuf == NULL)
370 				error("ip_print: malloc");
371 		}
372 		memcpy((char *)abuf, (char *)ip, min(length, snaplen));
373 		snapend += abuf - (u_char *)ip;
374 		packetp = abuf;
375 		ip = (struct ip *)abuf;
376 		/* We really want libpcap to give us aligned packets */
377 		if (!didwarn) {
378 			warning("compensating for unaligned libpcap packets");
379 			++didwarn;
380 		}
381 	}
382 #endif
383 	if ((u_char *)(ip + 1) > snapend) {
384 		printf("[|ip]");
385 		return;
386 	}
387 	if (length < sizeof (struct ip)) {
388 		(void)printf("truncated-ip %d", length);
389 		return;
390 	}
391 	hlen = ip->ip_hl * 4;
392 
393 	len = ntohs(ip->ip_len);
394 	if (length < len)
395 		(void)printf("truncated-ip - %d bytes missing!",
396 			len - length);
397 	len -= hlen;
398 
399 	/*
400 	 * If this is fragment zero, hand it to the next higher
401 	 * level protocol.
402 	 */
403 	off = ntohs(ip->ip_off);
404 	if ((off & 0x1fff) == 0) {
405 		cp = (const u_char *)ip + hlen;
406 		switch (ip->ip_p) {
407 
408 		case IPPROTO_TCP:
409 			tcp_print(cp, len, (const u_char *)ip);
410 			break;
411 
412 		case IPPROTO_UDP:
413 			udp_print(cp, len, (const u_char *)ip);
414 			break;
415 
416 		case IPPROTO_ICMP:
417 			icmp_print(cp, (const u_char *)ip);
418 			break;
419 
420 #ifndef IPPROTO_IGRP
421 #define IPPROTO_IGRP 9
422 #endif
423 		case IPPROTO_IGRP:
424 			igrp_print(cp, len, (const u_char *)ip);
425 			break;
426 
427 		case IPPROTO_ND:
428 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
429 				ipaddr_string(&ip->ip_dst));
430 			(void)printf(" nd %d", len);
431 			break;
432 
433 		case IPPROTO_EGP:
434 			egp_print(cp, len, (const u_char *)ip);
435 			break;
436 
437 #ifndef IPPROTO_OSPF
438 #define IPPROTO_OSPF 89
439 #endif
440 		case IPPROTO_OSPF:
441 			ospf_print(cp, len, (const u_char *)ip);
442 			break;
443 
444 #ifndef IPPROTO_IGMP
445 #define IPPROTO_IGMP 2
446 #endif
447 		case IPPROTO_IGMP:
448 			igmp_print(cp, len, (const u_char *)ip);
449 			break;
450 
451 		case 4:
452 			/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
453 			if (vflag)
454 				(void)printf("%s > %s: ",
455 					     ipaddr_string(&ip->ip_src),
456 					     ipaddr_string(&ip->ip_dst));
457 			ip_print(cp, len);
458 			if (! vflag) {
459 				printf(" (ipip)");
460 				return;
461 			}
462 			break;
463 
464 #ifndef IPPROTO_GRE
465 #define IPPROTO_GRE 47
466 #endif
467 		case IPPROTO_GRE:
468 			if (vflag)
469 				(void)printf("gre %s > %s: ",
470 					     ipaddr_string(&ip->ip_src),
471 					     ipaddr_string(&ip->ip_dst));
472 			/* do it */
473 			gre_print(cp, len);
474 			if (! vflag) {
475 				printf(" (gre encap)");
476 				return;
477   			}
478   			break;
479 
480 		default:
481 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
482 				ipaddr_string(&ip->ip_dst));
483 			(void)printf(" ip-proto-%d %d", ip->ip_p, len);
484 			break;
485 		}
486 	}
487 	/*
488 	 * for fragmented datagrams, print id:size@offset.  On all
489 	 * but the last stick a "+".  For unfragmented datagrams, note
490 	 * the don't fragment flag.
491 	 */
492 	if (off & 0x3fff) {
493 		/*
494 		 * if this isn't the first frag, we're missing the
495 		 * next level protocol header.  print the ip addr.
496 		 */
497 		if (off & 0x1fff)
498 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
499 				      ipaddr_string(&ip->ip_dst));
500 		(void)printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), len,
501 			(off & 0x1fff) * 8,
502 			(off & IP_MF)? "+" : "");
503 	} else if (off & IP_DF)
504 		(void)printf(" (DF)");
505 
506 	if (ip->ip_tos)
507 		(void)printf(" [tos 0x%x]", (int)ip->ip_tos);
508 	if (ip->ip_ttl <= 1)
509 		(void)printf(" [ttl %d]", (int)ip->ip_ttl);
510 
511 	if (vflag) {
512 		int sum;
513 		char *sep = "";
514 
515 		printf(" (");
516 		if (ip->ip_ttl > 1) {
517 			(void)printf("%sttl %d", sep, (int)ip->ip_ttl);
518 			sep = ", ";
519 		}
520 		if ((off & 0x3fff) == 0) {
521 			(void)printf("%sid %d", sep, (int)ntohs(ip->ip_id));
522 			sep = ", ";
523 		}
524 		if ((u_char *)ip + hlen <= snapend) {
525 			sum = in_cksum(ip);
526 			if (sum != 0) {
527 				(void)printf("%sbad cksum %x!", sep,
528 					     ntohs(ip->ip_sum));
529 				sep = ", ";
530 			}
531 		}
532 		if ((hlen -= sizeof(struct ip)) > 0) {
533 			(void)printf("%soptlen=%d", sep, hlen);
534 			ip_optprint((u_char *)(ip + 1), hlen);
535 		}
536 		printf(")");
537 	}
538 }
539