]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
45a3bddafd0222acb29c07b2d6058ae3e2edbc5b
[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.67 2002-12-11 22:29:21 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 static void icmp6_opt_print(const u_char *, int);
52 static void mld6_print(const u_char *);
53 static struct udphdr *get_upperlayer(u_char *, u_int *);
54 static void dnsname_print(const u_char *, const u_char *);
55 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
56 static void icmp6_rrenum_print(u_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 u_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, u_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 u_int nh;
411 int hlen;
412
413 /* 'ep' points to the end of available data. */
414 ep = snapend;
415
416 if (!TTEST(ip6->ip6_nxt))
417 return NULL;
418
419 nh = ip6->ip6_nxt;
420 hlen = sizeof(struct ip6_hdr);
421
422 while (bp < snapend) {
423 bp += hlen;
424
425 switch(nh) {
426 case IPPROTO_UDP:
427 case IPPROTO_TCP:
428 uh = (struct udphdr *)bp;
429 if (TTEST(uh->uh_dport)) {
430 *prot = nh;
431 return(uh);
432 }
433 else
434 return(NULL);
435 /* NOTREACHED */
436
437 case IPPROTO_HOPOPTS:
438 case IPPROTO_DSTOPTS:
439 case IPPROTO_ROUTING:
440 hbh = (struct ip6_hbh *)bp;
441 if (!TTEST(hbh->ip6h_len))
442 return(NULL);
443 nh = hbh->ip6h_nxt;
444 hlen = (hbh->ip6h_len + 1) << 3;
445 break;
446
447 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
448 fragh = (struct ip6_frag *)bp;
449 if (!TTEST(fragh->ip6f_offlg))
450 return(NULL);
451 /* fragments with non-zero offset are meaningless */
452 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
453 return(NULL);
454 nh = fragh->ip6f_nxt;
455 hlen = sizeof(struct ip6_frag);
456 break;
457
458 case IPPROTO_AH:
459 ah = (struct ah *)bp;
460 if (!TTEST(ah->ah_len))
461 return(NULL);
462 nh = ah->ah_nxt;
463 hlen = (ah->ah_len + 2) << 2;
464 break;
465
466 default: /* unknown or undecodable header */
467 *prot = nh; /* meaningless, but set here anyway */
468 return(NULL);
469 }
470 }
471
472 return(NULL); /* should be notreached, though */
473 }
474
475 static void
476 icmp6_opt_print(const u_char *bp, int resid)
477 {
478 const struct nd_opt_hdr *op;
479 const struct nd_opt_hdr *opl; /* why there's no struct? */
480 const struct nd_opt_prefix_info *opp;
481 const struct icmp6_opts_redirect *opr;
482 const struct nd_opt_mtu *opm;
483 const struct nd_opt_advinterval *opa;
484 const struct nd_opt_homeagent_info *oph;
485 const struct nd_opt_route_info *opri;
486 const u_char *cp, *ep;
487 struct in6_addr in6, *in6p;
488 size_t l;
489
490 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
491
492 cp = bp;
493 /* 'ep' points to the end of available data. */
494 ep = snapend;
495
496 while (cp < ep) {
497 op = (struct nd_opt_hdr *)cp;
498
499 ECHECK(op->nd_opt_len);
500 if (resid <= 0)
501 return;
502 if (op->nd_opt_len == 0)
503 goto trunc;
504 if (cp + (op->nd_opt_len << 3) > ep)
505 goto trunc;
506
507 switch (op->nd_opt_type) {
508 case ND_OPT_SOURCE_LINKADDR:
509 opl = (struct nd_opt_hdr *)op;
510 printf("(src lladdr: ");
511 l = (op->nd_opt_len << 3) - 2;
512 print_lladdr(cp + 2, l);
513 /*(*/
514 printf(")");
515 break;
516 case ND_OPT_TARGET_LINKADDR:
517 opl = (struct nd_opt_hdr *)op;
518 printf("(tgt lladdr: ");
519 l = (op->nd_opt_len << 3) - 2;
520 print_lladdr(cp + 2, l);
521 /*(*/
522 printf(")");
523 break;
524 case ND_OPT_PREFIX_INFORMATION:
525 opp = (struct nd_opt_prefix_info *)op;
526 TCHECK(opp->nd_opt_pi_prefix);
527 printf("(prefix info: "); /*)*/
528 if (op->nd_opt_len != 4) {
529 printf("badlen");
530 /*(*/
531 printf(")");
532 break;
533 }
534 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
535 printf("L");
536 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
537 printf("A");
538 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
539 printf("R");
540 if (opp->nd_opt_pi_flags_reserved)
541 printf(" ");
542 printf("valid_ltime=%s,",
543 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
544 printf("preferred_ltime=%s,",
545 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
546 printf("prefix=%s/%d",
547 ip6addr_string(&opp->nd_opt_pi_prefix),
548 opp->nd_opt_pi_prefix_len);
549 if (opp->nd_opt_pi_len != 4)
550 printf("!");
551 /*(*/
552 printf(")");
553 break;
554 case ND_OPT_REDIRECTED_HEADER:
555 opr = (struct icmp6_opts_redirect *)op;
556 printf("(redirect)");
557 /* xxx */
558 break;
559 case ND_OPT_MTU:
560 opm = (struct nd_opt_mtu *)op;
561 TCHECK(opm->nd_opt_mtu_mtu);
562 printf("(mtu:"); /*)*/
563 if (op->nd_opt_len != 1) {
564 printf("badlen");
565 /*(*/
566 printf(")");
567 break;
568 }
569 printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
570 if (opm->nd_opt_mtu_len != 1)
571 printf("!");
572 printf(")");
573 break;
574 case ND_OPT_ADVINTERVAL:
575 opa = (struct nd_opt_advinterval *)op;
576 TCHECK(opa->nd_opt_adv_interval);
577 printf("(advint:"); /*)*/
578 printf(" advint=%u",
579 EXTRACT_32BITS(&opa->nd_opt_adv_interval));
580 /*(*/
581 printf(")");
582 break;
583 case ND_OPT_HOMEAGENT_INFO:
584 oph = (struct nd_opt_homeagent_info *)op;
585 TCHECK(oph->nd_opt_hai_lifetime);
586 printf("(ha info:"); /*)*/
587 printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
588 printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
589 printf(")");
590 break;
591 case ND_OPT_ROUTE_INFO:
592 opri = (struct nd_opt_route_info *)op;
593 TCHECK(opri->nd_opt_rti_lifetime);
594 memset(&in6, 0, sizeof(in6));
595 in6p = (struct in6_addr *)(opri + 1);
596 switch (op->nd_opt_len) {
597 case 1:
598 break;
599 case 2:
600 TCHECK2(*in6p, 8);
601 memcpy(&in6, opri + 1, 8);
602 break;
603 case 3:
604 TCHECK(*in6p);
605 memcpy(&in6, opri + 1, sizeof(in6));
606 break;
607 default:
608 goto trunc;
609 }
610 printf("(rtinfo:"); /*)*/
611 printf(" %s/%u", ip6addr_string(&in6),
612 opri->nd_opt_rti_prefixlen);
613 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
614 printf(", lifetime=%s",
615 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
616 /*(*/
617 printf(")");
618 break;
619 default:
620 printf("(unknown opt_type=%d, opt_len=%d)",
621 op->nd_opt_type, op->nd_opt_len);
622 break;
623 }
624
625 cp += op->nd_opt_len << 3;
626 resid -= op->nd_opt_len << 3;
627 }
628 return;
629
630 trunc:
631 fputs("[ndp opt]", stdout);
632 return;
633 #undef ECHECK
634 }
635
636 static void
637 mld6_print(const u_char *bp)
638 {
639 struct mld6_hdr *mp = (struct mld6_hdr *)bp;
640 const u_char *ep;
641
642 /* 'ep' points to the end of available data. */
643 ep = snapend;
644
645 if ((u_char *)mp + sizeof(*mp) > ep)
646 return;
647
648 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
649 printf("addr: %s", ip6addr_string(&mp->mld6_addr));
650 }
651
652 static void
653 dnsname_print(const u_char *cp, const u_char *ep)
654 {
655 int i;
656
657 /* DNS name decoding - no decompression */
658 printf(", \"");
659 while (cp < ep) {
660 i = *cp++;
661 if (i) {
662 if (i > ep - cp) {
663 printf("???");
664 break;
665 }
666 while (i-- && cp < ep) {
667 safeputchar(*cp);
668 cp++;
669 }
670 if (cp + 1 < ep && *cp)
671 printf(".");
672 } else {
673 if (cp == ep) {
674 /* FQDN */
675 printf(".");
676 } else if (cp + 1 == ep && *cp == '\0') {
677 /* truncated */
678 } else {
679 /* invalid */
680 printf("???");
681 }
682 break;
683 }
684 }
685 printf("\"");
686 }
687
688 static void
689 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
690 {
691 struct icmp6_nodeinfo *ni6;
692 struct icmp6_hdr *dp;
693 const u_char *cp;
694 size_t siz, i;
695 int needcomma;
696
697 if (ep < bp)
698 return;
699 dp = (struct icmp6_hdr *)bp;
700 ni6 = (struct icmp6_nodeinfo *)bp;
701 siz = ep - bp;
702
703 switch (ni6->ni_type) {
704 case ICMP6_NI_QUERY:
705 if (siz == sizeof(*dp) + 4) {
706 /* KAME who-are-you */
707 printf("icmp6: who-are-you request");
708 break;
709 }
710 printf("icmp6: node information query");
711
712 TCHECK2(*dp, sizeof(*ni6));
713 ni6 = (struct icmp6_nodeinfo *)dp;
714 printf(" ("); /*)*/
715 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
716 case NI_QTYPE_NOOP:
717 printf("noop");
718 break;
719 case NI_QTYPE_SUPTYPES:
720 printf("supported qtypes");
721 i = EXTRACT_16BITS(&ni6->ni_flags);
722 if (i)
723 printf(" [%s]", (i & 0x01) ? "C" : "");
724 break;
725 break;
726 case NI_QTYPE_FQDN:
727 printf("DNS name");
728 break;
729 case NI_QTYPE_NODEADDR:
730 printf("node addresses");
731 i = ni6->ni_flags;
732 if (!i)
733 break;
734 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
735 printf(" [%s%s%s%s%s%s]",
736 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
737 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
738 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
739 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
740 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
741 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
742 break;
743 default:
744 printf("unknown");
745 break;
746 }
747
748 if (ni6->ni_qtype == NI_QTYPE_NOOP ||
749 ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
750 if (siz != sizeof(*ni6))
751 if (vflag)
752 printf(", invalid len");
753 /*(*/
754 printf(")");
755 break;
756 }
757
758
759 /* XXX backward compat, icmp-name-lookup-03 */
760 if (siz == sizeof(*ni6)) {
761 printf(", 03 draft");
762 /*(*/
763 printf(")");
764 break;
765 }
766
767 switch (ni6->ni_code) {
768 case ICMP6_NI_SUBJ_IPV6:
769 if (!TTEST2(*dp,
770 sizeof(*ni6) + sizeof(struct in6_addr)))
771 break;
772 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
773 if (vflag)
774 printf(", invalid subject len");
775 break;
776 }
777 printf(", subject=%s",
778 getname6((const u_char *)(ni6 + 1)));
779 break;
780 case ICMP6_NI_SUBJ_FQDN:
781 printf(", subject=DNS name");
782 cp = (const u_char *)(ni6 + 1);
783 if (cp[0] == ep - cp - 1) {
784 /* icmp-name-lookup-03, pascal string */
785 if (vflag)
786 printf(", 03 draft");
787 cp++;
788 printf(", \"");
789 while (cp < ep) {
790 safeputchar(*cp);
791 cp++;
792 }
793 printf("\"");
794 } else
795 dnsname_print(cp, ep);
796 break;
797 case ICMP6_NI_SUBJ_IPV4:
798 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
799 break;
800 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
801 if (vflag)
802 printf(", invalid subject len");
803 break;
804 }
805 printf(", subject=%s",
806 getname((const u_char *)(ni6 + 1)));
807 break;
808 default:
809 printf(", unknown subject");
810 break;
811 }
812
813 /*(*/
814 printf(")");
815 break;
816
817 case ICMP6_NI_REPLY:
818 if (icmp6len > siz) {
819 printf("[|icmp6: node information reply]");
820 break;
821 }
822
823 needcomma = 0;
824
825 ni6 = (struct icmp6_nodeinfo *)dp;
826 printf("icmp6: node information reply");
827 printf(" ("); /*)*/
828 switch (ni6->ni_code) {
829 case ICMP6_NI_SUCCESS:
830 if (vflag) {
831 printf("success");
832 needcomma++;
833 }
834 break;
835 case ICMP6_NI_REFUSED:
836 printf("refused");
837 needcomma++;
838 if (siz != sizeof(*ni6))
839 if (vflag)
840 printf(", invalid length");
841 break;
842 case ICMP6_NI_UNKNOWN:
843 printf("unknown");
844 needcomma++;
845 if (siz != sizeof(*ni6))
846 if (vflag)
847 printf(", invalid length");
848 break;
849 }
850
851 if (ni6->ni_code != ICMP6_NI_SUCCESS) {
852 /*(*/
853 printf(")");
854 break;
855 }
856
857 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
858 case NI_QTYPE_NOOP:
859 if (needcomma)
860 printf(", ");
861 printf("noop");
862 if (siz != sizeof(*ni6))
863 if (vflag)
864 printf(", invalid length");
865 break;
866 case NI_QTYPE_SUPTYPES:
867 if (needcomma)
868 printf(", ");
869 printf("supported qtypes");
870 i = EXTRACT_16BITS(&ni6->ni_flags);
871 if (i)
872 printf(" [%s]", (i & 0x01) ? "C" : "");
873 break;
874 case NI_QTYPE_FQDN:
875 if (needcomma)
876 printf(", ");
877 printf("DNS name");
878 cp = (const u_char *)(ni6 + 1) + 4;
879 if (cp[0] == ep - cp - 1) {
880 /* icmp-name-lookup-03, pascal string */
881 if (vflag)
882 printf(", 03 draft");
883 cp++;
884 printf(", \"");
885 while (cp < ep) {
886 safeputchar(*cp);
887 cp++;
888 }
889 printf("\"");
890 } else
891 dnsname_print(cp, ep);
892 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
893 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
894 break;
895 case NI_QTYPE_NODEADDR:
896 if (needcomma)
897 printf(", ");
898 printf("node addresses");
899 i = sizeof(*ni6);
900 while (i < siz) {
901 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
902 break;
903 printf(" %s", getname6(bp + i));
904 i += sizeof(struct in6_addr);
905 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
906 i += sizeof(int32_t);
907 }
908 i = ni6->ni_flags;
909 if (!i)
910 break;
911 printf(" [%s%s%s%s%s%s%s]",
912 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
913 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
914 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
915 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
916 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
917 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
918 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
919 break;
920 default:
921 if (needcomma)
922 printf(", ");
923 printf("unknown");
924 break;
925 }
926
927 /*(*/
928 printf(")");
929 break;
930 }
931 return;
932
933 trunc:
934 fputs("[|icmp6]", stdout);
935 }
936
937 static void
938 icmp6_rrenum_print(u_int icmp6len, const u_char *bp, const u_char *ep)
939 {
940 struct icmp6_router_renum *rr6;
941 struct icmp6_hdr *dp;
942 size_t siz;
943 const char *cp;
944 struct rr_pco_match *match;
945 struct rr_pco_use *use;
946 char hbuf[NI_MAXHOST];
947 int n;
948
949 if (ep < bp)
950 return;
951 dp = (struct icmp6_hdr *)bp;
952 rr6 = (struct icmp6_router_renum *)bp;
953 siz = ep - bp;
954 cp = (const char *)(rr6 + 1);
955
956 TCHECK(rr6->rr_reserved);
957 switch (rr6->rr_code) {
958 case ICMP6_ROUTER_RENUMBERING_COMMAND:
959 printf("router renum: command");
960 break;
961 case ICMP6_ROUTER_RENUMBERING_RESULT:
962 printf("router renum: result");
963 break;
964 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
965 printf("router renum: sequence number reset");
966 break;
967 default:
968 printf("router renum: code-#%d", rr6->rr_code);
969 break;
970 }
971
972 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
973
974 if (vflag) {
975 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
976 printf("["); /*]*/
977 if (rr6->rr_flags) {
978 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
979 F(ICMP6_RR_FLAGS_REQRESULT, "R"),
980 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
981 F(ICMP6_RR_FLAGS_SPECSITE, "S"),
982 F(ICMP6_RR_FLAGS_PREVDONE, "P"));
983 }
984 printf("seg=%u,", rr6->rr_segnum);
985 printf("maxdelay=%u", rr6->rr_maxdelay);
986 if (rr6->rr_reserved)
987 printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
988 /*[*/
989 printf("]");
990 #undef F
991 }
992
993 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
994 match = (struct rr_pco_match *)cp;
995 cp = (const char *)(match + 1);
996
997 TCHECK(match->rpm_prefix);
998
999 if (vflag > 1)
1000 printf("\n\t");
1001 else
1002 printf(" ");
1003 printf("match("); /*)*/
1004 switch (match->rpm_code) {
1005 case RPM_PCO_ADD: printf("add"); break;
1006 case RPM_PCO_CHANGE: printf("change"); break;
1007 case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
1008 default: printf("#%u", match->rpm_code); break;
1009 }
1010
1011 if (vflag) {
1012 printf(",ord=%u", match->rpm_ordinal);
1013 printf(",min=%u", match->rpm_minlen);
1014 printf(",max=%u", match->rpm_maxlen);
1015 }
1016 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
1017 printf(",%s/%u", hbuf, match->rpm_matchlen);
1018 else
1019 printf(",?/%u", match->rpm_matchlen);
1020 /*(*/
1021 printf(")");
1022
1023 n = match->rpm_len - 3;
1024 if (n % 4)
1025 goto trunc;
1026 n /= 4;
1027 while (n-- > 0) {
1028 use = (struct rr_pco_use *)cp;
1029 cp = (const char *)(use + 1);
1030
1031 TCHECK(use->rpu_prefix);
1032
1033 if (vflag > 1)
1034 printf("\n\t");
1035 else
1036 printf(" ");
1037 printf("use("); /*)*/
1038 if (use->rpu_flags) {
1039 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
1040 printf("%s%s,",
1041 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1042 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
1043 #undef F
1044 }
1045 if (vflag) {
1046 printf("mask=0x%x,", use->rpu_ramask);
1047 printf("raflags=0x%x,", use->rpu_raflags);
1048 if (~use->rpu_vltime == 0)
1049 printf("vltime=infty,");
1050 else
1051 printf("vltime=%u,",
1052 EXTRACT_32BITS(&use->rpu_vltime));
1053 if (~use->rpu_pltime == 0)
1054 printf("pltime=infty,");
1055 else
1056 printf("pltime=%u,",
1057 EXTRACT_32BITS(&use->rpu_pltime));
1058 }
1059 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1060 sizeof(hbuf)))
1061 printf("%s/%u/%u", hbuf, use->rpu_uselen,
1062 use->rpu_keeplen);
1063 else
1064 printf("?/%u/%u", use->rpu_uselen,
1065 use->rpu_keeplen);
1066 /*(*/
1067 printf(")");
1068 }
1069 }
1070
1071 return;
1072
1073 trunc:
1074 fputs("[|icmp6]", stdout);
1075 }
1076
1077 #endif /* INET6 */