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