Commit | Line | Data |
---|---|---|
c8cf0f94 PA |
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_ = | |
825e8fa1 | 24 | "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.149.2.9 2007/09/14 01:30:02 guy Exp $ (LBL)"; |
c8cf0f94 PA |
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" }, | |
825e8fa1 | 53 | { IPOPT_RFC1393, "traceroute" }, |
c8cf0f94 PA |
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 | 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 | static void | |
133 | ip_printts(register const u_char *cp, u_int length) | |
134 | { | |
135 | register u_int ptr; | |
136 | register u_int len; | |
137 | int hoplen; | |
138 | const char *type; | |
139 | ||
140 | if (length < 4) { | |
141 | printf("[bad length %u]", length); | |
142 | return; | |
143 | } | |
144 | printf(" TS{"); | |
145 | hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; | |
146 | if ((length - 4) & (hoplen-1)) | |
147 | printf("[bad length %u]", length); | |
148 | ptr = cp[2] - 1; | |
149 | len = 0; | |
150 | if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) | |
151 | printf("[bad ptr %u]", cp[2]); | |
152 | switch (cp[3]&0xF) { | |
153 | case IPOPT_TS_TSONLY: | |
154 | printf("TSONLY"); | |
155 | break; | |
156 | case IPOPT_TS_TSANDADDR: | |
157 | printf("TS+ADDR"); | |
158 | break; | |
159 | /* | |
160 | * prespecified should really be 3, but some ones might send 2 | |
161 | * instead, and the IPOPT_TS_PRESPEC constant can apparently | |
162 | * have both values, so we have to hard-code it here. | |
163 | */ | |
164 | ||
165 | case 2: | |
166 | printf("PRESPEC2.0"); | |
167 | break; | |
168 | case 3: /* IPOPT_TS_PRESPEC */ | |
169 | printf("PRESPEC"); | |
170 | break; | |
171 | default: | |
172 | printf("[bad ts type %d]", cp[3]&0xF); | |
173 | goto done; | |
174 | } | |
175 | ||
176 | type = " "; | |
177 | for (len = 4; len < length; len += hoplen) { | |
178 | if (ptr == len) | |
179 | type = " ^ "; | |
180 | printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), | |
181 | hoplen!=8 ? "" : ipaddr_string(&cp[len])); | |
182 | type = " "; | |
183 | } | |
184 | ||
185 | done: | |
186 | printf("%s", ptr == len ? " ^ " : ""); | |
187 | ||
188 | if (cp[3]>>4) | |
189 | printf(" [%d hops not recorded]} ", cp[3]>>4); | |
190 | else | |
191 | printf("}"); | |
192 | } | |
193 | ||
194 | /* | |
195 | * print IP options. | |
196 | */ | |
197 | static void | |
198 | ip_optprint(register const u_char *cp, u_int length) | |
199 | { | |
200 | register u_int option_len; | |
201 | const char *sep = ""; | |
202 | ||
203 | for (; length > 0; cp += option_len, length -= option_len) { | |
204 | u_int option_code; | |
205 | ||
206 | printf("%s", sep); | |
207 | sep = ","; | |
208 | ||
209 | TCHECK(*cp); | |
210 | option_code = *cp; | |
211 | ||
212 | printf("%s", | |
213 | tok2str(ip_option_values,"unknown %u",option_code)); | |
214 | ||
215 | if (option_code == IPOPT_NOP || | |
216 | option_code == IPOPT_EOL) | |
217 | option_len = 1; | |
218 | ||
219 | else { | |
220 | TCHECK(cp[1]); | |
221 | option_len = cp[1]; | |
222 | if (option_len < 2) { | |
223 | printf(" [bad length %u]", option_len); | |
224 | return; | |
225 | } | |
226 | } | |
227 | ||
228 | if (option_len > length) { | |
229 | printf(" [bad length %u]", option_len); | |
230 | return; | |
231 | } | |
232 | ||
233 | TCHECK2(*cp, option_len); | |
234 | ||
235 | switch (option_code) { | |
236 | case IPOPT_EOL: | |
237 | return; | |
238 | ||
239 | case IPOPT_TS: | |
240 | ip_printts(cp, option_len); | |
241 | break; | |
242 | ||
243 | case IPOPT_RR: /* fall through */ | |
244 | case IPOPT_SSRR: | |
245 | case IPOPT_LSRR: | |
246 | ip_printroute(cp, option_len); | |
247 | break; | |
248 | ||
249 | case IPOPT_RA: | |
250 | if (option_len < 4) { | |
251 | printf(" [bad length %u]", option_len); | |
252 | break; | |
253 | } | |
254 | TCHECK(cp[3]); | |
255 | if (EXTRACT_16BITS(&cp[2]) != 0) | |
256 | printf(" value %u", EXTRACT_16BITS(&cp[2])); | |
257 | break; | |
258 | ||
259 | case IPOPT_NOP: /* nothing to print - fall through */ | |
260 | case IPOPT_SECURITY: | |
261 | default: | |
262 | break; | |
263 | } | |
264 | } | |
265 | return; | |
266 | ||
267 | trunc: | |
268 | printf("[|ip]"); | |
269 | } | |
270 | ||
271 | /* | |
272 | * compute an IP header checksum. | |
273 | * don't modifiy the packet. | |
274 | */ | |
275 | u_short | |
276 | in_cksum(const u_short *addr, register u_int len, int csum) | |
277 | { | |
278 | int nleft = len; | |
279 | const u_short *w = addr; | |
280 | u_short answer; | |
281 | int sum = csum; | |
282 | ||
283 | /* | |
284 | * Our algorithm is simple, using a 32 bit accumulator (sum), | |
285 | * we add sequential 16 bit words to it, and at the end, fold | |
286 | * back all the carry bits from the top 16 bits into the lower | |
287 | * 16 bits. | |
288 | */ | |
289 | while (nleft > 1) { | |
290 | sum += *w++; | |
291 | nleft -= 2; | |
292 | } | |
293 | if (nleft == 1) | |
294 | sum += htons(*(u_char *)w<<8); | |
295 | ||
296 | /* | |
297 | * add back carry outs from top 16 bits to low 16 bits | |
298 | */ | |
299 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | |
300 | sum += (sum >> 16); /* add carry */ | |
301 | answer = ~sum; /* truncate to 16 bits */ | |
302 | return (answer); | |
303 | } | |
304 | ||
305 | /* | |
306 | * Given the host-byte-order value of the checksum field in a packet | |
307 | * header, and the network-byte-order computed checksum of the data | |
308 | * that the checksum covers (including the checksum itself), compute | |
309 | * what the checksum field *should* have been. | |
310 | */ | |
311 | u_int16_t | |
312 | in_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum) | |
313 | { | |
314 | u_int32_t shouldbe; | |
315 | ||
316 | /* | |
317 | * The value that should have gone into the checksum field | |
318 | * is the negative of the value gotten by summing up everything | |
319 | * *but* the checksum field. | |
320 | * | |
321 | * We can compute that by subtracting the value of the checksum | |
322 | * field from the sum of all the data in the packet, and then | |
323 | * computing the negative of that value. | |
324 | * | |
325 | * "sum" is the value of the checksum field, and "computed_sum" | |
326 | * is the negative of the sum of all the data in the packets, | |
327 | * so that's -(-computed_sum - sum), or (sum + computed_sum). | |
328 | * | |
329 | * All the arithmetic in question is one's complement, so the | |
330 | * addition must include an end-around carry; we do this by | |
331 | * doing the arithmetic in 32 bits (with no sign-extension), | |
332 | * and then adding the upper 16 bits of the sum, which contain | |
333 | * the carry, to the lower 16 bits of the sum, and then do it | |
334 | * again in case *that* sum produced a carry. | |
335 | * | |
336 | * As RFC 1071 notes, the checksum can be computed without | |
337 | * byte-swapping the 16-bit words; summing 16-bit words | |
338 | * on a big-endian machine gives a big-endian checksum, which | |
339 | * can be directly stuffed into the big-endian checksum fields | |
340 | * in protocol headers, and summing words on a little-endian | |
341 | * machine gives a little-endian checksum, which must be | |
342 | * byte-swapped before being stuffed into a big-endian checksum | |
343 | * field. | |
344 | * | |
345 | * "computed_sum" is a network-byte-order value, so we must put | |
346 | * it in host byte order before subtracting it from the | |
347 | * host-byte-order value from the header; the adjusted checksum | |
348 | * will be in host byte order, which is what we'll return. | |
349 | */ | |
350 | shouldbe = sum; | |
351 | shouldbe += ntohs(computed_sum); | |
352 | shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); | |
353 | shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); | |
354 | return shouldbe; | |
355 | } | |
356 | ||
357 | #define IP_RES 0x8000 | |
358 | ||
359 | static struct tok ip_frag_values[] = { | |
360 | { IP_MF, "+" }, | |
361 | { IP_DF, "DF" }, | |
362 | { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ | |
363 | { 0, NULL } | |
364 | }; | |
365 | ||
366 | struct ip_print_demux_state { | |
367 | const struct ip *ip; | |
368 | const u_char *cp; | |
369 | u_int len, off; | |
370 | u_char nh; | |
371 | int advance; | |
372 | }; | |
373 | ||
374 | static void | |
375 | ip_print_demux(netdissect_options *ndo, | |
376 | struct ip_print_demux_state *ipds) | |
377 | { | |
378 | struct protoent *proto; | |
379 | ||
380 | again: | |
381 | switch (ipds->nh) { | |
382 | ||
383 | case IPPROTO_AH: | |
384 | ipds->nh = *ipds->cp; | |
385 | ipds->advance = ah_print(ipds->cp); | |
386 | if (ipds->advance <= 0) | |
387 | break; | |
388 | ipds->cp += ipds->advance; | |
389 | ipds->len -= ipds->advance; | |
390 | goto again; | |
391 | ||
392 | case IPPROTO_ESP: | |
393 | { | |
394 | int enh, padlen; | |
395 | ipds->advance = esp_print(ndo, ipds->cp, ipds->len, | |
396 | (const u_char *)ipds->ip, | |
397 | &enh, &padlen); | |
398 | if (ipds->advance <= 0) | |
399 | break; | |
400 | ipds->cp += ipds->advance; | |
401 | ipds->len -= ipds->advance + padlen; | |
402 | ipds->nh = enh & 0xff; | |
403 | goto again; | |
404 | } | |
405 | ||
406 | case IPPROTO_IPCOMP: | |
407 | { | |
408 | int enh; | |
409 | ipds->advance = ipcomp_print(ipds->cp, &enh); | |
410 | if (ipds->advance <= 0) | |
411 | break; | |
412 | ipds->cp += ipds->advance; | |
413 | ipds->len -= ipds->advance; | |
414 | ipds->nh = enh & 0xff; | |
415 | goto again; | |
416 | } | |
417 | ||
418 | case IPPROTO_SCTP: | |
419 | sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); | |
420 | break; | |
421 | ||
422 | case IPPROTO_DCCP: | |
423 | dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); | |
424 | break; | |
425 | ||
426 | case IPPROTO_TCP: | |
427 | /* pass on the MF bit plus the offset to detect fragments */ | |
428 | tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, | |
429 | ipds->off & (IP_MF|IP_OFFMASK)); | |
430 | break; | |
431 | ||
432 | case IPPROTO_UDP: | |
433 | /* pass on the MF bit plus the offset to detect fragments */ | |
434 | udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, | |
435 | ipds->off & (IP_MF|IP_OFFMASK)); | |
436 | break; | |
437 | ||
438 | case IPPROTO_ICMP: | |
439 | /* pass on the MF bit plus the offset to detect fragments */ | |
440 | icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, | |
441 | ipds->off & (IP_MF|IP_OFFMASK)); | |
442 | break; | |
443 | ||
444 | case IPPROTO_PIGP: | |
445 | /* | |
446 | * XXX - the current IANA protocol number assignments | |
447 | * page lists 9 as "any private interior gateway | |
448 | * (used by Cisco for their IGRP)" and 88 as | |
449 | * "EIGRP" from Cisco. | |
450 | * | |
451 | * Recent BSD <netinet/in.h> headers define | |
452 | * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. | |
453 | * We define IP_PROTO_PIGP as 9 and | |
454 | * IP_PROTO_EIGRP as 88; those names better | |
455 | * match was the current protocol number | |
456 | * assignments say. | |
457 | */ | |
458 | igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); | |
459 | break; | |
460 | ||
461 | case IPPROTO_EIGRP: | |
462 | eigrp_print(ipds->cp, ipds->len); | |
463 | break; | |
464 | ||
465 | case IPPROTO_ND: | |
466 | ND_PRINT((ndo, " nd %d", ipds->len)); | |
467 | break; | |
468 | ||
469 | case IPPROTO_EGP: | |
470 | egp_print(ipds->cp, ipds->len); | |
471 | break; | |
472 | ||
473 | case IPPROTO_OSPF: | |
474 | ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); | |
475 | break; | |
476 | ||
477 | case IPPROTO_IGMP: | |
478 | igmp_print(ipds->cp, ipds->len); | |
479 | break; | |
480 | ||
481 | case IPPROTO_IPV4: | |
482 | /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ | |
483 | ip_print(gndo, ipds->cp, ipds->len); | |
484 | if (! vflag) { | |
485 | ND_PRINT((ndo, " (ipip-proto-4)")); | |
486 | return; | |
487 | } | |
488 | break; | |
489 | ||
490 | #ifdef INET6 | |
491 | case IPPROTO_IPV6: | |
492 | /* ip6-in-ip encapsulation */ | |
493 | ip6_print(ipds->cp, ipds->len); | |
494 | break; | |
495 | #endif /*INET6*/ | |
496 | ||
497 | case IPPROTO_RSVP: | |
498 | rsvp_print(ipds->cp, ipds->len); | |
499 | break; | |
500 | ||
501 | case IPPROTO_GRE: | |
502 | /* do it */ | |
503 | gre_print(ipds->cp, ipds->len); | |
504 | break; | |
505 | ||
506 | case IPPROTO_MOBILE: | |
507 | mobile_print(ipds->cp, ipds->len); | |
508 | break; | |
509 | ||
510 | case IPPROTO_PIM: | |
511 | pim_print(ipds->cp, ipds->len); | |
512 | break; | |
513 | ||
514 | case IPPROTO_VRRP: | |
515 | vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl); | |
516 | break; | |
517 | ||
518 | case IPPROTO_PGM: | |
519 | pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); | |
520 | break; | |
521 | ||
522 | default: | |
523 | if ((proto = getprotobynumber(ipds->nh)) != NULL) | |
524 | ND_PRINT((ndo, " %s", proto->p_name)); | |
525 | else | |
526 | ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); | |
527 | ND_PRINT((ndo, " %d", ipds->len)); | |
528 | break; | |
529 | } | |
530 | } | |
531 | ||
532 | void | |
533 | ip_print_inner(netdissect_options *ndo, | |
534 | const u_char *bp, | |
535 | u_int length, u_int nh, | |
536 | const u_char *bp2) | |
537 | { | |
538 | struct ip_print_demux_state ipd; | |
539 | ||
540 | ipd.ip = (const struct ip *)bp2; | |
541 | ipd.cp = bp; | |
542 | ipd.len = length; | |
543 | ipd.off = 0; | |
544 | ipd.nh = nh; | |
545 | ipd.advance = 0; | |
546 | ||
547 | ip_print_demux(ndo, &ipd); | |
548 | } | |
549 | ||
550 | ||
551 | /* | |
552 | * print an IP datagram. | |
553 | */ | |
554 | void | |
555 | ip_print(netdissect_options *ndo, | |
556 | const u_char *bp, | |
557 | u_int length) | |
558 | { | |
559 | struct ip_print_demux_state ipd; | |
560 | struct ip_print_demux_state *ipds=&ipd; | |
561 | const u_char *ipend; | |
562 | u_int hlen; | |
563 | u_int16_t sum, ip_sum; | |
564 | struct protoent *proto; | |
565 | ||
566 | ipds->ip = (const struct ip *)bp; | |
567 | if (IP_V(ipds->ip) != 4) { /* print version if != 4 */ | |
568 | printf("IP%u ", IP_V(ipds->ip)); | |
569 | if (IP_V(ipds->ip) == 6) | |
570 | printf(", wrong link-layer encapsulation"); | |
571 | } | |
572 | else if (!eflag) | |
573 | printf("IP "); | |
574 | ||
575 | if ((u_char *)(ipds->ip + 1) > snapend) { | |
576 | printf("[|ip]"); | |
577 | return; | |
578 | } | |
579 | if (length < sizeof (struct ip)) { | |
580 | (void)printf("truncated-ip %u", length); | |
581 | return; | |
582 | } | |
583 | hlen = IP_HL(ipds->ip) * 4; | |
584 | if (hlen < sizeof (struct ip)) { | |
585 | (void)printf("bad-hlen %u", hlen); | |
586 | return; | |
587 | } | |
588 | ||
589 | ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); | |
590 | if (length < ipds->len) | |
591 | (void)printf("truncated-ip - %u bytes missing! ", | |
592 | ipds->len - length); | |
593 | if (ipds->len < hlen) { | |
594 | #ifdef GUESS_TSO | |
595 | if (ipds->len) { | |
596 | (void)printf("bad-len %u", ipds->len); | |
597 | return; | |
598 | } | |
599 | else { | |
600 | /* we guess that it is a TSO send */ | |
601 | ipds->len = length; | |
602 | } | |
603 | #else | |
604 | (void)printf("bad-len %u", ipds->len); | |
605 | return; | |
606 | #endif /* GUESS_TSO */ | |
607 | } | |
608 | ||
609 | /* | |
610 | * Cut off the snapshot length to the end of the IP payload. | |
611 | */ | |
612 | ipend = bp + ipds->len; | |
613 | if (ipend < snapend) | |
614 | snapend = ipend; | |
615 | ||
616 | ipds->len -= hlen; | |
617 | ||
618 | ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); | |
619 | ||
620 | if (vflag) { | |
621 | (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos); | |
622 | /* ECN bits */ | |
623 | if (ipds->ip->ip_tos & 0x03) { | |
624 | switch (ipds->ip->ip_tos & 0x03) { | |
625 | case 1: | |
626 | (void)printf(",ECT(1)"); | |
627 | break; | |
628 | case 2: | |
629 | (void)printf(",ECT(0)"); | |
630 | break; | |
631 | case 3: | |
632 | (void)printf(",CE"); | |
633 | } | |
634 | } | |
635 | ||
636 | if (ipds->ip->ip_ttl >= 1) | |
66170f0a | 637 | (void)printf(", ttl %u", ipds->ip->ip_ttl); |
c8cf0f94 PA |
638 | |
639 | /* | |
640 | * for the firewall guys, print id, offset. | |
641 | * On all but the last stick a "+" in the flags portion. | |
642 | * For unfragmented datagrams, note the don't fragment flag. | |
643 | */ | |
644 | ||
66170f0a | 645 | (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)", |
c8cf0f94 PA |
646 | EXTRACT_16BITS(&ipds->ip->ip_id), |
647 | (ipds->off & 0x1fff) * 8, | |
66170f0a | 648 | bittok2str(ip_frag_values, "none", ipds->off&0xe000), |
c8cf0f94 PA |
649 | tok2str(ipproto_values,"unknown",ipds->ip->ip_p), |
650 | ipds->ip->ip_p); | |
651 | ||
66170f0a | 652 | (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len)); |
c8cf0f94 PA |
653 | |
654 | if ((hlen - sizeof(struct ip)) > 0) { | |
655 | printf(", options ("); | |
656 | ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); | |
657 | printf(")"); | |
658 | } | |
659 | ||
660 | if ((u_char *)ipds->ip + hlen <= snapend) { | |
661 | sum = in_cksum((const u_short *)ipds->ip, hlen, 0); | |
662 | if (sum != 0) { | |
663 | ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); | |
664 | (void)printf(", bad cksum %x (->%x)!", ip_sum, | |
665 | in_cksum_shouldbe(ip_sum, sum)); | |
666 | } | |
667 | } | |
668 | ||
669 | printf(") "); | |
670 | } | |
671 | ||
672 | /* | |
673 | * If this is fragment zero, hand it to the next higher | |
674 | * level protocol. | |
675 | */ | |
676 | if ((ipds->off & 0x1fff) == 0) { | |
677 | ipds->cp = (const u_char *)ipds->ip + hlen; | |
678 | ipds->nh = ipds->ip->ip_p; | |
679 | ||
680 | if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP && | |
681 | ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) { | |
682 | (void)printf("%s > %s: ", | |
683 | ipaddr_string(&ipds->ip->ip_src), | |
684 | ipaddr_string(&ipds->ip->ip_dst)); | |
685 | } | |
686 | ip_print_demux(ndo, ipds); | |
687 | } else { | |
688 | /* Ultra quiet now means that all this stuff should be suppressed */ | |
689 | if (qflag > 1) return; | |
690 | ||
691 | /* | |
692 | * if this isn't the first frag, we're missing the | |
693 | * next level protocol header. print the ip addr | |
694 | * and the protocol. | |
695 | */ | |
696 | if (ipds->off & 0x1fff) { | |
697 | (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src), | |
698 | ipaddr_string(&ipds->ip->ip_dst)); | |
699 | if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL) | |
700 | (void)printf(" %s", proto->p_name); | |
701 | else | |
702 | (void)printf(" ip-proto-%d", ipds->ip->ip_p); | |
703 | } | |
704 | } | |
705 | } | |
706 | ||
707 | void | |
708 | ipN_print(register const u_char *bp, register u_int length) | |
709 | { | |
710 | struct ip *ip, hdr; | |
711 | ||
712 | ip = (struct ip *)bp; | |
713 | if (length < 4) { | |
714 | (void)printf("truncated-ip %d", length); | |
715 | return; | |
716 | } | |
717 | memcpy (&hdr, (char *)ip, 4); | |
718 | switch (IP_V(&hdr)) { | |
719 | case 4: | |
720 | ip_print (gndo, bp, length); | |
721 | return; | |
722 | #ifdef INET6 | |
723 | case 6: | |
724 | ip6_print (bp, length); | |
725 | return; | |
726 | #endif | |
727 | default: | |
728 | (void)printf("unknown ip %d", IP_V(&hdr)); | |
729 | return; | |
730 | } | |
731 | } | |
732 | ||
733 | /* | |
734 | * Local Variables: | |
735 | * c-style: whitesmith | |
736 | * c-basic-offset: 8 | |
737 | * End: | |
738 | */ | |
739 | ||
740 |