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