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