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