]> CyberLeo.Net >> Repos - FreeBSD/releng/9.1.git/blob - contrib/tcpdump/print-ip.c
MFC r232197 (by phk):
[FreeBSD/releng/9.1.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         default:
487                 if ((proto = getprotobynumber(ipds->nh)) != NULL)
488                         ND_PRINT((ndo, " %s", proto->p_name));
489                 else
490                         ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
491                 ND_PRINT((ndo, " %d", ipds->len));
492                 break;
493         }
494 }
495                
496 void
497 ip_print_inner(netdissect_options *ndo,
498                const u_char *bp,
499                u_int length, u_int nh,
500                const u_char *bp2)
501 {
502         struct ip_print_demux_state  ipd;
503
504         ipd.ip = (const struct ip *)bp2;
505         ipd.cp = bp;
506         ipd.len  = length;
507         ipd.off  = 0;
508         ipd.nh   = nh;
509         ipd.advance = 0;
510
511         ip_print_demux(ndo, &ipd);
512 }
513
514
515 /*
516  * print an IP datagram.
517  */
518 void
519 ip_print(netdissect_options *ndo,
520          const u_char *bp,
521          u_int length)
522 {
523         struct ip_print_demux_state  ipd;
524         struct ip_print_demux_state *ipds=&ipd;
525         const u_char *ipend;
526         u_int hlen;
527         struct cksum_vec vec[1];
528         u_int16_t sum, ip_sum;
529         struct protoent *proto;
530
531         ipds->ip = (const struct ip *)bp;
532         if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
533             printf("IP%u ", IP_V(ipds->ip));
534             if (IP_V(ipds->ip) == 6)
535                 printf(", wrong link-layer encapsulation");
536         }
537         else if (!eflag)
538             printf("IP ");
539
540         if ((u_char *)(ipds->ip + 1) > ndo->ndo_snapend) {
541                 printf("[|ip]");
542                 return;
543         }
544         if (length < sizeof (struct ip)) {
545                 (void)printf("truncated-ip %u", length);
546                 return;
547         }
548         hlen = IP_HL(ipds->ip) * 4;
549         if (hlen < sizeof (struct ip)) {
550                 (void)printf("bad-hlen %u", hlen);
551                 return;
552         }
553
554         ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
555         if (length < ipds->len)
556                 (void)printf("truncated-ip - %u bytes missing! ",
557                         ipds->len - length);
558         if (ipds->len < hlen) {
559 #ifdef GUESS_TSO
560             if (ipds->len) {
561                 (void)printf("bad-len %u", ipds->len);
562                 return;
563             }
564             else {
565                 /* we guess that it is a TSO send */
566                 ipds->len = length;
567             }
568 #else
569             (void)printf("bad-len %u", ipds->len);
570             return;
571 #endif /* GUESS_TSO */
572         }
573
574         /*
575          * Cut off the snapshot length to the end of the IP payload.
576          */
577         ipend = bp + ipds->len;
578         if (ipend < ndo->ndo_snapend)
579                 ndo->ndo_snapend = ipend;
580
581         ipds->len -= hlen;
582
583         ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
584
585         if (vflag) {
586             (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
587             /* ECN bits */
588             if (ipds->ip->ip_tos & 0x03) {
589                 switch (ipds->ip->ip_tos & 0x03) {
590                 case 1:
591                     (void)printf(",ECT(1)");
592                     break;
593                 case 2:
594                     (void)printf(",ECT(0)");
595                     break;
596                 case 3:
597                     (void)printf(",CE");
598                 }
599             }
600
601             if (ipds->ip->ip_ttl >= 1)
602                 (void)printf(", ttl %u", ipds->ip->ip_ttl);    
603
604             /*
605              * for the firewall guys, print id, offset.
606              * On all but the last stick a "+" in the flags portion.
607              * For unfragmented datagrams, note the don't fragment flag.
608              */
609
610             (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)",
611                          EXTRACT_16BITS(&ipds->ip->ip_id),
612                          (ipds->off & 0x1fff) * 8,
613                          bittok2str(ip_frag_values, "none", ipds->off&0xe000),
614                          tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
615                          ipds->ip->ip_p);
616
617             (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
618
619             if ((hlen - sizeof(struct ip)) > 0) {
620                 printf(", options (");
621                 ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
622                 printf(")");
623             }
624
625             if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
626                 vec[0].ptr = (const u_int8_t *)(void *)ipds->ip;
627                 vec[0].len = hlen;
628                 sum = in_cksum(vec, 1);
629                 if (sum != 0) {
630                     ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
631                     (void)printf(", bad cksum %x (->%x)!", ip_sum,
632                              in_cksum_shouldbe(ip_sum, sum));
633                 }
634             }
635
636             printf(")\n    ");
637         }
638
639         /*
640          * If this is fragment zero, hand it to the next higher
641          * level protocol.
642          */
643         if ((ipds->off & 0x1fff) == 0) {
644                 ipds->cp = (const u_char *)ipds->ip + hlen;
645                 ipds->nh = ipds->ip->ip_p;
646
647                 if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
648                     ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
649                         (void)printf("%s > %s: ",
650                                      ipaddr_string(&ipds->ip->ip_src),
651                                      ipaddr_string(&ipds->ip->ip_dst));
652                 }
653                 ip_print_demux(ndo, ipds);
654         } else {
655             /* Ultra quiet now means that all this stuff should be suppressed */
656             if (qflag > 1) return;
657
658             /*
659              * if this isn't the first frag, we're missing the
660              * next level protocol header.  print the ip addr
661              * and the protocol.
662              */
663             if (ipds->off & 0x1fff) {
664                 (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
665                              ipaddr_string(&ipds->ip->ip_dst));
666                 if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
667                     (void)printf(" %s", proto->p_name);
668                 else
669                     (void)printf(" ip-proto-%d", ipds->ip->ip_p);
670             } 
671         }
672 }
673
674 void
675 ipN_print(register const u_char *bp, register u_int length)
676 {
677         struct ip *ip, hdr;
678
679         ip = (struct ip *)bp;
680         if (length < 4) {
681                 (void)printf("truncated-ip %d", length);
682                 return;
683         }
684         memcpy (&hdr, (char *)ip, 4);
685         switch (IP_V(&hdr)) {
686         case 4:
687                 ip_print (gndo, bp, length);
688                 return;
689 #ifdef INET6
690         case 6:
691                 ip6_print (gndo, bp, length);
692                 return;
693 #endif
694         default:
695                 (void)printf("unknown ip %d", IP_V(&hdr));
696                 return;
697         }
698 }
699
700 /*
701  * Local Variables:
702  * c-style: whitesmith
703  * c-basic-offset: 8
704  * End:
705  */
706
707