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