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