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