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