]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
From Shinsuke Suzuki <[email protected]>: a patch to sync ICMPv6-Type number
[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.5 2004-06-16 00:07:31 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 TCHECK(bp[group + 4]);
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 printf(" [gaddr %s", ip6addr_string(&bp[8]));
824
825 if (vflag) {
826 TCHECK(bp[25]);
827 if (bp[24] & 0x08) {
828 printf(" sflag");
829 }
830 if (bp[24] & 0x07) {
831 printf(" robustness=%d", bp[24] & 0x07);
832 }
833 if (bp[25] < 128) {
834 qqi = bp[25];
835 } else {
836 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
837 }
838 printf(" qqi=%d", qqi);
839 }
840
841 nsrcs = ntohs(*(u_short *)&bp[26]);
842 if (nsrcs > 0) {
843 if (len < 28 + nsrcs * 16)
844 printf(" [invalid number of sources]");
845 else if (vflag > 1) {
846 printf(" {");
847 for (i = 0; i < nsrcs; i++) {
848 TCHECK2(bp[28 + i * 16], 16);
849 printf(" %s", ip6addr_string(&bp[28 + i * 16]));
850 }
851 printf(" }");
852 } else
853 printf(", %d source(s)", nsrcs);
854 }
855 printf("]");
856 return;
857 trunc:
858 (void)printf("[|icmp6]");
859 return;
860 }
861
862 void
863 dnsname_print(const u_char *cp, const u_char *ep)
864 {
865 int i;
866
867 /* DNS name decoding - no decompression */
868 printf(", \"");
869 while (cp < ep) {
870 i = *cp++;
871 if (i) {
872 if (i > ep - cp) {
873 printf("???");
874 break;
875 }
876 while (i-- && cp < ep) {
877 safeputchar(*cp);
878 cp++;
879 }
880 if (cp + 1 < ep && *cp)
881 printf(".");
882 } else {
883 if (cp == ep) {
884 /* FQDN */
885 printf(".");
886 } else if (cp + 1 == ep && *cp == '\0') {
887 /* truncated */
888 } else {
889 /* invalid */
890 printf("???");
891 }
892 break;
893 }
894 }
895 printf("\"");
896 }
897
898 static void
899 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
900 {
901 struct icmp6_nodeinfo *ni6;
902 struct icmp6_hdr *dp;
903 const u_char *cp;
904 size_t siz, i;
905 int needcomma;
906
907 if (ep < bp)
908 return;
909 dp = (struct icmp6_hdr *)bp;
910 ni6 = (struct icmp6_nodeinfo *)bp;
911 siz = ep - bp;
912
913 switch (ni6->ni_type) {
914 case ICMP6_NI_QUERY:
915 if (siz == sizeof(*dp) + 4) {
916 /* KAME who-are-you */
917 printf("icmp6: who-are-you request");
918 break;
919 }
920 printf("icmp6: node information query");
921
922 TCHECK2(*dp, sizeof(*ni6));
923 ni6 = (struct icmp6_nodeinfo *)dp;
924 printf(" ("); /*)*/
925 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
926 case NI_QTYPE_NOOP:
927 printf("noop");
928 break;
929 case NI_QTYPE_SUPTYPES:
930 printf("supported qtypes");
931 i = EXTRACT_16BITS(&ni6->ni_flags);
932 if (i)
933 printf(" [%s]", (i & 0x01) ? "C" : "");
934 break;
935 break;
936 case NI_QTYPE_FQDN:
937 printf("DNS name");
938 break;
939 case NI_QTYPE_NODEADDR:
940 printf("node addresses");
941 i = ni6->ni_flags;
942 if (!i)
943 break;
944 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
945 printf(" [%s%s%s%s%s%s]",
946 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
947 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
948 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
949 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
950 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
951 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
952 break;
953 default:
954 printf("unknown");
955 break;
956 }
957
958 if (ni6->ni_qtype == NI_QTYPE_NOOP ||
959 ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
960 if (siz != sizeof(*ni6))
961 if (vflag)
962 printf(", invalid len");
963 /*(*/
964 printf(")");
965 break;
966 }
967
968
969 /* XXX backward compat, icmp-name-lookup-03 */
970 if (siz == sizeof(*ni6)) {
971 printf(", 03 draft");
972 /*(*/
973 printf(")");
974 break;
975 }
976
977 switch (ni6->ni_code) {
978 case ICMP6_NI_SUBJ_IPV6:
979 if (!TTEST2(*dp,
980 sizeof(*ni6) + sizeof(struct in6_addr)))
981 break;
982 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
983 if (vflag)
984 printf(", invalid subject len");
985 break;
986 }
987 printf(", subject=%s",
988 getname6((const u_char *)(ni6 + 1)));
989 break;
990 case ICMP6_NI_SUBJ_FQDN:
991 printf(", subject=DNS name");
992 cp = (const u_char *)(ni6 + 1);
993 if (cp[0] == ep - cp - 1) {
994 /* icmp-name-lookup-03, pascal string */
995 if (vflag)
996 printf(", 03 draft");
997 cp++;
998 printf(", \"");
999 while (cp < ep) {
1000 safeputchar(*cp);
1001 cp++;
1002 }
1003 printf("\"");
1004 } else
1005 dnsname_print(cp, ep);
1006 break;
1007 case ICMP6_NI_SUBJ_IPV4:
1008 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1009 break;
1010 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
1011 if (vflag)
1012 printf(", invalid subject len");
1013 break;
1014 }
1015 printf(", subject=%s",
1016 getname((const u_char *)(ni6 + 1)));
1017 break;
1018 default:
1019 printf(", unknown subject");
1020 break;
1021 }
1022
1023 /*(*/
1024 printf(")");
1025 break;
1026
1027 case ICMP6_NI_REPLY:
1028 if (icmp6len > siz) {
1029 printf("[|icmp6: node information reply]");
1030 break;
1031 }
1032
1033 needcomma = 0;
1034
1035 ni6 = (struct icmp6_nodeinfo *)dp;
1036 printf("icmp6: node information reply");
1037 printf(" ("); /*)*/
1038 switch (ni6->ni_code) {
1039 case ICMP6_NI_SUCCESS:
1040 if (vflag) {
1041 printf("success");
1042 needcomma++;
1043 }
1044 break;
1045 case ICMP6_NI_REFUSED:
1046 printf("refused");
1047 needcomma++;
1048 if (siz != sizeof(*ni6))
1049 if (vflag)
1050 printf(", invalid length");
1051 break;
1052 case ICMP6_NI_UNKNOWN:
1053 printf("unknown");
1054 needcomma++;
1055 if (siz != sizeof(*ni6))
1056 if (vflag)
1057 printf(", invalid length");
1058 break;
1059 }
1060
1061 if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1062 /*(*/
1063 printf(")");
1064 break;
1065 }
1066
1067 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1068 case NI_QTYPE_NOOP:
1069 if (needcomma)
1070 printf(", ");
1071 printf("noop");
1072 if (siz != sizeof(*ni6))
1073 if (vflag)
1074 printf(", invalid length");
1075 break;
1076 case NI_QTYPE_SUPTYPES:
1077 if (needcomma)
1078 printf(", ");
1079 printf("supported qtypes");
1080 i = EXTRACT_16BITS(&ni6->ni_flags);
1081 if (i)
1082 printf(" [%s]", (i & 0x01) ? "C" : "");
1083 break;
1084 case NI_QTYPE_FQDN:
1085 if (needcomma)
1086 printf(", ");
1087 printf("DNS name");
1088 cp = (const u_char *)(ni6 + 1) + 4;
1089 if (cp[0] == ep - cp - 1) {
1090 /* icmp-name-lookup-03, pascal string */
1091 if (vflag)
1092 printf(", 03 draft");
1093 cp++;
1094 printf(", \"");
1095 while (cp < ep) {
1096 safeputchar(*cp);
1097 cp++;
1098 }
1099 printf("\"");
1100 } else
1101 dnsname_print(cp, ep);
1102 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1103 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
1104 break;
1105 case NI_QTYPE_NODEADDR:
1106 if (needcomma)
1107 printf(", ");
1108 printf("node addresses");
1109 i = sizeof(*ni6);
1110 while (i < siz) {
1111 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1112 break;
1113 printf(" %s", getname6(bp + i));
1114 i += sizeof(struct in6_addr);
1115 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
1116 i += sizeof(int32_t);
1117 }
1118 i = ni6->ni_flags;
1119 if (!i)
1120 break;
1121 printf(" [%s%s%s%s%s%s%s]",
1122 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1123 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1124 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1125 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1126 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1127 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
1128 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
1129 break;
1130 default:
1131 if (needcomma)
1132 printf(", ");
1133 printf("unknown");
1134 break;
1135 }
1136
1137 /*(*/
1138 printf(")");
1139 break;
1140 }
1141 return;
1142
1143 trunc:
1144 fputs("[|icmp6]", stdout);
1145 }
1146
1147 static void
1148 icmp6_rrenum_print(const u_char *bp, const u_char *ep)
1149 {
1150 struct icmp6_router_renum *rr6;
1151 struct icmp6_hdr *dp;
1152 size_t siz;
1153 const char *cp;
1154 struct rr_pco_match *match;
1155 struct rr_pco_use *use;
1156 char hbuf[NI_MAXHOST];
1157 int n;
1158
1159 if (ep < bp)
1160 return;
1161 dp = (struct icmp6_hdr *)bp;
1162 rr6 = (struct icmp6_router_renum *)bp;
1163 siz = ep - bp;
1164 cp = (const char *)(rr6 + 1);
1165
1166 TCHECK(rr6->rr_reserved);
1167 switch (rr6->rr_code) {
1168 case ICMP6_ROUTER_RENUMBERING_COMMAND:
1169 printf("router renum: command");
1170 break;
1171 case ICMP6_ROUTER_RENUMBERING_RESULT:
1172 printf("router renum: result");
1173 break;
1174 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1175 printf("router renum: sequence number reset");
1176 break;
1177 default:
1178 printf("router renum: code-#%d", rr6->rr_code);
1179 break;
1180 }
1181
1182 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
1183
1184 if (vflag) {
1185 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
1186 printf("["); /*]*/
1187 if (rr6->rr_flags) {
1188 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1189 F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1190 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1191 F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1192 F(ICMP6_RR_FLAGS_PREVDONE, "P"));
1193 }
1194 printf("seg=%u,", rr6->rr_segnum);
1195 printf("maxdelay=%u", rr6->rr_maxdelay);
1196 if (rr6->rr_reserved)
1197 printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
1198 /*[*/
1199 printf("]");
1200 #undef F
1201 }
1202
1203 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1204 match = (struct rr_pco_match *)cp;
1205 cp = (const char *)(match + 1);
1206
1207 TCHECK(match->rpm_prefix);
1208
1209 if (vflag > 1)
1210 printf("\n\t");
1211 else
1212 printf(" ");
1213 printf("match("); /*)*/
1214 switch (match->rpm_code) {
1215 case RPM_PCO_ADD: printf("add"); break;
1216 case RPM_PCO_CHANGE: printf("change"); break;
1217 case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
1218 default: printf("#%u", match->rpm_code); break;
1219 }
1220
1221 if (vflag) {
1222 printf(",ord=%u", match->rpm_ordinal);
1223 printf(",min=%u", match->rpm_minlen);
1224 printf(",max=%u", match->rpm_maxlen);
1225 }
1226 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
1227 printf(",%s/%u", hbuf, match->rpm_matchlen);
1228 else
1229 printf(",?/%u", match->rpm_matchlen);
1230 /*(*/
1231 printf(")");
1232
1233 n = match->rpm_len - 3;
1234 if (n % 4)
1235 goto trunc;
1236 n /= 4;
1237 while (n-- > 0) {
1238 use = (struct rr_pco_use *)cp;
1239 cp = (const char *)(use + 1);
1240
1241 TCHECK(use->rpu_prefix);
1242
1243 if (vflag > 1)
1244 printf("\n\t");
1245 else
1246 printf(" ");
1247 printf("use("); /*)*/
1248 if (use->rpu_flags) {
1249 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
1250 printf("%s%s,",
1251 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1252 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
1253 #undef F
1254 }
1255 if (vflag) {
1256 printf("mask=0x%x,", use->rpu_ramask);
1257 printf("raflags=0x%x,", use->rpu_raflags);
1258 if (~use->rpu_vltime == 0)
1259 printf("vltime=infty,");
1260 else
1261 printf("vltime=%u,",
1262 EXTRACT_32BITS(&use->rpu_vltime));
1263 if (~use->rpu_pltime == 0)
1264 printf("pltime=infty,");
1265 else
1266 printf("pltime=%u,",
1267 EXTRACT_32BITS(&use->rpu_pltime));
1268 }
1269 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1270 sizeof(hbuf)))
1271 printf("%s/%u/%u", hbuf, use->rpu_uselen,
1272 use->rpu_keeplen);
1273 else
1274 printf("?/%u/%u", use->rpu_uselen,
1275 use->rpu_keeplen);
1276 /*(*/
1277 printf(")");
1278 }
1279 }
1280
1281 return;
1282
1283 trunc:
1284 fputs("[|icmp6]", stdout);
1285 }
1286
1287 #endif /* INET6 */