]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
add tracefiles for infinite loop testing
[tcpdump] / print-icmp6.c
1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
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-icmp6.c,v 1.72.2.6 2004-07-28 20:09:17 guy Exp $";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef INET6
32
33 #include <tcpdump-stdinc.h>
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "ip6.h"
39 #include "icmp6.h"
40 #include "ipproto.h"
41
42 #include "interface.h"
43 #include "addrtoname.h"
44 #include "extract.h"
45
46 #include "udp.h"
47 #include "ah.h"
48
49 static const char *get_rtpref(u_int);
50 static const char *get_lifetime(u_int32_t);
51 static void print_lladdr(const u_char *, size_t);
52 static void icmp6_opt_print(const u_char *, int);
53 static void mld6_print(const u_char *);
54 static void mldv2_report_print(const u_char *, u_int);
55 static void mldv2_query_print(const u_char *, u_int);
56 static struct udphdr *get_upperlayer(u_char *, u_int *);
57 static void dnsname_print(const u_char *, const u_char *);
58 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
59 static void icmp6_rrenum_print(const u_char *, const u_char *);
60
61 #ifndef abs
62 #define abs(a) ((0 < (a)) ? (a) : -(a))
63 #endif
64
65 /* mldv2 report types */
66 static struct tok mldv2report2str[] = {
67 { 1, "is_in" },
68 { 2, "is_ex" },
69 { 3, "to_in" },
70 { 4, "to_ex" },
71 { 5, "allow" },
72 { 6, "block" },
73 { 0, NULL }
74 };
75
76 static const char *
77 get_rtpref(u_int v)
78 {
79 static const char *rtpref_str[] = {
80 "medium", /* 00 */
81 "high", /* 01 */
82 "rsv", /* 10 */
83 "low" /* 11 */
84 };
85
86 return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
87 }
88
89 static const char *
90 get_lifetime(u_int32_t v)
91 {
92 static char buf[20];
93
94 if (v == (u_int32_t)~0UL)
95 return "infinity";
96 else {
97 snprintf(buf, sizeof(buf), "%u", v);
98 return buf;
99 }
100 }
101
102 static void
103 print_lladdr(const u_int8_t *p, size_t l)
104 {
105 const u_int8_t *ep, *q;
106
107 q = p;
108 ep = p + l;
109 while (l > 0 && q < ep) {
110 if (q > p)
111 printf(":");
112 printf("%02x", *q++);
113 l--;
114 }
115 }
116
117 static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
118 u_int len)
119 {
120 size_t i;
121 register const u_int16_t *sp;
122 u_int32_t sum;
123 union {
124 struct {
125 struct in6_addr ph_src;
126 struct in6_addr ph_dst;
127 u_int32_t ph_len;
128 u_int8_t ph_zero[3];
129 u_int8_t ph_nxt;
130 } ph;
131 u_int16_t pa[20];
132 } phu;
133
134 /* pseudo-header */
135 memset(&phu, 0, sizeof(phu));
136 phu.ph.ph_src = ip6->ip6_src;
137 phu.ph.ph_dst = ip6->ip6_dst;
138 phu.ph.ph_len = htonl(len);
139 phu.ph.ph_nxt = IPPROTO_ICMPV6;
140
141 sum = 0;
142 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
143 sum += phu.pa[i];
144
145 sp = (const u_int16_t *)icp;
146
147 for (i = 0; i < (len & ~1); i += 2)
148 sum += *sp++;
149
150 if (len & 1)
151 sum += htons((*(const u_int8_t *)sp) << 8);
152
153 while (sum > 0xffff)
154 sum = (sum & 0xffff) + (sum >> 16);
155 sum = ~sum & 0xffff;
156
157 return (sum);
158 }
159
160 void
161 icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
162 {
163 const struct icmp6_hdr *dp;
164 const struct ip6_hdr *ip;
165 const char *str;
166 const struct ip6_hdr *oip;
167 const struct udphdr *ouh;
168 int dport;
169 const u_char *ep;
170 char buf[256];
171 u_int prot;
172
173 dp = (struct icmp6_hdr *)bp;
174 ip = (struct ip6_hdr *)bp2;
175 oip = (struct ip6_hdr *)(dp + 1);
176 str = buf;
177 /* 'ep' points to the end of available data. */
178 ep = snapend;
179
180 TCHECK(dp->icmp6_cksum);
181
182 if (vflag && !fragmented) {
183 int sum = dp->icmp6_cksum;
184
185 if (TTEST2(bp[0], length)) {
186 sum = icmp6_cksum(ip, dp, length);
187 if (sum != 0)
188 (void)printf("[bad icmp6 cksum %x!] ", sum);
189 else
190 (void)printf("[icmp6 sum ok] ");
191 }
192 }
193
194 switch (dp->icmp6_type) {
195 case ICMP6_DST_UNREACH:
196 TCHECK(oip->ip6_dst);
197 switch (dp->icmp6_code) {
198 case ICMP6_DST_UNREACH_NOROUTE:
199 printf("icmp6: %s unreachable route",
200 ip6addr_string(&oip->ip6_dst));
201 break;
202 case ICMP6_DST_UNREACH_ADMIN:
203 printf("icmp6: %s unreachable prohibited",
204 ip6addr_string(&oip->ip6_dst));
205 break;
206 case ICMP6_DST_UNREACH_BEYONDSCOPE:
207 printf("icmp6: %s beyond scope of source address %s",
208 ip6addr_string(&oip->ip6_dst),
209 ip6addr_string(&oip->ip6_src));
210 break;
211 case ICMP6_DST_UNREACH_ADDR:
212 printf("icmp6: %s unreachable address",
213 ip6addr_string(&oip->ip6_dst));
214 break;
215 case ICMP6_DST_UNREACH_NOPORT:
216 if ((ouh = get_upperlayer((u_char *)oip, &prot))
217 == NULL)
218 goto trunc;
219
220 dport = EXTRACT_16BITS(&ouh->uh_dport);
221 switch (prot) {
222 case IPPROTO_TCP:
223 printf("icmp6: %s tcp port %s unreachable",
224 ip6addr_string(&oip->ip6_dst),
225 tcpport_string(dport));
226 break;
227 case IPPROTO_UDP:
228 printf("icmp6: %s udp port %s unreachable",
229 ip6addr_string(&oip->ip6_dst),
230 udpport_string(dport));
231 break;
232 default:
233 printf("icmp6: %s protocol %d port %d unreachable",
234 ip6addr_string(&oip->ip6_dst),
235 oip->ip6_nxt, dport);
236 break;
237 }
238 break;
239 default:
240 printf("icmp6: %s unreachable code-#%d",
241 ip6addr_string(&oip->ip6_dst),
242 dp->icmp6_code);
243 break;
244 }
245 break;
246 case ICMP6_PACKET_TOO_BIG:
247 TCHECK(dp->icmp6_mtu);
248 printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu));
249 break;
250 case ICMP6_TIME_EXCEEDED:
251 TCHECK(oip->ip6_dst);
252 switch (dp->icmp6_code) {
253 case ICMP6_TIME_EXCEED_TRANSIT:
254 printf("icmp6: time exceeded in-transit for %s",
255 ip6addr_string(&oip->ip6_dst));
256 break;
257 case ICMP6_TIME_EXCEED_REASSEMBLY:
258 printf("icmp6: ip6 reassembly time exceeded");
259 break;
260 default:
261 printf("icmp6: time exceeded code-#%d",
262 dp->icmp6_code);
263 break;
264 }
265 break;
266 case ICMP6_PARAM_PROB:
267 TCHECK(oip->ip6_dst);
268 switch (dp->icmp6_code) {
269 case ICMP6_PARAMPROB_HEADER:
270 printf("icmp6: parameter problem errorneous - octet %u",
271 EXTRACT_32BITS(&dp->icmp6_pptr));
272 break;
273 case ICMP6_PARAMPROB_NEXTHEADER:
274 printf("icmp6: parameter problem next header - octet %u",
275 EXTRACT_32BITS(&dp->icmp6_pptr));
276 break;
277 case ICMP6_PARAMPROB_OPTION:
278 printf("icmp6: parameter problem option - octet %u",
279 EXTRACT_32BITS(&dp->icmp6_pptr));
280 break;
281 default:
282 printf("icmp6: parameter problem code-#%d",
283 dp->icmp6_code);
284 break;
285 }
286 break;
287 case ICMP6_ECHO_REQUEST:
288 case ICMP6_ECHO_REPLY:
289 TCHECK(dp->icmp6_seq);
290 printf("icmp6: echo %s seq %u",
291 dp->icmp6_type == ICMP6_ECHO_REQUEST ?
292 "request" : "reply",
293 EXTRACT_16BITS(&dp->icmp6_seq));
294 break;
295 case ICMP6_MEMBERSHIP_QUERY:
296 printf("icmp6: multicast listener query ");
297 if (length == MLD_MINLEN) {
298 mld6_print((const u_char *)dp);
299 } else if (length >= MLDV2_MINLEN) {
300 printf("v2 ");
301 mldv2_query_print((const u_char *)dp, length);
302 } else {
303 printf(" unknown-version(len=%d) ", length);
304 }
305 break;
306 case ICMP6_MEMBERSHIP_REPORT:
307 printf("icmp6: multicast listener report ");
308 mld6_print((const u_char *)dp);
309 break;
310 case ICMP6_MEMBERSHIP_REDUCTION:
311 printf("icmp6: multicast listener done ");
312 mld6_print((const u_char *)dp);
313 break;
314 case ND_ROUTER_SOLICIT:
315 printf("icmp6: router solicitation ");
316 if (vflag) {
317 #define RTSOLLEN 8
318 icmp6_opt_print((const u_char *)dp + RTSOLLEN,
319 length - RTSOLLEN);
320 }
321 break;
322 case ND_ROUTER_ADVERT:
323 printf("icmp6: router advertisement");
324 if (vflag) {
325 struct nd_router_advert *p;
326
327 p = (struct nd_router_advert *)dp;
328 TCHECK(p->nd_ra_retransmit);
329 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
330 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
331 printf("M");
332 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
333 printf("O");
334 if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
335 printf("H");
336
337 if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
338 != 0)
339 printf(" ");
340
341 printf("pref=%s, ",
342 get_rtpref(p->nd_ra_flags_reserved));
343
344 printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime));
345 printf("reachable_time=%u, ",
346 EXTRACT_32BITS(&p->nd_ra_reachable));
347 printf("retrans_time=%u)",
348 EXTRACT_32BITS(&p->nd_ra_retransmit));
349 #define RTADVLEN 16
350 icmp6_opt_print((const u_char *)dp + RTADVLEN,
351 length - RTADVLEN);
352 }
353 break;
354 case ND_NEIGHBOR_SOLICIT:
355 {
356 struct nd_neighbor_solicit *p;
357 p = (struct nd_neighbor_solicit *)dp;
358 TCHECK(p->nd_ns_target);
359 printf("icmp6: neighbor sol: who has %s",
360 ip6addr_string(&p->nd_ns_target));
361 if (vflag) {
362 #define NDSOLLEN 24
363 icmp6_opt_print((const u_char *)dp + NDSOLLEN,
364 length - NDSOLLEN);
365 }
366 }
367 break;
368 case ND_NEIGHBOR_ADVERT:
369 {
370 struct nd_neighbor_advert *p;
371
372 p = (struct nd_neighbor_advert *)dp;
373 TCHECK(p->nd_na_target);
374 printf("icmp6: neighbor adv: tgt is %s",
375 ip6addr_string(&p->nd_na_target));
376 if (vflag) {
377 #define ND_NA_FLAG_ALL \
378 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
379 /* we don't need ntohl() here. see advanced-api-04. */
380 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) {
381 #undef ND_NA_FLAG_ALL
382 u_int32_t flags;
383
384 flags = p->nd_na_flags_reserved;
385 printf("(");
386 if (flags & ND_NA_FLAG_ROUTER)
387 printf("R");
388 if (flags & ND_NA_FLAG_SOLICITED)
389 printf("S");
390 if (flags & ND_NA_FLAG_OVERRIDE)
391 printf("O");
392 printf(")");
393 }
394 #define NDADVLEN 24
395 icmp6_opt_print((const u_char *)dp + NDADVLEN,
396 length - NDADVLEN);
397 #undef NDADVLEN
398 }
399 }
400 break;
401 case ND_REDIRECT:
402 #define RDR(i) ((struct nd_redirect *)(i))
403 TCHECK(RDR(dp)->nd_rd_dst);
404 printf("icmp6: redirect %s",
405 getname6((const u_char *)&RDR(dp)->nd_rd_dst));
406 TCHECK(RDR(dp)->nd_rd_target);
407 printf(" to %s",
408 getname6((const u_char*)&RDR(dp)->nd_rd_target));
409 #define REDIRECTLEN 40
410 if (vflag) {
411 icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
412 length - REDIRECTLEN);
413 }
414 break;
415 #undef REDIRECTLEN
416 #undef RDR
417 case ICMP6_ROUTER_RENUMBERING:
418 icmp6_rrenum_print(bp, ep);
419 break;
420 case ICMP6_NI_QUERY:
421 case ICMP6_NI_REPLY:
422 icmp6_nodeinfo_print(length, bp, ep);
423 break;
424 case IND_SOLICIT:
425 printf("icmp6: inverse neighbor solicitation");
426 break;
427 case IND_ADVERT:
428 printf("icmp6: inverse neighbor advertisement");
429 break;
430 case ICMP6_V2_MEMBERSHIP_REPORT:
431 printf("icmp6: multicast listener report v2 ");
432 mldv2_report_print((const u_char *) dp, length);
433 break;
434 case ICMP6_HADISCOV_REQUEST:
435 printf("icmp6: ha discovery request");
436 if (vflag) {
437 TCHECK(dp->icmp6_data16[0]);
438 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
439 }
440 break;
441 case ICMP6_HADISCOV_REPLY:
442 printf("icmp6: ha discovery reply");
443 if (vflag) {
444 struct in6_addr *in6;
445 u_char *cp;
446
447 TCHECK(dp->icmp6_data16[0]);
448 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
449 cp = (u_char *)dp + length;
450 in6 = (struct in6_addr *)(dp + 1);
451 for (; (u_char *)in6 < cp; in6++) {
452 TCHECK(*in6);
453 printf(", %s", ip6addr_string(in6));
454 }
455 printf(")");
456 }
457 break;
458 case ICMP6_MOBILEPREFIX_SOLICIT:
459 printf("icmp6: mobile router solicitation");
460 if (vflag) {
461 TCHECK(dp->icmp6_data16[0]);
462 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
463 }
464 break;
465 case ICMP6_MOBILEPREFIX_ADVERT:
466 printf("icmp6: mobile router advertisement");
467 if (vflag) {
468 TCHECK(dp->icmp6_data16[0]);
469 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
470 if (dp->icmp6_data16[1] & 0xc0)
471 printf(" ");
472 if (dp->icmp6_data16[1] & 0x80)
473 printf("M");
474 if (dp->icmp6_data16[1] & 0x40)
475 printf("O");
476 printf(")");
477 #define MPADVLEN 8
478 icmp6_opt_print((const u_char *)dp + MPADVLEN,
479 length - MPADVLEN);
480 }
481 break;
482 default:
483 printf("icmp6: type-#%d", dp->icmp6_type);
484 break;
485 }
486 return;
487 trunc:
488 fputs("[|icmp6]", stdout);
489 }
490
491 static struct udphdr *
492 get_upperlayer(u_char *bp, u_int *prot)
493 {
494 const u_char *ep;
495 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
496 struct udphdr *uh;
497 struct ip6_hbh *hbh;
498 struct ip6_frag *fragh;
499 struct ah *ah;
500 u_int nh;
501 int hlen;
502
503 /* 'ep' points to the end of available data. */
504 ep = snapend;
505
506 if (!TTEST(ip6->ip6_nxt))
507 return NULL;
508
509 nh = ip6->ip6_nxt;
510 hlen = sizeof(struct ip6_hdr);
511
512 while (bp < snapend) {
513 bp += hlen;
514
515 switch(nh) {
516 case IPPROTO_UDP:
517 case IPPROTO_TCP:
518 uh = (struct udphdr *)bp;
519 if (TTEST(uh->uh_dport)) {
520 *prot = nh;
521 return(uh);
522 }
523 else
524 return(NULL);
525 /* NOTREACHED */
526
527 case IPPROTO_HOPOPTS:
528 case IPPROTO_DSTOPTS:
529 case IPPROTO_ROUTING:
530 hbh = (struct ip6_hbh *)bp;
531 if (!TTEST(hbh->ip6h_len))
532 return(NULL);
533 nh = hbh->ip6h_nxt;
534 hlen = (hbh->ip6h_len + 1) << 3;
535 break;
536
537 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
538 fragh = (struct ip6_frag *)bp;
539 if (!TTEST(fragh->ip6f_offlg))
540 return(NULL);
541 /* fragments with non-zero offset are meaningless */
542 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
543 return(NULL);
544 nh = fragh->ip6f_nxt;
545 hlen = sizeof(struct ip6_frag);
546 break;
547
548 case IPPROTO_AH:
549 ah = (struct ah *)bp;
550 if (!TTEST(ah->ah_len))
551 return(NULL);
552 nh = ah->ah_nxt;
553 hlen = (ah->ah_len + 2) << 2;
554 break;
555
556 default: /* unknown or undecodable header */
557 *prot = nh; /* meaningless, but set here anyway */
558 return(NULL);
559 }
560 }
561
562 return(NULL); /* should be notreached, though */
563 }
564
565 static void
566 icmp6_opt_print(const u_char *bp, int resid)
567 {
568 const struct nd_opt_hdr *op;
569 const struct nd_opt_hdr *opl; /* why there's no struct? */
570 const struct nd_opt_prefix_info *opp;
571 const struct icmp6_opts_redirect *opr;
572 const struct nd_opt_mtu *opm;
573 const struct nd_opt_advinterval *opa;
574 const struct nd_opt_homeagent_info *oph;
575 const struct nd_opt_route_info *opri;
576 const u_char *cp, *ep;
577 struct in6_addr in6, *in6p;
578 size_t l;
579
580 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
581
582 cp = bp;
583 /* 'ep' points to the end of available data. */
584 ep = snapend;
585
586 while (cp < ep) {
587 op = (struct nd_opt_hdr *)cp;
588
589 ECHECK(op->nd_opt_len);
590 if (resid <= 0)
591 return;
592 if (op->nd_opt_len == 0)
593 goto trunc;
594 if (cp + (op->nd_opt_len << 3) > ep)
595 goto trunc;
596
597 switch (op->nd_opt_type) {
598 case ND_OPT_SOURCE_LINKADDR:
599 opl = (struct nd_opt_hdr *)op;
600 printf("(src lladdr: ");
601 l = (op->nd_opt_len << 3) - 2;
602 print_lladdr(cp + 2, l);
603 /*(*/
604 printf(")");
605 break;
606 case ND_OPT_TARGET_LINKADDR:
607 opl = (struct nd_opt_hdr *)op;
608 printf("(tgt lladdr: ");
609 l = (op->nd_opt_len << 3) - 2;
610 print_lladdr(cp + 2, l);
611 /*(*/
612 printf(")");
613 break;
614 case ND_OPT_PREFIX_INFORMATION:
615 opp = (struct nd_opt_prefix_info *)op;
616 TCHECK(opp->nd_opt_pi_prefix);
617 printf("(prefix info: "); /*)*/
618 if (op->nd_opt_len != 4) {
619 printf("badlen");
620 /*(*/
621 printf(")");
622 break;
623 }
624 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
625 printf("L");
626 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
627 printf("A");
628 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
629 printf("R");
630 if (opp->nd_opt_pi_flags_reserved)
631 printf(" ");
632 printf("valid_ltime=%s,",
633 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
634 printf("preferred_ltime=%s,",
635 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
636 printf("prefix=%s/%d",
637 ip6addr_string(&opp->nd_opt_pi_prefix),
638 opp->nd_opt_pi_prefix_len);
639 if (opp->nd_opt_pi_len != 4)
640 printf("!");
641 /*(*/
642 printf(")");
643 break;
644 case ND_OPT_REDIRECTED_HEADER:
645 opr = (struct icmp6_opts_redirect *)op;
646 printf("(redirect)");
647 /* xxx */
648 break;
649 case ND_OPT_MTU:
650 opm = (struct nd_opt_mtu *)op;
651 TCHECK(opm->nd_opt_mtu_mtu);
652 printf("(mtu:"); /*)*/
653 if (op->nd_opt_len != 1) {
654 printf("badlen");
655 /*(*/
656 printf(")");
657 break;
658 }
659 printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
660 if (opm->nd_opt_mtu_len != 1)
661 printf("!");
662 printf(")");
663 break;
664 case ND_OPT_ADVINTERVAL:
665 opa = (struct nd_opt_advinterval *)op;
666 TCHECK(opa->nd_opt_adv_interval);
667 printf("(advint:"); /*)*/
668 printf(" advint=%u",
669 EXTRACT_32BITS(&opa->nd_opt_adv_interval));
670 /*(*/
671 printf(")");
672 break;
673 case ND_OPT_HOMEAGENT_INFO:
674 oph = (struct nd_opt_homeagent_info *)op;
675 TCHECK(oph->nd_opt_hai_lifetime);
676 printf("(ha info:"); /*)*/
677 printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
678 printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
679 printf(")");
680 break;
681 case ND_OPT_ROUTE_INFO:
682 opri = (struct nd_opt_route_info *)op;
683 TCHECK(opri->nd_opt_rti_lifetime);
684 memset(&in6, 0, sizeof(in6));
685 in6p = (struct in6_addr *)(opri + 1);
686 switch (op->nd_opt_len) {
687 case 1:
688 break;
689 case 2:
690 TCHECK2(*in6p, 8);
691 memcpy(&in6, opri + 1, 8);
692 break;
693 case 3:
694 TCHECK(*in6p);
695 memcpy(&in6, opri + 1, sizeof(in6));
696 break;
697 default:
698 goto trunc;
699 }
700 printf("(rtinfo:"); /*)*/
701 printf(" %s/%u", ip6addr_string(&in6),
702 opri->nd_opt_rti_prefixlen);
703 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
704 printf(", lifetime=%s",
705 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
706 /*(*/
707 printf(")");
708 break;
709 default:
710 printf("(unknown opt_type=%d, opt_len=%d)",
711 op->nd_opt_type, op->nd_opt_len);
712 break;
713 }
714
715 cp += op->nd_opt_len << 3;
716 resid -= op->nd_opt_len << 3;
717 }
718 return;
719
720 trunc:
721 fputs("[ndp opt]", stdout);
722 return;
723 #undef ECHECK
724 }
725
726 static void
727 mld6_print(const u_char *bp)
728 {
729 struct mld6_hdr *mp = (struct mld6_hdr *)bp;
730 const u_char *ep;
731
732 /* 'ep' points to the end of available data. */
733 ep = snapend;
734
735 if ((u_char *)mp + sizeof(*mp) > ep)
736 return;
737
738 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
739 printf("addr: %s", ip6addr_string(&mp->mld6_addr));
740 }
741
742 static void
743 mldv2_report_print(const u_char *bp, u_int len)
744 {
745 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
746 u_int group, nsrcs, ngroups;
747 u_int i, j;
748
749 /* Minimum len is 8 */
750 if (len < 8) {
751 printf(" [invalid len %d]", len);
752 return;
753 }
754
755 TCHECK(icp->icmp6_data16[1]);
756 ngroups = ntohs(icp->icmp6_data16[1]);
757 printf(", %d group record(s)", ngroups);
758 if (vflag > 0) {
759 /* Print the group records */
760 group = 8;
761 for (i = 0; i < ngroups; i++) {
762 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
763 if (len < group + 20) {
764 printf(" [invalid number of groups]");
765 return;
766 }
767 TCHECK2(bp[group + 4], 16);
768 printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
769 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
770 bp[group]));
771 nsrcs = (bp[group + 2] << 8) + bp[group + 3];
772 /* Check the number of sources and print them */
773 if (len < group + 20 + (nsrcs * 16)) {
774 printf(" [invalid number of sources %d]", nsrcs);
775 return;
776 }
777 if (vflag == 1)
778 printf(", %d source(s)", nsrcs);
779 else {
780 /* Print the sources */
781 (void)printf(" {");
782 for (j = 0; j < nsrcs; j++) {
783 TCHECK2(bp[group + 20 + j * 16], 16);
784 printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
785 }
786 (void)printf(" }");
787 }
788 /* Next group record */
789 group += 20 + nsrcs * 16;
790 printf("]");
791 }
792 }
793 return;
794 trunc:
795 (void)printf("[|icmp6]");
796 return;
797 }
798
799 static void
800 mldv2_query_print(const u_char *bp, u_int len)
801 {
802 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
803 u_int mrc;
804 int mrt, qqi;
805 u_int nsrcs;
806 register u_int i;
807
808 /* Minimum len is 28 */
809 if (len < 28) {
810 printf(" [invalid len %d]", len);
811 return;
812 }
813 TCHECK(icp->icmp6_data16[0]);
814 mrc = ntohs(icp->icmp6_data16[0]);
815 if (mrc < 32768) {
816 mrt = mrc;
817 } else {
818 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
819 }
820 if (vflag) {
821 (void)printf(" [max resp delay=%d]", mrt);
822 }
823 TCHECK2(bp[8], 16);
824 printf(" [gaddr %s", ip6addr_string(&bp[8]));
825
826 if (vflag) {
827 TCHECK(bp[25]);
828 if (bp[24] & 0x08) {
829 printf(" sflag");
830 }
831 if (bp[24] & 0x07) {
832 printf(" robustness=%d", bp[24] & 0x07);
833 }
834 if (bp[25] < 128) {
835 qqi = bp[25];
836 } else {
837 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
838 }
839 printf(" qqi=%d", qqi);
840 }
841
842 TCHECK2(bp[26], 2);
843 nsrcs = ntohs(*(u_short *)&bp[26]);
844 if (nsrcs > 0) {
845 if (len < 28 + nsrcs * 16)
846 printf(" [invalid number of sources]");
847 else if (vflag > 1) {
848 printf(" {");
849 for (i = 0; i < nsrcs; i++) {
850 TCHECK2(bp[28 + i * 16], 16);
851 printf(" %s", ip6addr_string(&bp[28 + i * 16]));
852 }
853 printf(" }");
854 } else
855 printf(", %d source(s)", nsrcs);
856 }
857 printf("]");
858 return;
859 trunc:
860 (void)printf("[|icmp6]");
861 return;
862 }
863
864 void
865 dnsname_print(const u_char *cp, const u_char *ep)
866 {
867 int i;
868
869 /* DNS name decoding - no decompression */
870 printf(", \"");
871 while (cp < ep) {
872 i = *cp++;
873 if (i) {
874 if (i > ep - cp) {
875 printf("???");
876 break;
877 }
878 while (i-- && cp < ep) {
879 safeputchar(*cp);
880 cp++;
881 }
882 if (cp + 1 < ep && *cp)
883 printf(".");
884 } else {
885 if (cp == ep) {
886 /* FQDN */
887 printf(".");
888 } else if (cp + 1 == ep && *cp == '\0') {
889 /* truncated */
890 } else {
891 /* invalid */
892 printf("???");
893 }
894 break;
895 }
896 }
897 printf("\"");
898 }
899
900 static void
901 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
902 {
903 struct icmp6_nodeinfo *ni6;
904 struct icmp6_hdr *dp;
905 const u_char *cp;
906 size_t siz, i;
907 int needcomma;
908
909 if (ep < bp)
910 return;
911 dp = (struct icmp6_hdr *)bp;
912 ni6 = (struct icmp6_nodeinfo *)bp;
913 siz = ep - bp;
914
915 switch (ni6->ni_type) {
916 case ICMP6_NI_QUERY:
917 if (siz == sizeof(*dp) + 4) {
918 /* KAME who-are-you */
919 printf("icmp6: who-are-you request");
920 break;
921 }
922 printf("icmp6: node information query");
923
924 TCHECK2(*dp, sizeof(*ni6));
925 ni6 = (struct icmp6_nodeinfo *)dp;
926 printf(" ("); /*)*/
927 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
928 case NI_QTYPE_NOOP:
929 printf("noop");
930 break;
931 case NI_QTYPE_SUPTYPES:
932 printf("supported qtypes");
933 i = EXTRACT_16BITS(&ni6->ni_flags);
934 if (i)
935 printf(" [%s]", (i & 0x01) ? "C" : "");
936 break;
937 break;
938 case NI_QTYPE_FQDN:
939 printf("DNS name");
940 break;
941 case NI_QTYPE_NODEADDR:
942 printf("node addresses");
943 i = ni6->ni_flags;
944 if (!i)
945 break;
946 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
947 printf(" [%s%s%s%s%s%s]",
948 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
949 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
950 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
951 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
952 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
953 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
954 break;
955 default:
956 printf("unknown");
957 break;
958 }
959
960 if (ni6->ni_qtype == NI_QTYPE_NOOP ||
961 ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
962 if (siz != sizeof(*ni6))
963 if (vflag)
964 printf(", invalid len");
965 /*(*/
966 printf(")");
967 break;
968 }
969
970
971 /* XXX backward compat, icmp-name-lookup-03 */
972 if (siz == sizeof(*ni6)) {
973 printf(", 03 draft");
974 /*(*/
975 printf(")");
976 break;
977 }
978
979 switch (ni6->ni_code) {
980 case ICMP6_NI_SUBJ_IPV6:
981 if (!TTEST2(*dp,
982 sizeof(*ni6) + sizeof(struct in6_addr)))
983 break;
984 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
985 if (vflag)
986 printf(", invalid subject len");
987 break;
988 }
989 printf(", subject=%s",
990 getname6((const u_char *)(ni6 + 1)));
991 break;
992 case ICMP6_NI_SUBJ_FQDN:
993 printf(", subject=DNS name");
994 cp = (const u_char *)(ni6 + 1);
995 if (cp[0] == ep - cp - 1) {
996 /* icmp-name-lookup-03, pascal string */
997 if (vflag)
998 printf(", 03 draft");
999 cp++;
1000 printf(", \"");
1001 while (cp < ep) {
1002 safeputchar(*cp);
1003 cp++;
1004 }
1005 printf("\"");
1006 } else
1007 dnsname_print(cp, ep);
1008 break;
1009 case ICMP6_NI_SUBJ_IPV4:
1010 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1011 break;
1012 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
1013 if (vflag)
1014 printf(", invalid subject len");
1015 break;
1016 }
1017 printf(", subject=%s",
1018 getname((const u_char *)(ni6 + 1)));
1019 break;
1020 default:
1021 printf(", unknown subject");
1022 break;
1023 }
1024
1025 /*(*/
1026 printf(")");
1027 break;
1028
1029 case ICMP6_NI_REPLY:
1030 if (icmp6len > siz) {
1031 printf("[|icmp6: node information reply]");
1032 break;
1033 }
1034
1035 needcomma = 0;
1036
1037 ni6 = (struct icmp6_nodeinfo *)dp;
1038 printf("icmp6: node information reply");
1039 printf(" ("); /*)*/
1040 switch (ni6->ni_code) {
1041 case ICMP6_NI_SUCCESS:
1042 if (vflag) {
1043 printf("success");
1044 needcomma++;
1045 }
1046 break;
1047 case ICMP6_NI_REFUSED:
1048 printf("refused");
1049 needcomma++;
1050 if (siz != sizeof(*ni6))
1051 if (vflag)
1052 printf(", invalid length");
1053 break;
1054 case ICMP6_NI_UNKNOWN:
1055 printf("unknown");
1056 needcomma++;
1057 if (siz != sizeof(*ni6))
1058 if (vflag)
1059 printf(", invalid length");
1060 break;
1061 }
1062
1063 if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1064 /*(*/
1065 printf(")");
1066 break;
1067 }
1068
1069 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1070 case NI_QTYPE_NOOP:
1071 if (needcomma)
1072 printf(", ");
1073 printf("noop");
1074 if (siz != sizeof(*ni6))
1075 if (vflag)
1076 printf(", invalid length");
1077 break;
1078 case NI_QTYPE_SUPTYPES:
1079 if (needcomma)
1080 printf(", ");
1081 printf("supported qtypes");
1082 i = EXTRACT_16BITS(&ni6->ni_flags);
1083 if (i)
1084 printf(" [%s]", (i & 0x01) ? "C" : "");
1085 break;
1086 case NI_QTYPE_FQDN:
1087 if (needcomma)
1088 printf(", ");
1089 printf("DNS name");
1090 cp = (const u_char *)(ni6 + 1) + 4;
1091 if (cp[0] == ep - cp - 1) {
1092 /* icmp-name-lookup-03, pascal string */
1093 if (vflag)
1094 printf(", 03 draft");
1095 cp++;
1096 printf(", \"");
1097 while (cp < ep) {
1098 safeputchar(*cp);
1099 cp++;
1100 }
1101 printf("\"");
1102 } else
1103 dnsname_print(cp, ep);
1104 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1105 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
1106 break;
1107 case NI_QTYPE_NODEADDR:
1108 if (needcomma)
1109 printf(", ");
1110 printf("node addresses");
1111 i = sizeof(*ni6);
1112 while (i < siz) {
1113 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1114 break;
1115 printf(" %s", getname6(bp + i));
1116 i += sizeof(struct in6_addr);
1117 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
1118 i += sizeof(int32_t);
1119 }
1120 i = ni6->ni_flags;
1121 if (!i)
1122 break;
1123 printf(" [%s%s%s%s%s%s%s]",
1124 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1125 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1126 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1127 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1128 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1129 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
1130 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
1131 break;
1132 default:
1133 if (needcomma)
1134 printf(", ");
1135 printf("unknown");
1136 break;
1137 }
1138
1139 /*(*/
1140 printf(")");
1141 break;
1142 }
1143 return;
1144
1145 trunc:
1146 fputs("[|icmp6]", stdout);
1147 }
1148
1149 static void
1150 icmp6_rrenum_print(const u_char *bp, const u_char *ep)
1151 {
1152 struct icmp6_router_renum *rr6;
1153 struct icmp6_hdr *dp;
1154 size_t siz;
1155 const char *cp;
1156 struct rr_pco_match *match;
1157 struct rr_pco_use *use;
1158 char hbuf[NI_MAXHOST];
1159 int n;
1160
1161 if (ep < bp)
1162 return;
1163 dp = (struct icmp6_hdr *)bp;
1164 rr6 = (struct icmp6_router_renum *)bp;
1165 siz = ep - bp;
1166 cp = (const char *)(rr6 + 1);
1167
1168 TCHECK(rr6->rr_reserved);
1169 switch (rr6->rr_code) {
1170 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1171 printf("router renum: command");
1172 break;
1173 case ICMP6_ROUTER_RENUMBERING_RESULT:
1174 printf("router renum: result");
1175 break;
1176 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1177 printf("router renum: sequence number reset");
1178 break;
1179 default:
1180 printf("router renum: code-#%d", rr6->rr_code);
1181 break;
1182 }
1183
1184 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
1185
1186 if (vflag) {
1187 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
1188 printf("["); /*]*/
1189 if (rr6->rr_flags) {
1190 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1191 F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1192 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1193 F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1194 F(ICMP6_RR_FLAGS_PREVDONE, "P"));
1195 }
1196 printf("seg=%u,", rr6->rr_segnum);
1197 printf("maxdelay=%u", rr6->rr_maxdelay);
1198 if (rr6->rr_reserved)
1199 printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
1200 /*[*/
1201 printf("]");
1202 #undef F
1203 }
1204
1205 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1206 match = (struct rr_pco_match *)cp;
1207 cp = (const char *)(match + 1);
1208
1209 TCHECK(match->rpm_prefix);
1210
1211 if (vflag > 1)
1212 printf("\n\t");
1213 else
1214 printf(" ");
1215 printf("match("); /*)*/
1216 switch (match->rpm_code) {
1217 case RPM_PCO_ADD: printf("add"); break;
1218 case RPM_PCO_CHANGE: printf("change"); break;
1219 case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
1220 default: printf("#%u", match->rpm_code); break;
1221 }
1222
1223 if (vflag) {
1224 printf(",ord=%u", match->rpm_ordinal);
1225 printf(",min=%u", match->rpm_minlen);
1226 printf(",max=%u", match->rpm_maxlen);
1227 }
1228 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
1229 printf(",%s/%u", hbuf, match->rpm_matchlen);
1230 else
1231 printf(",?/%u", match->rpm_matchlen);
1232 /*(*/
1233 printf(")");
1234
1235 n = match->rpm_len - 3;
1236 if (n % 4)
1237 goto trunc;
1238 n /= 4;
1239 while (n-- > 0) {
1240 use = (struct rr_pco_use *)cp;
1241 cp = (const char *)(use + 1);
1242
1243 TCHECK(use->rpu_prefix);
1244
1245 if (vflag > 1)
1246 printf("\n\t");
1247 else
1248 printf(" ");
1249 printf("use("); /*)*/
1250 if (use->rpu_flags) {
1251 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
1252 printf("%s%s,",
1253 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1254 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
1255 #undef F
1256 }
1257 if (vflag) {
1258 printf("mask=0x%x,", use->rpu_ramask);
1259 printf("raflags=0x%x,", use->rpu_raflags);
1260 if (~use->rpu_vltime == 0)
1261 printf("vltime=infty,");
1262 else
1263 printf("vltime=%u,",
1264 EXTRACT_32BITS(&use->rpu_vltime));
1265 if (~use->rpu_pltime == 0)
1266 printf("pltime=infty,");
1267 else
1268 printf("pltime=%u,",
1269 EXTRACT_32BITS(&use->rpu_pltime));
1270 }
1271 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1272 sizeof(hbuf)))
1273 printf("%s/%u/%u", hbuf, use->rpu_uselen,
1274 use->rpu_keeplen);
1275 else
1276 printf("?/%u/%u", use->rpu_uselen,
1277 use->rpu_keeplen);
1278 /*(*/
1279 printf(")");
1280 }
1281 }
1282
1283 return;
1284
1285 trunc:
1286 fputs("[|icmp6]", stdout);
1287 }
1288
1289 #endif /* INET6 */