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