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