]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
23047b243eca11701c31f0740e22a50fc7d36855
[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[] =
24 "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.44 2001-01-28 09:02:14 itojun Exp $";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef INET6
32
33 #include <ctype.h>
34
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39
40
41 #include <netinet/in.h>
42
43 #include <arpa/inet.h>
44
45 #include <stdio.h>
46 #include <netdb.h>
47
48 #include "ip6.h"
49 #include "icmp6.h"
50
51 #include "interface.h"
52 #include "addrtoname.h"
53
54 #include "udp.h"
55 #include "ah.h"
56
57 void icmp6_opt_print(const u_char *, int);
58 void mld6_print(const u_char *);
59 static struct udphdr *get_upperlayer(u_char *, int *);
60 static void dnsname_print(const u_char *, const u_char *);
61 void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
62 void icmp6_rrenum_print(int, const u_char *, const u_char *);
63
64 #ifndef abs
65 #define abs(a) ((0 < (a)) ? (a) : -(a))
66 #endif
67
68 void
69 icmp6_print(register const u_char *bp, register const u_char *bp2)
70 {
71 const struct icmp6_hdr *dp;
72 register const struct ip6_hdr *ip;
73 register const char *str;
74 register const struct ip6_hdr *oip;
75 register const struct udphdr *ouh;
76 register int dport;
77 register const u_char *ep;
78 char buf[256];
79 int icmp6len, prot;
80
81 #if 0
82 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
83 #endif
84
85 dp = (struct icmp6_hdr *)bp;
86 ip = (struct ip6_hdr *)bp2;
87 oip = (struct ip6_hdr *)(dp + 1);
88 str = buf;
89 /* 'ep' points to the end of available data. */
90 ep = snapend;
91 if (ip->ip6_plen)
92 icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
93 (bp - bp2));
94 else /* XXX: jumbo payload case... */
95 icmp6len = snapend - bp;
96
97 #if 0
98 (void)printf("%s > %s: ",
99 ip6addr_string(&ip->ip6_src),
100 ip6addr_string(&ip->ip6_dst));
101 #endif
102
103 TCHECK(dp->icmp6_code);
104 switch (dp->icmp6_type) {
105 case ICMP6_DST_UNREACH:
106 TCHECK(oip->ip6_dst);
107 switch (dp->icmp6_code) {
108 case ICMP6_DST_UNREACH_NOROUTE:
109 printf("icmp6: %s unreachable route",
110 ip6addr_string(&oip->ip6_dst));
111 break;
112 case ICMP6_DST_UNREACH_ADMIN:
113 printf("icmp6: %s unreachable prohibited",
114 ip6addr_string(&oip->ip6_dst));
115 break;
116 case ICMP6_DST_UNREACH_BEYONDSCOPE:
117 printf("icmp6: %s beyond scope of source address %s",
118 ip6addr_string(&oip->ip6_dst),
119 ip6addr_string(&oip->ip6_src));
120 break;
121 case ICMP6_DST_UNREACH_ADDR:
122 printf("icmp6: %s unreachable address",
123 ip6addr_string(&oip->ip6_dst));
124 break;
125 case ICMP6_DST_UNREACH_NOPORT:
126 if ((ouh = get_upperlayer((u_char *)oip, &prot))
127 == NULL)
128 goto trunc;
129
130 dport = ntohs(ouh->uh_dport);
131 switch (prot) {
132 case IPPROTO_TCP:
133 printf("icmp6: %s tcp port %s unreachable",
134 ip6addr_string(&oip->ip6_dst),
135 tcpport_string(dport));
136 break;
137 case IPPROTO_UDP:
138 printf("icmp6: %s udp port %s unreachable",
139 ip6addr_string(&oip->ip6_dst),
140 udpport_string(dport));
141 break;
142 default:
143 printf("icmp6: %s protocol %d port %d unreachable",
144 ip6addr_string(&oip->ip6_dst),
145 oip->ip6_nxt, dport);
146 break;
147 }
148 break;
149 default:
150 printf("icmp6: %s unreachable code-#%d",
151 ip6addr_string(&oip->ip6_dst),
152 dp->icmp6_code);
153 break;
154 }
155 break;
156 case ICMP6_PACKET_TOO_BIG:
157 TCHECK(dp->icmp6_mtu);
158 printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu));
159 break;
160 case ICMP6_TIME_EXCEEDED:
161 TCHECK(oip->ip6_dst);
162 switch (dp->icmp6_code) {
163 case ICMP6_TIME_EXCEED_TRANSIT:
164 printf("icmp6: time exceeded in-transit for %s",
165 ip6addr_string(&oip->ip6_dst));
166 break;
167 case ICMP6_TIME_EXCEED_REASSEMBLY:
168 printf("icmp6: ip6 reassembly time exceeded");
169 break;
170 default:
171 printf("icmp6: time exceeded code-#%d",
172 dp->icmp6_code);
173 break;
174 }
175 break;
176 case ICMP6_PARAM_PROB:
177 TCHECK(oip->ip6_dst);
178 switch (dp->icmp6_code) {
179 case ICMP6_PARAMPROB_HEADER:
180 printf("icmp6: parameter problem errorneous - octet %u\n",
181 (u_int32_t)ntohl(dp->icmp6_pptr));
182 break;
183 case ICMP6_PARAMPROB_NEXTHEADER:
184 printf("icmp6: parameter problem next header - octet %u\n",
185 (u_int32_t)ntohl(dp->icmp6_pptr));
186 break;
187 case ICMP6_PARAMPROB_OPTION:
188 printf("icmp6: parameter problem option - octet %u\n",
189 (u_int32_t)ntohl(dp->icmp6_pptr));
190 break;
191 default:
192 printf("icmp6: parameter problem code-#%d",
193 dp->icmp6_code);
194 break;
195 }
196 break;
197 case ICMP6_ECHO_REQUEST:
198 printf("icmp6: echo request");
199 break;
200 case ICMP6_ECHO_REPLY:
201 printf("icmp6: echo reply");
202 break;
203 case ICMP6_MEMBERSHIP_QUERY:
204 printf("icmp6: multicast listener query ");
205 mld6_print((const u_char *)dp);
206 break;
207 case ICMP6_MEMBERSHIP_REPORT:
208 printf("icmp6: multicast listener report ");
209 mld6_print((const u_char *)dp);
210 break;
211 case ICMP6_MEMBERSHIP_REDUCTION:
212 printf("icmp6: multicast listener done ");
213 mld6_print((const u_char *)dp);
214 break;
215 case ND_ROUTER_SOLICIT:
216 printf("icmp6: router solicitation ");
217 if (vflag) {
218 #define RTSOLLEN 8
219 icmp6_opt_print((const u_char *)dp + RTSOLLEN,
220 icmp6len - RTSOLLEN);
221 }
222 break;
223 case ND_ROUTER_ADVERT:
224 printf("icmp6: router advertisement");
225 if (vflag) {
226 struct nd_router_advert *p;
227
228 p = (struct nd_router_advert *)dp;
229 TCHECK(p->nd_ra_retransmit);
230 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
231 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
232 printf("M");
233 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
234 printf("O");
235 #ifndef ND_RA_FLAG_HA
236 #define ND_RA_FLAG_HA 0x20
237 #endif
238 if (p->nd_ra_flags_reserved & ND_RA_FLAG_HA)
239 printf("H");
240 if (p->nd_ra_flags_reserved != 0)
241 printf(" ");
242 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
243 printf("reachable_time=%u, ",
244 (u_int32_t)ntohl(p->nd_ra_reachable));
245 printf("retrans_time=%u)",
246 (u_int32_t)ntohl(p->nd_ra_retransmit));
247 #define RTADVLEN 16
248 icmp6_opt_print((const u_char *)dp + RTADVLEN,
249 icmp6len - RTADVLEN);
250 }
251 break;
252 case ND_NEIGHBOR_SOLICIT:
253 {
254 struct nd_neighbor_solicit *p;
255 p = (struct nd_neighbor_solicit *)dp;
256 TCHECK(p->nd_ns_target);
257 printf("icmp6: neighbor sol: who has %s",
258 ip6addr_string(&p->nd_ns_target));
259 if (vflag) {
260 #define NDSOLLEN 24
261 icmp6_opt_print((const u_char *)dp + NDSOLLEN,
262 icmp6len - NDSOLLEN);
263 }
264 }
265 break;
266 case ND_NEIGHBOR_ADVERT:
267 {
268 struct nd_neighbor_advert *p;
269
270 p = (struct nd_neighbor_advert *)dp;
271 TCHECK(p->nd_na_target);
272 printf("icmp6: neighbor adv: tgt is %s",
273 ip6addr_string(&p->nd_na_target));
274 if (vflag) {
275 #define ND_NA_FLAG_ALL \
276 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
277 /* we don't need ntohl() here. see advanced-api-04. */
278 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) {
279 #undef ND_NA_FLAG_ALL
280 u_int32_t flags;
281
282 flags = p->nd_na_flags_reserved;
283 printf("(");
284 if (flags & ND_NA_FLAG_ROUTER)
285 printf("R");
286 if (flags & ND_NA_FLAG_SOLICITED)
287 printf("S");
288 if (flags & ND_NA_FLAG_OVERRIDE)
289 printf("O");
290 printf(")");
291 }
292 #define NDADVLEN 24
293 icmp6_opt_print((const u_char *)dp + NDADVLEN,
294 icmp6len - NDADVLEN);
295 #undef NDADVLEN
296 }
297 }
298 break;
299 case ND_REDIRECT:
300 #define RDR(i) ((struct nd_redirect *)(i))
301 TCHECK(RDR(dp)->nd_rd_dst);
302 printf("icmp6: redirect %s",
303 getname6((const u_char *)&RDR(dp)->nd_rd_dst));
304 printf(" to %s",
305 getname6((const u_char*)&RDR(dp)->nd_rd_target));
306 #define REDIRECTLEN 40
307 if (vflag) {
308 icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
309 icmp6len - REDIRECTLEN);
310 }
311 break;
312 #undef REDIRECTLEN
313 #undef RDR
314 case ICMP6_ROUTER_RENUMBERING:
315 icmp6_rrenum_print(icmp6len, bp, ep);
316 break;
317 case ICMP6_NI_QUERY:
318 case ICMP6_NI_REPLY:
319 icmp6_nodeinfo_print(icmp6len, bp, ep);
320 break;
321 default:
322 printf("icmp6: type-#%d", dp->icmp6_type);
323 break;
324 }
325 return;
326 trunc:
327 fputs("[|icmp6]", stdout);
328 #if 0
329 #undef TCHECK
330 #endif
331 }
332
333 static struct udphdr *
334 get_upperlayer(register u_char *bp, int *prot)
335 {
336 register const u_char *ep;
337 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
338 struct udphdr *uh;
339 struct ip6_hbh *hbh;
340 struct ip6_frag *fragh;
341 struct ah *ah;
342 int nh, hlen;
343
344 /* 'ep' points to the end of available data. */
345 ep = snapend;
346
347 if (TTEST(ip6->ip6_nxt) == 0)
348 return NULL;
349
350 nh = ip6->ip6_nxt;
351 hlen = sizeof(struct ip6_hdr);
352
353 while (bp < snapend) {
354 bp += hlen;
355
356 switch(nh) {
357 case IPPROTO_UDP:
358 case IPPROTO_TCP:
359 uh = (struct udphdr *)bp;
360 if (TTEST(uh->uh_dport)) {
361 *prot = nh;
362 return(uh);
363 }
364 else
365 return(NULL);
366 /* NOTREACHED */
367
368 case IPPROTO_HOPOPTS:
369 case IPPROTO_DSTOPTS:
370 case IPPROTO_ROUTING:
371 hbh = (struct ip6_hbh *)bp;
372 if (TTEST(hbh->ip6h_len) == 0)
373 return(NULL);
374 nh = hbh->ip6h_nxt;
375 hlen = (hbh->ip6h_len + 1) << 3;
376 break;
377
378 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
379 fragh = (struct ip6_frag *)bp;
380 if (TTEST(fragh->ip6f_offlg) == 0)
381 return(NULL);
382 /* fragments with non-zero offset are meaningless */
383 if ((fragh->ip6f_offlg & IP6F_OFF_MASK) != 0)
384 return(NULL);
385 nh = fragh->ip6f_nxt;
386 hlen = sizeof(struct ip6_frag);
387 break;
388
389 case IPPROTO_AH:
390 ah = (struct ah *)bp;
391 if (TTEST(ah->ah_len) == 0)
392 return(NULL);
393 nh = ah->ah_nxt;
394 hlen = (ah->ah_len + 2) << 2;
395 break;
396
397 default: /* unknown or undecodable header */
398 *prot = nh; /* meaningless, but set here anyway */
399 return(NULL);
400 }
401 }
402
403 return(NULL); /* should be notreached, though */
404 }
405
406 void
407 icmp6_opt_print(register const u_char *bp, int resid)
408 {
409 register const struct nd_opt_hdr *op;
410 register const struct nd_opt_hdr *opl; /* why there's no struct? */
411 register const struct nd_opt_prefix_info *opp;
412 register const struct icmp6_opts_redirect *opr;
413 register const struct nd_opt_mtu *opm;
414 register const struct nd_opt_advint *opa;
415 register const u_char *ep;
416 int opts_len;
417 #if 0
418 register const struct ip6_hdr *ip;
419 register const char *str;
420 register const struct ip6_hdr *oip;
421 register const struct udphdr *ouh;
422 register int hlen, dport;
423 char buf[256];
424 #endif
425
426 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
427
428 op = (struct nd_opt_hdr *)bp;
429 #if 0
430 ip = (struct ip6_hdr *)bp2;
431 oip = &dp->icmp6_ip6;
432 str = buf;
433 #endif
434 /* 'ep' points to the end of available data. */
435 ep = snapend;
436
437 ECHECK(op->nd_opt_len);
438 if (resid <= 0)
439 return;
440 switch (op->nd_opt_type) {
441 case ND_OPT_SOURCE_LINKADDR:
442 opl = (struct nd_opt_hdr *)op;
443 #if 1
444 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
445 goto trunc;
446 #else
447 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
448 #endif
449 printf("(src lladdr: %s", /*)*/
450 etheraddr_string((u_char *)(opl + 1)));
451 if (opl->nd_opt_len != 1)
452 printf("!");
453 /*(*/
454 printf(")");
455 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
456 resid - (op->nd_opt_len << 3));
457 break;
458 case ND_OPT_TARGET_LINKADDR:
459 opl = (struct nd_opt_hdr *)op;
460 #if 1
461 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
462 goto trunc;
463 #else
464 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
465 #endif
466 printf("(tgt lladdr: %s", /*)*/
467 etheraddr_string((u_char *)(opl + 1)));
468 if (opl->nd_opt_len != 1)
469 printf("!");
470 /*(*/
471 printf(")");
472 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
473 resid - (op->nd_opt_len << 3));
474 break;
475 case ND_OPT_PREFIX_INFORMATION:
476 opp = (struct nd_opt_prefix_info *)op;
477 TCHECK(opp->nd_opt_pi_prefix);
478 printf("(prefix info: "); /*)*/
479 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
480 printf("L");
481 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
482 printf("A");
483 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
484 printf("R");
485 if (opp->nd_opt_pi_flags_reserved)
486 printf(" ");
487 printf("valid_ltime=");
488 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
489 printf("infinity");
490 else {
491 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
492 }
493 printf(", ");
494 printf("preffered_ltime=");
495 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
496 printf("infinity");
497 else {
498 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
499 }
500 printf(", ");
501 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
502 opp->nd_opt_pi_prefix_len);
503 if (opp->nd_opt_pi_len != 4)
504 printf("!");
505 /*(*/
506 printf(")");
507 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
508 resid - (op->nd_opt_len << 3));
509 break;
510 case ND_OPT_REDIRECTED_HEADER:
511 opr = (struct icmp6_opts_redirect *)op;
512 printf("(redirect)");
513 /* xxx */
514 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
515 resid - (op->nd_opt_len << 3));
516 break;
517 case ND_OPT_MTU:
518 opm = (struct nd_opt_mtu *)op;
519 TCHECK(opm->nd_opt_mtu_mtu);
520 printf("(mtu: "); /*)*/
521 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
522 if (opm->nd_opt_mtu_len != 1)
523 printf("!");
524 printf(")");
525 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
526 resid - (op->nd_opt_len << 3));
527 break;
528 case ND_OPT_ADVINTERVAL:
529 opa = (struct nd_opt_advint *)op;
530 TCHECK(opa->nd_opt_advint_advint);
531 printf("(advint: "); /*)*/
532 printf("advint=%u",
533 (u_int32_t)ntohl(opa->nd_opt_advint_advint));
534 /*(*/
535 printf(")");
536 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
537 resid - (op->nd_opt_len << 3));
538 break;
539 default:
540 opts_len = op->nd_opt_len;
541 printf("(unknwon opt_type=%d, opt_len=%d)",
542 op->nd_opt_type, opts_len);
543 if (opts_len == 0)
544 opts_len = 1; /* XXX */
545 icmp6_opt_print((const u_char *)op + (opts_len << 3),
546 resid - (opts_len << 3));
547 break;
548 }
549 return;
550 trunc:
551 fputs("[ndp opt]", stdout);
552 return;
553 #undef ECHECK
554 }
555
556 void
557 mld6_print(register const u_char *bp)
558 {
559 register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
560 register const u_char *ep;
561
562 /* 'ep' points to the end of available data. */
563 ep = snapend;
564
565 if ((u_char *)mp + sizeof(*mp) > ep)
566 return;
567
568 printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
569 printf("addr: %s", ip6addr_string(&mp->mld6_addr));
570 }
571
572 static void
573 dnsname_print(const u_char *cp, const u_char *ep)
574 {
575 int i;
576
577 /* DNS name decoding - no decompression */
578 printf(", \"");
579 while (cp < ep) {
580 i = *cp++;
581 if (i) {
582 if (i > ep - cp) {
583 printf("???");
584 break;
585 }
586 while (i-- && cp < ep) {
587 safeputchar(*cp);
588 cp++;
589 }
590 if (cp + 1 < ep && *cp)
591 printf(".");
592 } else {
593 if (cp == ep) {
594 /* FQDN */
595 printf(".");
596 } else if (cp + 1 == ep && *cp == '\0') {
597 /* truncated */
598 } else {
599 /* invalid */
600 printf("???");
601 }
602 break;
603 }
604 }
605 printf("\"");
606 }
607
608 void
609 icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
610 {
611 struct icmp6_nodeinfo *ni6;
612 struct icmp6_hdr *dp;
613 const u_char *cp;
614 int siz, i;
615 int needcomma;
616
617 dp = (struct icmp6_hdr *)bp;
618 ni6 = (struct icmp6_nodeinfo *)bp;
619 siz = ep - bp;
620
621 switch (ni6->ni_type) {
622 case ICMP6_NI_QUERY:
623 if (siz == sizeof(*dp) + 4) {
624 /* KAME who-are-you */
625 printf("icmp6: who-are-you request");
626 break;
627 }
628 printf("icmp6: node information query");
629
630 TCHECK2(*dp, sizeof(*ni6));
631 ni6 = (struct icmp6_nodeinfo *)dp;
632 printf(" ("); /*)*/
633 switch (ntohs(ni6->ni_qtype)) {
634 case NI_QTYPE_NOOP:
635 printf("noop");
636 break;
637 case NI_QTYPE_SUPTYPES:
638 printf("supported qtypes");
639 i = ntohs(ni6->ni_flags);
640 if (i)
641 printf(" [%s]", (i & 0x01) ? "C" : "");
642 break;
643 break;
644 case NI_QTYPE_FQDN:
645 printf("DNS name");
646 break;
647 case NI_QTYPE_NODEADDR:
648 printf("node addresses");
649 i = ni6->ni_flags;
650 if (!i)
651 break;
652 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
653 printf(" [%s%s%s%s%s%s]",
654 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
655 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
656 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
657 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
658 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
659 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
660 break;
661 default:
662 printf("unknown");
663 break;
664 }
665
666 if (ni6->ni_qtype == NI_QTYPE_NOOP ||
667 ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
668 if (siz != sizeof(*ni6))
669 if (vflag)
670 printf(", invalid len");
671 /*(*/
672 printf(")");
673 break;
674 }
675
676
677 /* XXX backward compat, icmp-name-lookup-03 */
678 if (siz == sizeof(*ni6)) {
679 printf(", 03 draft");
680 /*(*/
681 printf(")");
682 break;
683 }
684
685 switch (ni6->ni_code) {
686 case ICMP6_NI_SUBJ_IPV6:
687 if (!TTEST2(*dp,
688 sizeof(*ni6) + sizeof(struct in6_addr)))
689 break;
690 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
691 if (vflag)
692 printf(", invalid subject len");
693 break;
694 }
695 printf(", subject=%s",
696 getname6((const u_char *)(ni6 + 1)));
697 break;
698 case ICMP6_NI_SUBJ_FQDN:
699 printf(", subject=DNS name");
700 cp = (const u_char *)(ni6 + 1);
701 if (cp[0] == ep - cp - 1) {
702 /* icmp-name-lookup-03, pascal string */
703 if (vflag)
704 printf(", 03 draft");
705 cp++;
706 printf(", \"");
707 while (cp < ep) {
708 safeputchar(*cp);
709 cp++;
710 }
711 printf("\"");
712 } else
713 dnsname_print(cp, ep);
714 break;
715 case ICMP6_NI_SUBJ_IPV4:
716 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
717 break;
718 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
719 if (vflag)
720 printf(", invalid subject len");
721 break;
722 }
723 printf(", subject=%s",
724 getname((const u_char *)(ni6 + 1)));
725 break;
726 default:
727 printf(", unknown subject");
728 break;
729 }
730
731 /*(*/
732 printf(")");
733 break;
734
735 case ICMP6_NI_REPLY:
736 if (icmp6len > siz) {
737 printf("[|icmp6: node information reply]");
738 break;
739 }
740
741 needcomma = 0;
742
743 ni6 = (struct icmp6_nodeinfo *)dp;
744 printf("icmp6: node information reply");
745 printf(" ("); /*)*/
746 switch (ni6->ni_code) {
747 case ICMP6_NI_SUCCESS:
748 if (vflag) {
749 printf("success");
750 needcomma++;
751 }
752 break;
753 case ICMP6_NI_REFUSED:
754 printf("refused");
755 needcomma++;
756 if (siz != sizeof(*ni6))
757 if (vflag)
758 printf(", invalid length");
759 break;
760 case ICMP6_NI_UNKNOWN:
761 printf("unknown");
762 needcomma++;
763 if (siz != sizeof(*ni6))
764 if (vflag)
765 printf(", invalid length");
766 break;
767 }
768
769 if (ni6->ni_code != ICMP6_NI_SUCCESS) {
770 /*(*/
771 printf(")");
772 break;
773 }
774
775 switch (ntohs(ni6->ni_qtype)) {
776 case NI_QTYPE_NOOP:
777 if (needcomma)
778 printf(", ");
779 printf("noop");
780 if (siz != sizeof(*ni6))
781 if (vflag)
782 printf(", invalid length");
783 break;
784 case NI_QTYPE_SUPTYPES:
785 if (needcomma)
786 printf(", ");
787 printf("supported qtypes");
788 i = ntohs(ni6->ni_flags);
789 if (i)
790 printf(" [%s]", (i & 0x01) ? "C" : "");
791 break;
792 case NI_QTYPE_FQDN:
793 if (needcomma)
794 printf(", ");
795 printf("DNS name");
796 cp = (const u_char *)(ni6 + 1) + 4;
797 if (cp[0] == ep - cp - 1) {
798 /* icmp-name-lookup-03, pascal string */
799 if (vflag)
800 printf(", 03 draft");
801 cp++;
802 printf(", \"");
803 while (cp < ep) {
804 safeputchar(*cp);
805 cp++;
806 }
807 printf("\"");
808 } else
809 dnsname_print(cp, ep);
810 if ((ntohs(ni6->ni_flags) & 0x01) != 0)
811 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
812 break;
813 case NI_QTYPE_NODEADDR:
814 if (needcomma)
815 printf(", ");
816 printf("node addresses");
817 i = sizeof(*ni6);
818 while (i < siz) {
819 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
820 break;
821 printf(" %s", getname6(bp + i));
822 i += sizeof(struct in6_addr);
823 printf("(%d)", ntohl(*(int32_t *)(bp + i)));
824 i += sizeof(int32_t);
825 }
826 i = ni6->ni_flags;
827 if (!i)
828 break;
829 printf(" [%s%s%s%s%s%s%s]",
830 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
831 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
832 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
833 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
834 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
835 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
836 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
837 break;
838 default:
839 if (needcomma)
840 printf(", ");
841 printf("unknown");
842 break;
843 }
844
845 /*(*/
846 printf(")");
847 break;
848 }
849 return;
850
851 trunc:
852 fputs("[|icmp6]", stdout);
853 }
854
855 void
856 icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
857 {
858 struct icmp6_router_renum *rr6;
859 struct icmp6_hdr *dp;
860 size_t siz;
861 const char *cp;
862 struct rr_pco_match *match;
863 struct rr_pco_use *use;
864 char hbuf[NI_MAXHOST];
865 int n;
866
867 dp = (struct icmp6_hdr *)bp;
868 rr6 = (struct icmp6_router_renum *)bp;
869 siz = ep - bp;
870 cp = (const char *)(rr6 + 1);
871
872 TCHECK(rr6->rr_reserved);
873 switch (rr6->rr_code) {
874 case ICMP6_ROUTER_RENUMBERING_COMMAND:
875 printf("router renum: command");
876 break;
877 case ICMP6_ROUTER_RENUMBERING_RESULT:
878 printf("router renum: result");
879 break;
880 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
881 printf("router renum: sequence number reset");
882 break;
883 default:
884 printf("router renum: code-#%d", rr6->rr_code);
885 break;
886 }
887
888 printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum));
889
890 if (vflag) {
891 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
892 printf("["); /*]*/
893 if (rr6->rr_flags) {
894 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
895 F(ICMP6_RR_FLAGS_REQRESULT, "R"),
896 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
897 F(ICMP6_RR_FLAGS_SPECSITE, "S"),
898 F(ICMP6_RR_FLAGS_PREVDONE, "P"));
899 }
900 printf("seg=%u,", rr6->rr_segnum);
901 printf("maxdelay=%u", rr6->rr_maxdelay);
902 if (rr6->rr_reserved)
903 printf("rsvd=0x%x", (u_int16_t)ntohs(rr6->rr_reserved));
904 /*[*/
905 printf("]");
906 #undef F
907 }
908
909 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
910 match = (struct rr_pco_match *)cp;
911 cp = (const char *)(match + 1);
912
913 TCHECK(match->rpm_prefix);
914
915 if (vflag)
916 printf("\n\t");
917 else
918 printf(" ");
919 printf("match("); /*)*/
920 switch (match->rpm_code) {
921 case RPM_PCO_ADD: printf("add"); break;
922 case RPM_PCO_CHANGE: printf("change"); break;
923 case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
924 default: printf("#%u", match->rpm_code); break;
925 }
926
927 if (vflag) {
928 printf(",ord=%u", match->rpm_ordinal);
929 printf(",min=%u", match->rpm_minlen);
930 printf(",max=%u", match->rpm_maxlen);
931 }
932 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
933 printf(",%s/%u", hbuf, match->rpm_matchlen);
934 else
935 printf(",?/%u", match->rpm_matchlen);
936 /*(*/
937 printf(")");
938
939 n = match->rpm_len - 3;
940 if (n % 4)
941 goto trunc;
942 n /= 4;
943 while (n-- > 0) {
944 use = (struct rr_pco_use *)cp;
945 cp = (const char *)(use + 1);
946
947 TCHECK(use->rpu_prefix);
948
949 if (vflag)
950 printf("\n\t");
951 else
952 printf(" ");
953 printf("use("); /*)*/
954 if (use->rpu_flags) {
955 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
956 printf("%s%s,",
957 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
958 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
959 #undef F
960 }
961 if (vflag) {
962 printf("mask=0x%x,", use->rpu_ramask);
963 printf("raflags=0x%x,", use->rpu_raflags);
964 if (~use->rpu_vltime == 0)
965 printf("vltime=infty,");
966 else
967 printf("vltime=%u,",
968 (u_int32_t)ntohl(use->rpu_vltime));
969 if (~use->rpu_pltime == 0)
970 printf("pltime=infty,");
971 else
972 printf("pltime=%u,",
973 (u_int32_t)ntohl(use->rpu_pltime));
974 }
975 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
976 sizeof(hbuf)))
977 printf("%s/%u/%u", hbuf, use->rpu_uselen,
978 use->rpu_keeplen);
979 else
980 printf("?/%u/%u", use->rpu_uselen,
981 use->rpu_keeplen);
982 /*(*/
983 printf(")");
984 }
985 }
986
987 return;
988
989 trunc:
990 fputs("[|icmp6]", stdout);
991 }
992
993 #endif /* INET6 */