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