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