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