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