print-icmp6.c revision 75115
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
23static const char rcsid[] =
24    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.42 2000/12/13 07:57: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 <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
57void icmp6_opt_print(const u_char *, int);
58void mld6_print(const u_char *);
59static struct udphdr *get_upperlayer(u_char *, int *);
60static void dnsname_print(const u_char *, const u_char *);
61void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
62void 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
68void
69icmp6_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;
326trunc:
327	fputs("[|icmp6]", stdout);
328#if 0
329#undef TCHECK
330#endif
331}
332
333static struct udphdr *
334get_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
406void
407icmp6_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 struct nd_opt_advint *opa;
415	register const u_char *ep;
416	int	opts_len;
417#if 0
418	register const struct ip6_hdr *ip;
419	register const char *str;
420	register const struct ip6_hdr *oip;
421	register const struct udphdr *ouh;
422	register int hlen, dport;
423	char buf[256];
424#endif
425
426#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
427
428	op = (struct nd_opt_hdr *)bp;
429#if 0
430	ip = (struct ip6_hdr *)bp2;
431	oip = &dp->icmp6_ip6;
432	str = buf;
433#endif
434	/* 'ep' points to the end of available data. */
435	ep = snapend;
436
437	ECHECK(op->nd_opt_len);
438	if (resid <= 0)
439		return;
440	switch (op->nd_opt_type) {
441	case ND_OPT_SOURCE_LINKADDR:
442		opl = (struct nd_opt_hdr *)op;
443#if 1
444		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
445			goto trunc;
446#else
447		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
448#endif
449		printf("(src lladdr: %s",	/*)*/
450			etheraddr_string((u_char *)(opl + 1)));
451		if (opl->nd_opt_len != 1)
452			printf("!");
453		/*(*/
454		printf(")");
455		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
456				resid - (op->nd_opt_len << 3));
457		break;
458	case ND_OPT_TARGET_LINKADDR:
459		opl = (struct nd_opt_hdr *)op;
460#if 1
461		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
462			goto trunc;
463#else
464		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
465#endif
466		printf("(tgt lladdr: %s",	/*)*/
467			etheraddr_string((u_char *)(opl + 1)));
468		if (opl->nd_opt_len != 1)
469			printf("!");
470		/*(*/
471		printf(")");
472		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
473				resid - (op->nd_opt_len << 3));
474		break;
475	case ND_OPT_PREFIX_INFORMATION:
476		opp = (struct nd_opt_prefix_info *)op;
477		TCHECK(opp->nd_opt_pi_prefix);
478		printf("(prefix info: ");	/*)*/
479		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
480			printf("L");
481		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
482			printf("A");
483		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
484			printf("R");
485		if (opp->nd_opt_pi_flags_reserved)
486			printf(" ");
487		printf("valid_ltime=");
488		if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
489			printf("infinity");
490		else {
491			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
492		}
493		printf(", ");
494		printf("preffered_ltime=");
495		if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
496			printf("infinity");
497		else {
498			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
499		}
500		printf(", ");
501		printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
502			opp->nd_opt_pi_prefix_len);
503		if (opp->nd_opt_pi_len != 4)
504			printf("!");
505		/*(*/
506		printf(")");
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_REDIRECTED_HEADER:
511		opr = (struct icmp6_opts_redirect *)op;
512		printf("(redirect)");
513		/* xxx */
514		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
515				resid - (op->nd_opt_len << 3));
516		break;
517	case ND_OPT_MTU:
518		opm = (struct nd_opt_mtu *)op;
519		TCHECK(opm->nd_opt_mtu_mtu);
520		printf("(mtu: ");	/*)*/
521		printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
522		if (opm->nd_opt_mtu_len != 1)
523			printf("!");
524		printf(")");
525		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
526				resid - (op->nd_opt_len << 3));
527		break;
528        case ND_OPT_ADVINT:
529		opa = (struct nd_opt_advint *)op;
530		TCHECK(opa->nd_opt_advint_advint);
531		printf("(advint: ");	/*)*/
532		printf("advint=%u",
533		    (u_int32_t)ntohl(opa->nd_opt_advint_advint));
534		/*(*/
535		printf(")");
536		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
537				resid - (op->nd_opt_len << 3));
538		break;
539	default:
540		opts_len = op->nd_opt_len;
541		printf("(unknwon opt_type=%d, opt_len=%d)",
542		       op->nd_opt_type, opts_len);
543		if (opts_len == 0)
544			opts_len = 1; /* XXX */
545		icmp6_opt_print((const u_char *)op + (opts_len << 3),
546				resid - (opts_len << 3));
547		break;
548	}
549	return;
550 trunc:
551	fputs("[ndp opt]", stdout);
552	return;
553#undef ECHECK
554}
555
556void
557mld6_print(register const u_char *bp)
558{
559	register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
560	register const u_char *ep;
561
562	/* 'ep' points to the end of available data. */
563	ep = snapend;
564
565	if ((u_char *)mp + sizeof(*mp) > ep)
566		return;
567
568	printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
569	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
570}
571
572static void
573dnsname_print(const u_char *cp, const u_char *ep)
574{
575	int i;
576
577	/* DNS name decoding - no decompression */
578	printf(", \"");
579	while (cp < ep) {
580		i = *cp++;
581		if (i) {
582			if (i > ep - cp) {
583				printf("???");
584				break;
585			}
586			while (i-- && cp < ep) {
587				safeputchar(*cp);
588				cp++;
589			}
590			if (cp + 1 < ep && *cp)
591				printf(".");
592		} else {
593			if (cp == ep) {
594				/* FQDN */
595				printf(".");
596			} else if (cp + 1 == ep && *cp == '\0') {
597				/* truncated */
598			} else {
599				/* invalid */
600				printf("???");
601			}
602			break;
603		}
604	}
605	printf("\"");
606}
607
608void
609icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
610{
611	struct icmp6_nodeinfo *ni6;
612	struct icmp6_hdr *dp;
613	const u_char *cp;
614	int siz, i;
615	int needcomma;
616
617	dp = (struct icmp6_hdr *)bp;
618	ni6 = (struct icmp6_nodeinfo *)bp;
619	siz = ep - bp;
620
621	switch (ni6->ni_type) {
622	case ICMP6_NI_QUERY:
623		if (siz == sizeof(*dp) + 4) {
624			/* KAME who-are-you */
625			printf("icmp6: who-are-you request");
626			break;
627		}
628		printf("icmp6: node information query");
629
630		TCHECK2(*dp, sizeof(*ni6));
631		ni6 = (struct icmp6_nodeinfo *)dp;
632		printf(" (");	/*)*/
633		switch (ntohs(ni6->ni_qtype)) {
634		case NI_QTYPE_NOOP:
635			printf("noop");
636			break;
637		case NI_QTYPE_SUPTYPES:
638			printf("supported qtypes");
639			i = ntohs(ni6->ni_flags);
640			if (i)
641				printf(" [%s]", (i & 0x01) ? "C" : "");
642			break;
643			break;
644		case NI_QTYPE_FQDN:
645			printf("DNS name");
646			break;
647		case NI_QTYPE_NODEADDR:
648			printf("node addresses");
649			i = ni6->ni_flags;
650			if (!i)
651				break;
652			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
653			printf(" [%s%s%s%s%s%s]",
654			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
655			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
656			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
657			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
658			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
659			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
660			break;
661		default:
662			printf("unknown");
663			break;
664		}
665
666		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
667		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
668			if (siz != sizeof(*ni6))
669				if (vflag)
670					printf(", invalid len");
671			/*(*/
672			printf(")");
673			break;
674		}
675
676
677		/* XXX backward compat, icmp-name-lookup-03 */
678		if (siz == sizeof(*ni6)) {
679			printf(", 03 draft");
680			/*(*/
681			printf(")");
682			break;
683		}
684
685		switch (ni6->ni_code) {
686		case ICMP6_NI_SUBJ_IPV6:
687			if (!TTEST2(*dp,
688			    sizeof(*ni6) + sizeof(struct in6_addr)))
689				break;
690			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
691				if (vflag)
692					printf(", invalid subject len");
693				break;
694			}
695			printf(", subject=%s",
696			    getname6((const u_char *)(ni6 + 1)));
697			break;
698		case ICMP6_NI_SUBJ_FQDN:
699			printf(", subject=DNS name");
700			cp = (const u_char *)(ni6 + 1);
701			if (cp[0] == ep - cp - 1) {
702				/* icmp-name-lookup-03, pascal string */
703				if (vflag)
704					printf(", 03 draft");
705				cp++;
706				printf(", \"");
707				while (cp < ep) {
708					safeputchar(*cp);
709					cp++;
710				}
711				printf("\"");
712			} else
713				dnsname_print(cp, ep);
714			break;
715		case ICMP6_NI_SUBJ_IPV4:
716			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
717				break;
718			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
719				if (vflag)
720					printf(", invalid subject len");
721				break;
722			}
723			printf(", subject=%s",
724			    getname((const u_char *)(ni6 + 1)));
725			break;
726		default:
727			printf(", unknown subject");
728			break;
729		}
730
731		/*(*/
732		printf(")");
733		break;
734
735	case ICMP6_NI_REPLY:
736		if (icmp6len > siz) {
737			printf("[|icmp6: node information reply]");
738			break;
739		}
740
741		needcomma = 0;
742
743		ni6 = (struct icmp6_nodeinfo *)dp;
744		printf("icmp6: node information reply");
745		printf(" (");	/*)*/
746		switch (ni6->ni_code) {
747		case ICMP6_NI_SUCCESS:
748			if (vflag) {
749				printf("success");
750				needcomma++;
751			}
752			break;
753		case ICMP6_NI_REFUSED:
754			printf("refused");
755			needcomma++;
756			if (siz != sizeof(*ni6))
757				if (vflag)
758					printf(", invalid length");
759			break;
760		case ICMP6_NI_UNKNOWN:
761			printf("unknown");
762			needcomma++;
763			if (siz != sizeof(*ni6))
764				if (vflag)
765					printf(", invalid length");
766			break;
767		}
768
769		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
770			/*(*/
771			printf(")");
772			break;
773		}
774
775		switch (ntohs(ni6->ni_qtype)) {
776		case NI_QTYPE_NOOP:
777			if (needcomma)
778				printf(", ");
779			printf("noop");
780			if (siz != sizeof(*ni6))
781				if (vflag)
782					printf(", invalid length");
783			break;
784		case NI_QTYPE_SUPTYPES:
785			if (needcomma)
786				printf(", ");
787			printf("supported qtypes");
788			i = ntohs(ni6->ni_flags);
789			if (i)
790				printf(" [%s]", (i & 0x01) ? "C" : "");
791			break;
792		case NI_QTYPE_FQDN:
793			if (needcomma)
794				printf(", ");
795			printf("DNS name");
796			cp = (const u_char *)(ni6 + 1) + 4;
797			if (cp[0] == ep - cp - 1) {
798				/* icmp-name-lookup-03, pascal string */
799				if (vflag)
800					printf(", 03 draft");
801				cp++;
802				printf(", \"");
803				while (cp < ep) {
804					safeputchar(*cp);
805					cp++;
806				}
807				printf("\"");
808			} else
809				dnsname_print(cp, ep);
810			if ((ntohs(ni6->ni_flags) & 0x01) != 0)
811				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
812			break;
813		case NI_QTYPE_NODEADDR:
814			if (needcomma)
815				printf(", ");
816			printf("node addresses");
817			i = sizeof(*ni6);
818			while (i < siz) {
819				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
820					break;
821				printf(" %s", getname6(bp + i));
822				i += sizeof(struct in6_addr);
823				printf("(%d)", ntohl(*(int32_t *)(bp + i)));
824				i += sizeof(int32_t);
825			}
826			i = ni6->ni_flags;
827			if (!i)
828				break;
829			printf(" [%s%s%s%s%s%s%s]",
830			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
831			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
832			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
833			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
834			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
835			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
836			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
837			break;
838		default:
839			if (needcomma)
840				printf(", ");
841			printf("unknown");
842			break;
843		}
844
845		/*(*/
846		printf(")");
847		break;
848	}
849	return;
850
851trunc:
852	fputs("[|icmp6]", stdout);
853}
854
855void
856icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
857{
858	struct icmp6_router_renum *rr6;
859	struct icmp6_hdr *dp;
860	size_t siz;
861	const char *cp;
862	struct rr_pco_match *match;
863	struct rr_pco_use *use;
864	char hbuf[NI_MAXHOST];
865	int n;
866
867	dp = (struct icmp6_hdr *)bp;
868	rr6 = (struct icmp6_router_renum *)bp;
869	siz = ep - bp;
870	cp = (const char *)(rr6 + 1);
871
872	TCHECK(rr6->rr_reserved);
873	switch (rr6->rr_code) {
874	case ICMP6_ROUTER_RENUMBERING_COMMAND:
875		printf("router renum: command");
876		break;
877	case ICMP6_ROUTER_RENUMBERING_RESULT:
878		printf("router renum: result");
879		break;
880	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
881		printf("router renum: sequence number reset");
882		break;
883	default:
884		printf("router renum: code-#%d", rr6->rr_code);
885		break;
886	}
887
888	printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum));
889
890	if (vflag) {
891#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
892		printf("[");	/*]*/
893		if (rr6->rr_flags) {
894			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
895			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
896			    F(ICMP6_RR_FLAGS_ALLIF, "A"),
897			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
898			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
899		}
900		printf("seg=%u,", rr6->rr_segnum);
901		printf("maxdelay=%u", rr6->rr_maxdelay);
902		if (rr6->rr_reserved)
903			printf("rsvd=0x%x", (u_int16_t)ntohs(rr6->rr_reserved));
904		/*[*/
905		printf("]");
906#undef F
907	}
908
909	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
910		match = (struct rr_pco_match *)cp;
911		cp = (const char *)(match + 1);
912
913		TCHECK(match->rpm_prefix);
914
915		if (vflag)
916			printf("\n\t");
917		else
918			printf(" ");
919		printf("match(");	/*)*/
920		switch (match->rpm_code) {
921		case RPM_PCO_ADD:	printf("add"); break;
922		case RPM_PCO_CHANGE:	printf("change"); break;
923		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
924		default:		printf("#%u", match->rpm_code); break;
925		}
926
927		if (vflag) {
928			printf(",ord=%u", match->rpm_ordinal);
929			printf(",min=%u", match->rpm_minlen);
930			printf(",max=%u", match->rpm_maxlen);
931		}
932		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
933			printf(",%s/%u", hbuf, match->rpm_matchlen);
934		else
935			printf(",?/%u", match->rpm_matchlen);
936		/*(*/
937		printf(")");
938
939		n = match->rpm_len - 3;
940		if (n % 4)
941			goto trunc;
942		n /= 4;
943		while (n-- > 0) {
944			use = (struct rr_pco_use *)cp;
945			cp = (const char *)(use + 1);
946
947			TCHECK(use->rpu_prefix);
948
949			if (vflag)
950				printf("\n\t");
951			else
952				printf(" ");
953			printf("use(");	/*)*/
954			if (use->rpu_flags) {
955#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
956				printf("%s%s,",
957				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
958				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
959#undef F
960			}
961			if (vflag) {
962				printf("mask=0x%x,", use->rpu_ramask);
963				printf("raflags=0x%x,", use->rpu_raflags);
964				if (~use->rpu_vltime == 0)
965					printf("vltime=infty,");
966				else
967					printf("vltime=%u,",
968					    (u_int32_t)ntohl(use->rpu_vltime));
969				if (~use->rpu_pltime == 0)
970					printf("pltime=infty,");
971				else
972					printf("pltime=%u,",
973					    (u_int32_t)ntohl(use->rpu_pltime));
974			}
975			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
976			    sizeof(hbuf)))
977				printf("%s/%u/%u", hbuf, use->rpu_uselen,
978				    use->rpu_keeplen);
979			else
980				printf("?/%u/%u", use->rpu_uselen,
981				    use->rpu_keeplen);
982			/*(*/
983			printf(")");
984		}
985	}
986
987	return;
988
989trunc:
990	fputs("[|icmp6]", stdout);
991}
992
993#endif /* INET6 */
994