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