]> The Tcpdump Group git mirrors - tcpdump/blob - print-ip.c
5fb6cf1a817f1e4cc38d44a8701e88b72787ca5a
[tcpdump] / print-ip.c
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: /tcpdump/master/tcpdump/print-ip.c,v 1.85 2000-07-29 06:06:27 assar Exp $ (LBL)";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <sys/socket.h>
34
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <netinet/ip_var.h>
39 #include <netinet/udp.h>
40 #include <netinet/udp_var.h>
41 #include <netinet/tcp.h>
42
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 u_int tr_rttlqid; /* response ttl and qid */
71 };
72
73 #define TR_GETTTL(x) (int)(((x) >> 24) & 0xff)
74 #define TR_GETQID(x) ((x) & 0x00ffffff)
75
76 /*
77 * Traceroute response format. A traceroute response has a tr_query at the
78 * beginning, followed by one tr_resp for each hop taken.
79 */
80 struct tr_resp {
81 u_int tr_qarr; /* query arrival time */
82 u_int tr_inaddr; /* incoming interface address */
83 u_int tr_outaddr; /* outgoing interface address */
84 u_int tr_rmtaddr; /* parent address in source tree */
85 u_int tr_vifin; /* input packet count on interface */
86 u_int tr_vifout; /* output packet count on interface */
87 u_int tr_pktcnt; /* total incoming packets for src-grp */
88 u_char tr_rproto; /* routing proto deployed on router */
89 u_char tr_fttl; /* ttl required to forward on outvif */
90 u_char tr_smask; /* subnet mask for src addr */
91 u_char tr_rflags; /* forwarding error codes */
92 };
93
94 /* defs within mtrace */
95 #define TR_QUERY 1
96 #define TR_RESP 2
97
98 /* fields for tr_rflags (forwarding error codes) */
99 #define TR_NO_ERR 0
100 #define TR_WRONG_IF 1
101 #define TR_PRUNED 2
102 #define TR_OPRUNED 3
103 #define TR_SCOPED 4
104 #define TR_NO_RTE 5
105 #define TR_NO_FWD 7
106 #define TR_NO_SPACE 0x81
107 #define TR_OLD_ROUTER 0x82
108
109 /* fields for tr_rproto (routing protocol) */
110 #define TR_PROTO_DVMRP 1
111 #define TR_PROTO_MOSPF 2
112 #define TR_PROTO_PIM 3
113 #define TR_PROTO_CBT 4
114
115 static void print_mtrace(register const u_char *bp, register u_int len)
116 {
117 register struct tr_query *tr = (struct tr_query *)(bp + 8);
118
119 printf("mtrace %lu: %s to %s reply-to %s",
120 (u_long)TR_GETQID(ntohl(tr->tr_rttlqid)),
121 ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
122 ipaddr_string(&tr->tr_raddr));
123 if (IN_CLASSD(ntohl(tr->tr_raddr)))
124 printf(" with-ttl %d", TR_GETTTL(ntohl(tr->tr_rttlqid)));
125 }
126
127 static void print_mresp(register const u_char *bp, register u_int len)
128 {
129 register struct tr_query *tr = (struct tr_query *)(bp + 8);
130
131 printf("mresp %lu: %s to %s reply-to %s",
132 (u_long)TR_GETQID(ntohl(tr->tr_rttlqid)),
133 ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
134 ipaddr_string(&tr->tr_raddr));
135 if (IN_CLASSD(ntohl(tr->tr_raddr)))
136 printf(" with-ttl %d", TR_GETTTL(ntohl(tr->tr_rttlqid)));
137 }
138
139 static void
140 igmp_print(register const u_char *bp, register u_int len,
141 register const u_char *bp2)
142 {
143 register const struct ip *ip;
144
145 ip = (const struct ip *)bp2;
146 (void)printf("%s > %s: ",
147 ipaddr_string(&ip->ip_src),
148 ipaddr_string(&ip->ip_dst));
149
150 if (qflag) {
151 (void)printf("igmp");
152 return;
153 }
154
155 TCHECK2(bp[0], 8);
156 switch (bp[0]) {
157 case 0x11:
158 (void)printf("igmp query");
159 if (EXTRACT_32BITS(&bp[4]))
160 (void)printf(" [gaddr %s]", ipaddr_string(&bp[4]));
161 if (len != 8)
162 (void)printf(" [len %d]", len);
163 break;
164 case 0x12:
165 (void)printf("igmp v1 report %s", ipaddr_string(&bp[4]));
166 if (len != 8)
167 (void)printf(" [len %d]", len);
168 break;
169 case 0x16:
170 (void)printf("igmp v2 report %s", ipaddr_string(&bp[4]));
171 break;
172 case 0x17:
173 (void)printf("igmp leave %s", ipaddr_string(&bp[4]));
174 break;
175 case 0x13:
176 (void)printf("igmp dvmrp");
177 if (len < 8)
178 (void)printf(" [len %d]", len);
179 else
180 dvmrp_print(bp, len);
181 break;
182 case 0x14:
183 (void)printf("igmp pimv1");
184 pimv1_print(bp, len);
185 break;
186 case 0x1e:
187 print_mresp(bp, len);
188 break;
189 case 0x1f:
190 print_mtrace(bp, len);
191 break;
192 default:
193 (void)printf("igmp-%d", bp[0]);
194 break;
195 }
196
197 if (vflag && TTEST2(bp[0], len)) {
198 /* Check the IGMP checksum */
199 if (in_cksum((const u_short*)bp, len, 0))
200 printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]));
201 }
202 return;
203 trunc:
204 fputs("[|igmp]", stdout);
205 }
206
207 /*
208 * print the recorded route in an IP RR, LSRR or SSRR option.
209 */
210 static void
211 ip_printroute(const char *type, register const u_char *cp, u_int length)
212 {
213 register u_int ptr = cp[2] - 1;
214 register u_int len;
215
216 printf(" %s{", type);
217 if ((length + 1) & 3)
218 printf(" [bad length %d]", length);
219 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
220 printf(" [bad ptr %d]", cp[2]);
221
222 type = "";
223 for (len = 3; len < length; len += 4) {
224 if (ptr == len)
225 type = "#";
226 printf("%s%s", type, ipaddr_string(&cp[len]));
227 type = " ";
228 }
229 printf("%s}", ptr == len? "#" : "");
230 }
231
232 static void
233 ip_printts(register const u_char *cp, u_int length)
234 {
235 register u_int ptr = cp[2] - 1;
236 register u_int len = 0;
237 int hoplen;
238 char *type;
239
240 printf(" TS{");
241 hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
242 if ((length - 4) & (hoplen-1))
243 printf("[bad length %d]", length);
244 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
245 printf("[bad ptr %d]", cp[2]);
246 switch (cp[3]&0xF) {
247 case IPOPT_TS_TSONLY:
248 printf("TSONLY");
249 break;
250 case IPOPT_TS_TSANDADDR:
251 printf("TS+ADDR");
252 break;
253 /*
254 * prespecified should really be 3, but some ones might send 2
255 * instead, and the IPOPT_TS_PRESPEC constant can apparently
256 * have both values, so we have to hard-code it here.
257 */
258
259 case 2:
260 printf("PRESPEC2.0");
261 break;
262 case 3: /* IPOPT_TS_PRESPEC */
263 printf("PRESPEC");
264 break;
265 default:
266 printf("[bad ts type %d]", cp[3]&0xF);
267 goto done;
268 }
269
270 type = " ";
271 for (len = 4; len < length; len += hoplen) {
272 if (ptr == len)
273 type = " ^ ";
274 printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
275 hoplen!=8 ? "" : ipaddr_string(&cp[len]));
276 type = " ";
277 }
278
279 done:
280 printf("%s", ptr == len ? " ^ " : "");
281
282 if (cp[3]>>4)
283 printf(" [%d hops not recorded]} ", cp[3]>>4);
284 else
285 printf("}");
286 }
287
288 /*
289 * print IP options.
290 */
291 static void
292 ip_optprint(register const u_char *cp, u_int length)
293 {
294 register u_int len;
295
296 for (; length > 0; cp += len, length -= len) {
297 int tt = *cp;
298
299 if (tt == IPOPT_NOP || tt == IPOPT_EOL)
300 len = 1;
301 else {
302 if (&cp[1] >= snapend) {
303 printf("[|ip]");
304 return;
305 }
306 len = cp[1];
307 }
308 if (len <= 0) {
309 printf("[|ip op len %d]", len);
310 return;
311 }
312 if (&cp[1] >= snapend || cp + len > snapend) {
313 printf("[|ip]");
314 return;
315 }
316 switch (tt) {
317
318 case IPOPT_EOL:
319 printf(" EOL");
320 if (length > 1)
321 printf("-%d", length - 1);
322 return;
323
324 case IPOPT_NOP:
325 printf(" NOP");
326 break;
327
328 case IPOPT_TS:
329 ip_printts(cp, len);
330 break;
331
332 #ifndef IPOPT_SECURITY
333 #define IPOPT_SECURITY 130
334 #endif /* IPOPT_SECURITY */
335 case IPOPT_SECURITY:
336 printf(" SECURITY{%d}", len);
337 break;
338
339 case IPOPT_RR:
340 ip_printroute("RR", cp, len);
341 break;
342
343 case IPOPT_SSRR:
344 ip_printroute("SSRR", cp, len);
345 break;
346
347 case IPOPT_LSRR:
348 ip_printroute("LSRR", cp, len);
349 break;
350
351 #ifndef IPOPT_RA
352 #define IPOPT_RA 148 /* router alert */
353 #endif
354 case IPOPT_RA:
355 printf(" RA");
356 if (len != 4)
357 printf("{%d}", len);
358 else if (cp[2] || cp[3])
359 printf("%d.%d", cp[2], cp[3]);
360 break;
361
362 default:
363 printf(" IPOPT-%d{%d}", cp[0], len);
364 break;
365 }
366 }
367 }
368
369 /*
370 * compute an IP header checksum.
371 * don't modifiy the packet.
372 */
373 u_short
374 in_cksum(const u_short *addr, register int len, u_short csum)
375 {
376 int nleft = len;
377 const u_short *w = addr;
378 u_short answer;
379 int sum = csum;
380
381 /*
382 * Our algorithm is simple, using a 32 bit accumulator (sum),
383 * we add sequential 16 bit words to it, and at the end, fold
384 * back all the carry bits from the top 16 bits into the lower
385 * 16 bits.
386 */
387 while (nleft > 1) {
388 sum += *w++;
389 nleft -= 2;
390 }
391 if (nleft == 1)
392 sum += htons(*(u_char *)w<<8);
393
394 /*
395 * add back carry outs from top 16 bits to low 16 bits
396 */
397 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
398 sum += (sum >> 16); /* add carry */
399 answer = ~sum; /* truncate to 16 bits */
400 return (answer);
401 }
402
403 /*
404 * print an IP datagram.
405 */
406 void
407 ip_print(register const u_char *bp, register u_int length)
408 {
409 register const struct ip *ip;
410 register u_int hlen, len, len0, off;
411 register const u_char *cp;
412 u_char nh;
413 int advance;
414
415 ip = (const struct ip *)bp;
416 #ifdef LBL_ALIGN
417 /*
418 * If the IP header is not aligned, copy into abuf.
419 * This will never happen with BPF. It does happen raw packet
420 * dumps from -r.
421 */
422 if ((long)ip & 3) {
423 static u_char *abuf = NULL;
424 static int didwarn = 0;
425
426 if (abuf == NULL) {
427 abuf = (u_char *)malloc(snaplen);
428 if (abuf == NULL)
429 error("ip_print: malloc");
430 }
431 memcpy((char *)abuf, (char *)ip, min(length, snaplen));
432 snapend += abuf - (u_char *)ip;
433 packetp = abuf;
434 ip = (struct ip *)abuf;
435 /* We really want libpcap to give us aligned packets */
436 if (!didwarn) {
437 warning("compensating for unaligned libpcap packets");
438 ++didwarn;
439 }
440 }
441 #endif
442 if ((u_char *)(ip + 1) > snapend) {
443 printf("[|ip]");
444 return;
445 }
446 if (length < sizeof (struct ip)) {
447 (void)printf("truncated-ip %d", length);
448 return;
449 }
450 hlen = ip->ip_hl * 4;
451 if (hlen < sizeof (struct ip)) {
452 (void)printf("bad-hlen %d", hlen);
453 return;
454 }
455
456 len = ntohs(ip->ip_len);
457 if (length < len)
458 (void)printf("truncated-ip - %d bytes missing!",
459 len - length);
460 len -= hlen;
461 len0 = len;
462
463 /*
464 * If this is fragment zero, hand it to the next higher
465 * level protocol.
466 */
467 off = ntohs(ip->ip_off);
468 if ((off & 0x1fff) == 0) {
469 cp = (const u_char *)ip + hlen;
470 nh = ip->ip_p;
471
472 if (nh != IPPROTO_TCP && nh != IPPROTO_UDP) {
473 (void)printf("%s > %s: ", ipaddr_string(&ip->ip_src),
474 ipaddr_string(&ip->ip_dst));
475 }
476 again:
477 switch (nh) {
478
479 #ifndef IPPROTO_AH
480 #define IPPROTO_AH 51
481 #endif
482 case IPPROTO_AH:
483 nh = *cp;
484 advance = ah_print(cp, (const u_char *)ip);
485 cp += advance;
486 len -= advance;
487 goto again;
488
489 #ifndef IPPROTO_ESP
490 #define IPPROTO_ESP 50
491 #endif
492 case IPPROTO_ESP:
493 {
494 int enh;
495 advance = esp_print(cp, (const u_char *)ip, &enh);
496 cp += advance;
497 len -= advance;
498 if (enh < 0)
499 break;
500 nh = enh & 0xff;
501 goto again;
502 }
503
504 #ifndef IPPROTO_IPCOMP
505 #define IPPROTO_IPCOMP 108
506 #endif
507 case IPPROTO_IPCOMP:
508 {
509 int enh;
510 advance = ipcomp_print(cp, (const u_char *)ip, &enh);
511 cp += advance;
512 len -= advance;
513 if (enh < 0)
514 break;
515 nh = enh & 0xff;
516 goto again;
517 }
518
519 case IPPROTO_TCP:
520 tcp_print(cp, len, (const u_char *)ip);
521 break;
522
523 case IPPROTO_UDP:
524 udp_print(cp, len, (const u_char *)ip);
525 break;
526
527 case IPPROTO_ICMP:
528 icmp_print(cp, len, (const u_char *)ip);
529 break;
530
531 #ifndef IPPROTO_IGRP
532 #define IPPROTO_IGRP 9
533 #endif
534 case IPPROTO_IGRP:
535 igrp_print(cp, len, (const u_char *)ip);
536 break;
537
538 case IPPROTO_ND:
539 #if 0
540 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
541 ipaddr_string(&ip->ip_dst));
542 #endif
543 (void)printf(" nd %d", len);
544 break;
545
546 case IPPROTO_EGP:
547 egp_print(cp, len, (const u_char *)ip);
548 break;
549
550 #ifndef IPPROTO_OSPF
551 #define IPPROTO_OSPF 89
552 #endif
553 case IPPROTO_OSPF:
554 ospf_print(cp, len, (const u_char *)ip);
555 break;
556
557 #ifndef IPPROTO_IGMP
558 #define IPPROTO_IGMP 2
559 #endif
560 case IPPROTO_IGMP:
561 igmp_print(cp, len, (const u_char *)ip);
562 break;
563
564 case 4:
565 /* DVMRP multicast tunnel (ip-in-ip encapsulation) */
566 #if 0
567 if (vflag)
568 (void)printf("%s > %s: ",
569 ipaddr_string(&ip->ip_src),
570 ipaddr_string(&ip->ip_dst));
571 #endif
572 ip_print(cp, len);
573 if (! vflag) {
574 printf(" (ipip)");
575 return;
576 }
577 break;
578
579 #ifdef INET6
580 #ifndef IP6PROTO_ENCAP
581 #define IP6PROTO_ENCAP 41
582 #endif
583 case IP6PROTO_ENCAP:
584 /* ip6-in-ip encapsulation */
585 #if 0
586 if (vflag)
587 (void)printf("%s > %s: ",
588 ipaddr_string(&ip->ip_src),
589 ipaddr_string(&ip->ip_dst));
590 #endif
591 ip6_print(cp, len);
592 if (! vflag) {
593 printf(" (encap)");
594 return;
595 }
596 break;
597 #endif /*INET6*/
598
599
600 #ifndef IPPROTO_GRE
601 #define IPPROTO_GRE 47
602 #endif
603 case IPPROTO_GRE:
604 if (vflag)
605 (void)printf("gre %s > %s: ",
606 ipaddr_string(&ip->ip_src),
607 ipaddr_string(&ip->ip_dst));
608 /* do it */
609 gre_print(cp, len);
610 if (! vflag) {
611 printf(" (gre encap)");
612 return;
613 }
614 break;
615
616 #ifndef IPPROTO_MOBILE
617 #define IPPROTO_MOBILE 55
618 #endif
619 case IPPROTO_MOBILE:
620 if (vflag)
621 (void)printf("mobile %s > %s: ",
622 ipaddr_string(&ip->ip_src),
623 ipaddr_string(&ip->ip_dst));
624 mobile_print(cp, len);
625 if (! vflag) {
626 printf(" (mobile encap)");
627 return;
628 }
629 break;
630
631 #ifndef IPPROTO_PIM
632 #define IPPROTO_PIM 103
633 #endif
634 case IPPROTO_PIM:
635 pim_print(cp, len);
636 break;
637
638 #ifndef IPPROTO_VRRP
639 #define IPPROTO_VRRP 112
640 #endif
641 case IPPROTO_VRRP:
642 vrrp_print(cp, len, ip->ip_ttl);
643 break;
644
645 default:
646 #if 0
647 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
648 ipaddr_string(&ip->ip_dst));
649 #endif
650 (void)printf(" ip-proto-%d %d", nh, len);
651 break;
652 }
653 }
654
655 /* Ultra quiet now means that all this stuff should be suppressed */
656 /* res 3-Nov-98 */
657 if (qflag > 1) return;
658
659
660 /*
661 * for fragmented datagrams, print id:size@offset. On all
662 * but the last stick a "+". For unfragmented datagrams, note
663 * the don't fragment flag.
664 */
665 len = len0; /* get the original length */
666 if (off & 0x3fff) {
667 /*
668 * if this isn't the first frag, we're missing the
669 * next level protocol header. print the ip addr.
670 */
671 if (off & 0x1fff)
672 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
673 ipaddr_string(&ip->ip_dst));
674 #ifndef IP_MF
675 #define IP_MF 0x2000
676 #endif /* IP_MF */
677 #ifndef IP_DF
678 #define IP_DF 0x4000
679 #endif /* IP_DF */
680 (void)printf(" (frag %d:%u@%d%s)", ntohs(ip->ip_id), len,
681 (off & 0x1fff) * 8,
682 (off & IP_MF)? "+" : "");
683
684 } else if (off & IP_DF)
685 (void)printf(" (DF)");
686
687 if (ip->ip_tos) {
688 (void)printf(" [tos 0x%x", (int)ip->ip_tos);
689 /* ECN bits */
690 if (ip->ip_tos&0x02) {
691 (void)printf(",ECT");
692 if (ip->ip_tos&0x01)
693 (void)printf(",CE");
694 }
695 (void)printf("] ");
696 }
697
698 if (ip->ip_ttl <= 1)
699 (void)printf(" [ttl %d]", (int)ip->ip_ttl);
700
701 if (vflag) {
702 int sum;
703 char *sep = "";
704
705 printf(" (");
706 if (ip->ip_ttl > 1) {
707 (void)printf("%sttl %d", sep, (int)ip->ip_ttl);
708 sep = ", ";
709 }
710 if ((off & 0x3fff) == 0) {
711 (void)printf("%sid %d", sep, (int)ntohs(ip->ip_id));
712 sep = ", ";
713 }
714 (void)printf("%slen %d", sep, (int)ntohs(ip->ip_len));
715 sep = ", ";
716 if ((u_char *)ip + hlen <= snapend) {
717 sum = in_cksum((const u_short *)ip, hlen, 0);
718 if (sum != 0) {
719 (void)printf("%sbad cksum %x!", sep,
720 ntohs(ip->ip_sum));
721 sep = ", ";
722 }
723 }
724 if ((hlen -= sizeof(struct ip)) > 0) {
725 (void)printf("%soptlen=%d", sep, hlen);
726 ip_optprint((u_char *)(ip + 1), hlen);
727 }
728 printf(")");
729 }
730 }
731
732 void
733 ipN_print(register const u_char *bp, register u_int length)
734 {
735 struct ip *ip, hdr;
736
737 ip = (struct ip *)bp;
738 if (length < 4) {
739 (void)printf("truncated-ip %d", length);
740 return;
741 }
742 memcpy (&hdr, (char *)ip, 4);
743 switch (hdr.ip_v) {
744 case 4:
745 ip_print (bp, length);
746 return;
747 #ifdef INET6
748 case 6:
749 ip6_print (bp, length);
750 return;
751 #endif
752 default:
753 (void)printf("unknown ip %d", hdr.ip_v);
754 return;
755 }
756 }