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