xref: /netbsd/external/bsd/tcpdump/dist/print-icmp6.c (revision c8ac67c2)
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 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-icmp6.c,v 1.14 2021/05/30 21:48:42 thorpej Exp $");
25 #endif
26 
27 /* \summary: IPv6 Internet Control Message Protocol (ICMPv6) printer */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <netdissect-stdinc.h>
34 
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "netdissect.h"
39 #include "addrtoname.h"
40 #include "addrtostr.h"
41 #include "extract.h"
42 
43 #include "ip6.h"
44 #include "ipproto.h"
45 
46 #include "udp.h"
47 #include "ah.h"
48 
49 static const char icmp6_tstr[] = " [|icmp6]";
50 static const char rpl_tstr[] = " [|rpl]";
51 static const char mldv2_tstr[] = " [|mldv2]";
52 
53 /*	NetBSD: icmp6.h,v 1.13 2000/08/03 16:30:37 itojun Exp 	*/
54 /*	$KAME: icmp6.h,v 1.22 2000/08/03 15:25:16 jinmei Exp $	*/
55 
56 /*
57  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
58  * All rights reserved.
59  *
60  * Redistribution and use in source and binary forms, with or without
61  * modification, are permitted provided that the following conditions
62  * are met:
63  * 1. Redistributions of source code must retain the above copyright
64  *    notice, this list of conditions and the following disclaimer.
65  * 2. Redistributions in binary form must reproduce the above copyright
66  *    notice, this list of conditions and the following disclaimer in the
67  *    documentation and/or other materials provided with the distribution.
68  * 3. Neither the name of the project nor the names of its contributors
69  *    may be used to endorse or promote products derived from this software
70  *    without specific prior written permission.
71  *
72  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
73  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
74  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
76  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
77  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
78  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
80  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
81  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82  * SUCH DAMAGE.
83  */
84 
85 struct icmp6_hdr {
86 	uint8_t		icmp6_type;	/* type field */
87 	uint8_t		icmp6_code;	/* code field */
88 	uint16_t	icmp6_cksum;	/* checksum field */
89 	union {
90 		uint32_t	icmp6_un_data32[1]; /* type-specific field */
91 		uint16_t	icmp6_un_data16[2]; /* type-specific field */
92 		uint8_t		icmp6_un_data8[4];  /* type-specific field */
93 	} icmp6_dataun;
94 } UNALIGNED;
95 
96 #define icmp6_data32	icmp6_dataun.icmp6_un_data32
97 #define icmp6_data16	icmp6_dataun.icmp6_un_data16
98 #define icmp6_data8	icmp6_dataun.icmp6_un_data8
99 #define icmp6_pptr	icmp6_data32[0]		/* parameter prob */
100 #define icmp6_mtu	icmp6_data32[0]		/* packet too big */
101 #define icmp6_id	icmp6_data16[0]		/* echo request/reply */
102 #define icmp6_seq	icmp6_data16[1]		/* echo request/reply */
103 #define icmp6_maxdelay	icmp6_data16[0]		/* mcast group membership */
104 
105 #define ICMP6_DST_UNREACH		1	/* dest unreachable, codes: */
106 #define ICMP6_PACKET_TOO_BIG		2	/* packet too big */
107 #define ICMP6_TIME_EXCEEDED		3	/* time exceeded, code: */
108 #define ICMP6_PARAM_PROB		4	/* ip6 header bad */
109 
110 #define ICMP6_ECHO_REQUEST		128	/* echo service */
111 #define ICMP6_ECHO_REPLY		129	/* echo reply */
112 #define ICMP6_MEMBERSHIP_QUERY		130	/* group membership query */
113 #define MLD6_LISTENER_QUERY		130 	/* multicast listener query */
114 #define ICMP6_MEMBERSHIP_REPORT		131	/* group membership report */
115 #define MLD6_LISTENER_REPORT		131	/* multicast listener report */
116 #define ICMP6_MEMBERSHIP_REDUCTION	132	/* group membership termination */
117 #define MLD6_LISTENER_DONE		132	/* multicast listener done */
118 
119 #define ND_ROUTER_SOLICIT		133	/* router solicitation */
120 #define ND_ROUTER_ADVERT		134	/* router advertisement */
121 #define ND_NEIGHBOR_SOLICIT		135	/* neighbor solicitation */
122 #define ND_NEIGHBOR_ADVERT		136	/* neighbor advertisement */
123 #define ND_REDIRECT			137	/* redirect */
124 
125 #define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */
126 
127 #define ICMP6_WRUREQUEST		139	/* who are you request */
128 #define ICMP6_WRUREPLY			140	/* who are you reply */
129 #define ICMP6_FQDN_QUERY		139	/* FQDN query */
130 #define ICMP6_FQDN_REPLY		140	/* FQDN reply */
131 #define ICMP6_NI_QUERY			139	/* node information request */
132 #define ICMP6_NI_REPLY			140	/* node information reply */
133 #define IND_SOLICIT			141	/* inverse neighbor solicitation */
134 #define IND_ADVERT			142	/* inverse neighbor advertisement */
135 
136 #define ICMP6_V2_MEMBERSHIP_REPORT	143	/* v2 membership report */
137 #define MLDV2_LISTENER_REPORT		143	/* v2 multicast listener report */
138 #define ICMP6_HADISCOV_REQUEST		144
139 #define ICMP6_HADISCOV_REPLY		145
140 #define ICMP6_MOBILEPREFIX_SOLICIT	146
141 #define ICMP6_MOBILEPREFIX_ADVERT	147
142 
143 #define MLD6_MTRACE_RESP		200	/* mtrace response(to sender) */
144 #define MLD6_MTRACE			201	/* mtrace messages */
145 
146 #define ICMP6_MAXTYPE			201
147 
148 #define ICMP6_DST_UNREACH_NOROUTE	0	/* no route to destination */
149 #define ICMP6_DST_UNREACH_ADMIN	 	1	/* administratively prohibited */
150 #define ICMP6_DST_UNREACH_NOTNEIGHBOR	2	/* not a neighbor(obsolete) */
151 #define ICMP6_DST_UNREACH_BEYONDSCOPE	2	/* beyond scope of source address */
152 #define ICMP6_DST_UNREACH_ADDR		3	/* address unreachable */
153 #define ICMP6_DST_UNREACH_NOPORT	4	/* port unreachable */
154 
155 #define ICMP6_TIME_EXCEED_TRANSIT 	0	/* ttl==0 in transit */
156 #define ICMP6_TIME_EXCEED_REASSEMBLY	1	/* ttl==0 in reass */
157 
158 #define ICMP6_PARAMPROB_HEADER 	 	0	/* erroneous header field */
159 #define ICMP6_PARAMPROB_NEXTHEADER	1	/* unrecognized next header */
160 #define ICMP6_PARAMPROB_OPTION		2	/* unrecognized option */
161 
162 #define ICMP6_INFOMSG_MASK		0x80	/* all informational messages */
163 
164 #define ICMP6_NI_SUBJ_IPV6	0	/* Query Subject is an IPv6 address */
165 #define ICMP6_NI_SUBJ_FQDN	1	/* Query Subject is a Domain name */
166 #define ICMP6_NI_SUBJ_IPV4	2	/* Query Subject is an IPv4 address */
167 
168 #define ICMP6_NI_SUCCESS	0	/* node information successful reply */
169 #define ICMP6_NI_REFUSED	1	/* node information request is refused */
170 #define ICMP6_NI_UNKNOWN	2	/* unknown Qtype */
171 
172 #define ICMP6_ROUTER_RENUMBERING_COMMAND  0	/* rr command */
173 #define ICMP6_ROUTER_RENUMBERING_RESULT   1	/* rr result */
174 #define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET   255	/* rr seq num reset */
175 
176 /* Used in kernel only */
177 #define ND_REDIRECT_ONLINK	0	/* redirect to an on-link node */
178 #define ND_REDIRECT_ROUTER	1	/* redirect to a better router */
179 
180 /*
181  * Multicast Listener Discovery
182  */
183 struct mld6_hdr {
184 	struct icmp6_hdr	mld6_hdr;
185 	struct in6_addr		mld6_addr; /* multicast address */
186 } UNALIGNED;
187 
188 #define mld6_type	mld6_hdr.icmp6_type
189 #define mld6_code	mld6_hdr.icmp6_code
190 #define mld6_cksum	mld6_hdr.icmp6_cksum
191 #define mld6_maxdelay	mld6_hdr.icmp6_data16[0]
192 #define mld6_reserved	mld6_hdr.icmp6_data16[1]
193 
194 #define MLD_MINLEN	24
195 #define MLDV2_MINLEN	28
196 
197 /*
198  * Neighbor Discovery
199  */
200 
201 struct nd_router_solicit {	/* router solicitation */
202 	struct icmp6_hdr 	nd_rs_hdr;
203 	/* could be followed by options */
204 } UNALIGNED;
205 
206 #define nd_rs_type	nd_rs_hdr.icmp6_type
207 #define nd_rs_code	nd_rs_hdr.icmp6_code
208 #define nd_rs_cksum	nd_rs_hdr.icmp6_cksum
209 #define nd_rs_reserved	nd_rs_hdr.icmp6_data32[0]
210 
211 struct nd_router_advert {	/* router advertisement */
212 	struct icmp6_hdr	nd_ra_hdr;
213 	uint32_t		nd_ra_reachable;	/* reachable time */
214 	uint32_t		nd_ra_retransmit;	/* retransmit timer */
215 	/* could be followed by options */
216 } UNALIGNED;
217 
218 #define nd_ra_type		nd_ra_hdr.icmp6_type
219 #define nd_ra_code		nd_ra_hdr.icmp6_code
220 #define nd_ra_cksum		nd_ra_hdr.icmp6_cksum
221 #define nd_ra_curhoplimit	nd_ra_hdr.icmp6_data8[0]
222 #define nd_ra_flags_reserved	nd_ra_hdr.icmp6_data8[1]
223 #define ND_RA_FLAG_MANAGED	0x80
224 #define ND_RA_FLAG_OTHER	0x40
225 #define ND_RA_FLAG_HOME_AGENT	0x20
226 
227 /*
228  * Router preference values based on draft-draves-ipngwg-router-selection-01.
229  * These are non-standard definitions.
230  */
231 #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
232 
233 #define ND_RA_FLAG_RTPREF_HIGH	0x08 /* 00001000 */
234 #define ND_RA_FLAG_RTPREF_MEDIUM	0x00 /* 00000000 */
235 #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
236 #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
237 
238 #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
239 
240 struct nd_neighbor_solicit {	/* neighbor solicitation */
241 	struct icmp6_hdr	nd_ns_hdr;
242 	struct in6_addr		nd_ns_target;	/*target address */
243 	/* could be followed by options */
244 } UNALIGNED;
245 
246 #define nd_ns_type		nd_ns_hdr.icmp6_type
247 #define nd_ns_code		nd_ns_hdr.icmp6_code
248 #define nd_ns_cksum		nd_ns_hdr.icmp6_cksum
249 #define nd_ns_reserved		nd_ns_hdr.icmp6_data32[0]
250 
251 struct nd_neighbor_advert {	/* neighbor advertisement */
252 	struct icmp6_hdr	nd_na_hdr;
253 	struct in6_addr		nd_na_target;	/* target address */
254 	/* could be followed by options */
255 } UNALIGNED;
256 
257 #define nd_na_type		nd_na_hdr.icmp6_type
258 #define nd_na_code		nd_na_hdr.icmp6_code
259 #define nd_na_cksum		nd_na_hdr.icmp6_cksum
260 #define nd_na_flags_reserved	nd_na_hdr.icmp6_data32[0]
261 
262 #define ND_NA_FLAG_ROUTER		0x80000000
263 #define ND_NA_FLAG_SOLICITED		0x40000000
264 #define ND_NA_FLAG_OVERRIDE		0x20000000
265 
266 struct nd_redirect {		/* redirect */
267 	struct icmp6_hdr	nd_rd_hdr;
268 	struct in6_addr		nd_rd_target;	/* target address */
269 	struct in6_addr		nd_rd_dst;	/* destination address */
270 	/* could be followed by options */
271 } UNALIGNED;
272 
273 #define nd_rd_type		nd_rd_hdr.icmp6_type
274 #define nd_rd_code		nd_rd_hdr.icmp6_code
275 #define nd_rd_cksum		nd_rd_hdr.icmp6_cksum
276 #define nd_rd_reserved		nd_rd_hdr.icmp6_data32[0]
277 
278 struct nd_opt_hdr {		/* Neighbor discovery option header */
279 	uint8_t		nd_opt_type;
280 	uint8_t		nd_opt_len;
281 	/* followed by option specific data*/
282 };
283 
284 #define ND_OPT_SOURCE_LINKADDR		1
285 #define ND_OPT_TARGET_LINKADDR		2
286 #define ND_OPT_PREFIX_INFORMATION	3
287 #define ND_OPT_REDIRECTED_HEADER	4
288 #define ND_OPT_MTU			5
289 #define ND_OPT_ADVINTERVAL		7
290 #define ND_OPT_HOMEAGENT_INFO		8
291 #define ND_OPT_ROUTE_INFO		24	/* RFC4191 */
292 #define ND_OPT_RDNSS			25
293 #define ND_OPT_DNSSL			31
294 
295 struct nd_opt_prefix_info {	/* prefix information */
296 	nd_uint8_t		nd_opt_pi_type;
297 	nd_uint8_t		nd_opt_pi_len;
298 	nd_uint8_t		nd_opt_pi_prefix_len;
299 	nd_uint8_t		nd_opt_pi_flags_reserved;
300 	nd_uint32_t		nd_opt_pi_valid_time;
301 	nd_uint32_t		nd_opt_pi_preferred_time;
302 	nd_uint32_t		nd_opt_pi_reserved2;
303 	struct in6_addr	nd_opt_pi_prefix;
304 } UNALIGNED;
305 
306 #define ND_OPT_PI_FLAG_ONLINK		0x80
307 #define ND_OPT_PI_FLAG_AUTO		0x40
308 #define ND_OPT_PI_FLAG_ROUTER		0x20	/*2292bis*/
309 
310 struct nd_opt_rd_hdr {         /* redirected header */
311 	uint8_t		nd_opt_rh_type;
312 	uint8_t		nd_opt_rh_len;
313 	uint16_t	nd_opt_rh_reserved1;
314 	uint32_t	nd_opt_rh_reserved2;
315 	/* followed by IP header and data */
316 } UNALIGNED;
317 
318 struct nd_opt_mtu {		/* MTU option */
319 	uint8_t		nd_opt_mtu_type;
320 	uint8_t		nd_opt_mtu_len;
321 	uint16_t	nd_opt_mtu_reserved;
322 	uint32_t	nd_opt_mtu_mtu;
323 } UNALIGNED;
324 
325 struct nd_opt_rdnss {		/* RDNSS RFC 6106 5.1 */
326 	uint8_t		nd_opt_rdnss_type;
327 	uint8_t		nd_opt_rdnss_len;
328 	uint16_t	nd_opt_rdnss_reserved;
329 	uint32_t	nd_opt_rdnss_lifetime;
330 	struct in6_addr nd_opt_rdnss_addr[1];	/* variable-length */
331 } UNALIGNED;
332 
333 struct nd_opt_dnssl {		/* DNSSL RFC 6106 5.2 */
334 	uint8_t  nd_opt_dnssl_type;
335 	uint8_t  nd_opt_dnssl_len;
336 	uint16_t nd_opt_dnssl_reserved;
337 	uint32_t nd_opt_dnssl_lifetime;
338 	/* followed by list of DNS search domains, variable-length */
339 } UNALIGNED;
340 
341 struct nd_opt_advinterval {	/* Advertisement interval option */
342 	uint8_t		nd_opt_adv_type;
343 	uint8_t		nd_opt_adv_len;
344 	uint16_t	nd_opt_adv_reserved;
345 	uint32_t	nd_opt_adv_interval;
346 } UNALIGNED;
347 
348 struct nd_opt_homeagent_info {	/* Home Agent info */
349 	uint8_t		nd_opt_hai_type;
350 	uint8_t		nd_opt_hai_len;
351 	uint16_t	nd_opt_hai_reserved;
352 	int16_t		nd_opt_hai_preference;
353 	uint16_t	nd_opt_hai_lifetime;
354 } UNALIGNED;
355 
356 struct nd_opt_route_info {	/* route info */
357 	uint8_t		nd_opt_rti_type;
358 	uint8_t		nd_opt_rti_len;
359 	uint8_t		nd_opt_rti_prefixlen;
360 	uint8_t		nd_opt_rti_flags;
361 	uint32_t	nd_opt_rti_lifetime;
362 	/* prefix follows */
363 } UNALIGNED;
364 
365 /*
366  * icmp6 namelookup
367  */
368 
369 struct icmp6_namelookup {
370 	struct icmp6_hdr 	icmp6_nl_hdr;
371 	uint8_t		icmp6_nl_nonce[8];
372 	int32_t		icmp6_nl_ttl;
373 #if 0
374 	uint8_t		icmp6_nl_len;
375 	uint8_t		icmp6_nl_name[3];
376 #endif
377 	/* could be followed by options */
378 } UNALIGNED;
379 
380 /*
381  * icmp6 node information
382  */
383 struct icmp6_nodeinfo {
384 	struct icmp6_hdr icmp6_ni_hdr;
385 	uint8_t icmp6_ni_nonce[8];
386 	/* could be followed by reply data */
387 } UNALIGNED;
388 
389 #define ni_type		icmp6_ni_hdr.icmp6_type
390 #define ni_code		icmp6_ni_hdr.icmp6_code
391 #define ni_cksum	icmp6_ni_hdr.icmp6_cksum
392 #define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
393 #define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
394 
395 #define NI_QTYPE_NOOP		0 /* NOOP  */
396 #define NI_QTYPE_SUPTYPES	1 /* Supported Qtypes */
397 #define NI_QTYPE_FQDN		2 /* FQDN (draft 04) */
398 #define NI_QTYPE_DNSNAME	2 /* DNS Name */
399 #define NI_QTYPE_NODEADDR	3 /* Node Addresses */
400 #define NI_QTYPE_IPV4ADDR	4 /* IPv4 Addresses */
401 
402 /* network endian */
403 #define NI_SUPTYPE_FLAG_COMPRESS	((uint16_t)htons(0x1))
404 #define NI_FQDN_FLAG_VALIDTTL		((uint16_t)htons(0x1))
405 
406 /* network endian */
407 #define NI_NODEADDR_FLAG_TRUNCATE	((uint16_t)htons(0x1))
408 #define NI_NODEADDR_FLAG_ALL		((uint16_t)htons(0x2))
409 #define NI_NODEADDR_FLAG_COMPAT		((uint16_t)htons(0x4))
410 #define NI_NODEADDR_FLAG_LINKLOCAL	((uint16_t)htons(0x8))
411 #define NI_NODEADDR_FLAG_SITELOCAL	((uint16_t)htons(0x10))
412 #define NI_NODEADDR_FLAG_GLOBAL		((uint16_t)htons(0x20))
413 #define NI_NODEADDR_FLAG_ANYCAST	((uint16_t)htons(0x40)) /* just experimental. not in spec */
414 
415 struct ni_reply_fqdn {
416 	uint32_t ni_fqdn_ttl;	/* TTL */
417 	uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */
418 	uint8_t ni_fqdn_name[3]; /* XXX: alignment */
419 } UNALIGNED;
420 
421 /*
422  * Router Renumbering. as router-renum-08.txt
423  */
424 struct icmp6_router_renum {	/* router renumbering header */
425 	struct icmp6_hdr	rr_hdr;
426 	uint8_t		rr_segnum;
427 	uint8_t		rr_flags;
428 	uint16_t	rr_maxdelay;
429 	uint32_t	rr_reserved;
430 } UNALIGNED;
431 #define ICMP6_RR_FLAGS_TEST		0x80
432 #define ICMP6_RR_FLAGS_REQRESULT	0x40
433 #define ICMP6_RR_FLAGS_FORCEAPPLY	0x20
434 #define ICMP6_RR_FLAGS_SPECSITE		0x10
435 #define ICMP6_RR_FLAGS_PREVDONE		0x08
436 
437 #define rr_type		rr_hdr.icmp6_type
438 #define rr_code		rr_hdr.icmp6_code
439 #define rr_cksum	rr_hdr.icmp6_cksum
440 #define rr_seqnum 	rr_hdr.icmp6_data32[0]
441 
442 struct rr_pco_match {		/* match prefix part */
443 	uint8_t		rpm_code;
444 	uint8_t		rpm_len;
445 	uint8_t		rpm_ordinal;
446 	uint8_t		rpm_matchlen;
447 	uint8_t		rpm_minlen;
448 	uint8_t		rpm_maxlen;
449 	uint16_t	rpm_reserved;
450 	struct	in6_addr	rpm_prefix;
451 } UNALIGNED;
452 
453 #define RPM_PCO_ADD		1
454 #define RPM_PCO_CHANGE		2
455 #define RPM_PCO_SETGLOBAL	3
456 #define RPM_PCO_MAX		4
457 
458 struct rr_pco_use {		/* use prefix part */
459 	uint8_t		rpu_uselen;
460 	uint8_t		rpu_keeplen;
461 	uint8_t		rpu_ramask;
462 	uint8_t		rpu_raflags;
463 	uint32_t	rpu_vltime;
464 	uint32_t	rpu_pltime;
465 	uint32_t	rpu_flags;
466 	struct	in6_addr rpu_prefix;
467 } UNALIGNED;
468 #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK	0x80
469 #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO	0x40
470 
471 /* network endian */
472 #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME     ((uint32_t)htonl(0x80000000))
473 #define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME     ((uint32_t)htonl(0x40000000))
474 
475 struct rr_result {		/* router renumbering result message */
476 	uint16_t	rrr_flags;
477 	uint8_t		rrr_ordinal;
478 	uint8_t		rrr_matchedlen;
479 	uint32_t	rrr_ifid;
480 	struct	in6_addr rrr_prefix;
481 } UNALIGNED;
482 /* network endian */
483 #define ICMP6_RR_RESULT_FLAGS_OOB		((uint16_t)htons(0x0002))
484 #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		((uint16_t)htons(0x0001))
485 
486 static const char *get_rtpref(u_int);
487 static const char *get_lifetime(uint32_t);
488 static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
489 static void icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
490 static void mld6_print(netdissect_options *ndo, const u_char *);
491 static void mldv2_report_print(netdissect_options *ndo, const u_char *, u_int);
492 static void mldv2_query_print(netdissect_options *ndo, const u_char *, u_int);
493 static const struct udphdr *get_upperlayer(netdissect_options *ndo, const u_char *, u_int *);
494 static void dnsname_print(netdissect_options *ndo, const u_char *, const u_char *);
495 static void icmp6_nodeinfo_print(netdissect_options *ndo, u_int, const u_char *, const u_char *);
496 static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_char *);
497 
498 #ifndef abs
499 #define abs(a)	((0 < (a)) ? (a) : -(a))
500 #endif
501 
502 #include "rpl.h"
503 
504 static const struct tok icmp6_type_values[] = {
505     { ICMP6_DST_UNREACH, "destination unreachable"},
506     { ICMP6_PACKET_TOO_BIG, "packet too big"},
507     { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
508     { ICMP6_PARAM_PROB, "parameter problem"},
509     { ICMP6_ECHO_REQUEST, "echo request"},
510     { ICMP6_ECHO_REPLY, "echo reply"},
511     { MLD6_LISTENER_QUERY, "multicast listener query"},
512     { MLD6_LISTENER_REPORT, "multicast listener report"},
513     { MLD6_LISTENER_DONE, "multicast listener done"},
514     { ND_ROUTER_SOLICIT, "router solicitation"},
515     { ND_ROUTER_ADVERT, "router advertisement"},
516     { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
517     { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
518     { ND_REDIRECT, "redirect"},
519     { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
520     { IND_SOLICIT, "inverse neighbor solicitation"},
521     { IND_ADVERT, "inverse neighbor advertisement"},
522     { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
523     { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
524     { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
525     { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
526     { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
527     { ICMP6_WRUREQUEST, "who-are-you request"},
528     { ICMP6_WRUREPLY, "who-are-you reply"},
529     { ICMP6_NI_QUERY, "node information query"},
530     { ICMP6_NI_REPLY, "node information reply"},
531     { MLD6_MTRACE, "mtrace message"},
532     { MLD6_MTRACE_RESP, "mtrace response"},
533     { ND_RPL_MESSAGE,   "RPL"},
534     { 0,	NULL }
535 };
536 
537 static const struct tok icmp6_dst_unreach_code_values[] = {
538     { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
539     { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
540     { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
541     { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
542     { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
543     { 0,	NULL }
544 };
545 
546 static const struct tok icmp6_opt_pi_flag_values[] = {
547     { ND_OPT_PI_FLAG_ONLINK, "onlink" },
548     { ND_OPT_PI_FLAG_AUTO, "auto" },
549     { ND_OPT_PI_FLAG_ROUTER, "router" },
550     { 0,	NULL }
551 };
552 
553 static const struct tok icmp6_opt_ra_flag_values[] = {
554     { ND_RA_FLAG_MANAGED, "managed" },
555     { ND_RA_FLAG_OTHER, "other stateful"},
556     { ND_RA_FLAG_HOME_AGENT, "home agent"},
557     { 0,	NULL }
558 };
559 
560 static const struct tok icmp6_nd_na_flag_values[] = {
561     { ND_NA_FLAG_ROUTER, "router" },
562     { ND_NA_FLAG_SOLICITED, "solicited" },
563     { ND_NA_FLAG_OVERRIDE, "override" },
564     { 0,	NULL }
565 };
566 
567 
568 static const struct tok icmp6_opt_values[] = {
569    { ND_OPT_SOURCE_LINKADDR, "source link-address"},
570    { ND_OPT_TARGET_LINKADDR, "destination link-address"},
571    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
572    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
573    { ND_OPT_MTU, "mtu"},
574    { ND_OPT_RDNSS, "rdnss"},
575    { ND_OPT_DNSSL, "dnssl"},
576    { ND_OPT_ADVINTERVAL, "advertisement interval"},
577    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
578    { ND_OPT_ROUTE_INFO, "route info"},
579    { 0,	NULL }
580 };
581 
582 /* mldv2 report types */
583 static const struct tok mldv2report2str[] = {
584 	{ 1,	"is_in" },
585 	{ 2,	"is_ex" },
586 	{ 3,	"to_in" },
587 	{ 4,	"to_ex" },
588 	{ 5,	"allow" },
589 	{ 6,	"block" },
590 	{ 0,	NULL }
591 };
592 
593 static const char *
get_rtpref(u_int v)594 get_rtpref(u_int v)
595 {
596 	static const char *rtpref_str[] = {
597 		"medium",		/* 00 */
598 		"high",			/* 01 */
599 		"rsv",			/* 10 */
600 		"low"			/* 11 */
601 	};
602 
603 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
604 }
605 
606 static const char *
get_lifetime(uint32_t v)607 get_lifetime(uint32_t v)
608 {
609 	static char buf[20];
610 
611 	if (v == (uint32_t)~0UL)
612 		return "infinity";
613 	else {
614 		snprintf(buf, sizeof(buf), "%us", v);
615 		return buf;
616 	}
617 }
618 
619 static void
print_lladdr(netdissect_options * ndo,const uint8_t * p,size_t l)620 print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
621 {
622 	const uint8_t *ep, *q;
623 
624 	q = p;
625 	ep = p + l;
626 	while (l > 0 && q < ep) {
627 		if (q > p)
628                         ND_PRINT((ndo,":"));
629 		ND_PRINT((ndo,"%02x", *q++));
630 		l--;
631 	}
632 }
633 
icmp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct icmp6_hdr * icp,u_int len)634 static int icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
635 	const struct icmp6_hdr *icp, u_int len)
636 {
637 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len,
638 				IPPROTO_ICMPV6);
639 }
640 
641 static const struct tok rpl_mop_values[] = {
642         { RPL_DIO_NONSTORING,         "nonstoring"},
643         { RPL_DIO_STORING,            "storing"},
644         { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"},
645         { RPL_DIO_STORING_MULTICAST,  "storing-multicast"},
646         { 0, NULL},
647 };
648 
649 static const struct tok rpl_subopt_values[] = {
650         { RPL_OPT_PAD0, "pad0"},
651         { RPL_OPT_PADN, "padN"},
652         { RPL_DIO_METRICS, "metrics"},
653         { RPL_DIO_ROUTINGINFO, "routinginfo"},
654         { RPL_DIO_CONFIG,    "config"},
655         { RPL_DAO_RPLTARGET, "rpltarget"},
656         { RPL_DAO_TRANSITINFO, "transitinfo"},
657         { RPL_DIO_DESTPREFIX, "destprefix"},
658         { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"},
659         { 0, NULL},
660 };
661 
662 static void
rpl_dio_printopt(netdissect_options * ndo,const struct rpl_dio_genoption * opt,u_int length)663 rpl_dio_printopt(netdissect_options *ndo,
664                  const struct rpl_dio_genoption *opt,
665                  u_int length)
666 {
667         if(length < RPL_DIO_GENOPTION_LEN) return;
668         length -= RPL_DIO_GENOPTION_LEN;
669 
670         ND_TCHECK(opt->rpl_dio_len);
671 
672         while((opt->rpl_dio_type == RPL_OPT_PAD0 &&
673                (const u_char *)opt < ndo->ndo_snapend) ||
674               ND_TTEST2(*opt,(opt->rpl_dio_len+2))) {
675 
676                 unsigned int optlen = opt->rpl_dio_len+2;
677                 if(opt->rpl_dio_type == RPL_OPT_PAD0) {
678                         optlen = 1;
679                         ND_PRINT((ndo, " opt:pad0"));
680                 } else {
681                         ND_PRINT((ndo, " opt:%s len:%u ",
682                                   tok2str(rpl_subopt_values, "subopt:%u", opt->rpl_dio_type),
683                                   optlen));
684                         if(ndo->ndo_vflag > 2) {
685                                 unsigned int paylen = opt->rpl_dio_len;
686                                 if(paylen > length) paylen = length;
687                                 hex_print(ndo,
688                                           " ",
689                                           ((const uint8_t *)opt) + RPL_DIO_GENOPTION_LEN,  /* content of DIO option */
690                                           paylen);
691                         }
692                 }
693                 opt = (const struct rpl_dio_genoption *)(((const char *)opt) + optlen);
694                 length -= optlen;
695                 ND_TCHECK(opt->rpl_dio_len);
696         }
697         return;
698 trunc:
699 	ND_PRINT((ndo, "%s", rpl_tstr));
700 	return;
701 }
702 
703 static void
rpl_dio_print(netdissect_options * ndo,const u_char * bp,u_int length)704 rpl_dio_print(netdissect_options *ndo,
705               const u_char *bp, u_int length)
706 {
707         const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp;
708         const char *dagid_str;
709 
710         ND_TCHECK(*dio);
711         dagid_str = ip6addr_string (ndo, dio->rpl_dagid);
712 
713         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]",
714                   dagid_str,
715                   dio->rpl_dtsn,
716                   dio->rpl_instanceid,
717                   EXTRACT_16BITS(&dio->rpl_dagrank),
718                   RPL_DIO_GROUNDED(dio->rpl_mopprf) ? "grounded,":"",
719                   tok2str(rpl_mop_values, "mop%u", RPL_DIO_MOP(dio->rpl_mopprf)),
720                   RPL_DIO_PRF(dio->rpl_mopprf)));
721 
722         if(ndo->ndo_vflag > 1) {
723                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)&dio[1];
724                 rpl_dio_printopt(ndo, opt, length);
725         }
726 	return;
727 trunc:
728 	ND_PRINT((ndo, "%s", rpl_tstr));
729 	return;
730 }
731 
732 static void
rpl_dao_print(netdissect_options * ndo,const u_char * bp,u_int length)733 rpl_dao_print(netdissect_options *ndo,
734               const u_char *bp, u_int length)
735 {
736         const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp;
737         const char *dagid_str = "<elided>";
738 
739         ND_TCHECK(*dao);
740         if (length < ND_RPL_DAO_MIN_LEN)
741         	goto tooshort;
742 
743         bp += ND_RPL_DAO_MIN_LEN;
744         length -= ND_RPL_DAO_MIN_LEN;
745         if(RPL_DAO_D(dao->rpl_flags)) {
746                 ND_TCHECK2(dao->rpl_dagid, DAGID_LEN);
747                 if (length < DAGID_LEN)
748                 	goto tooshort;
749                 dagid_str = ip6addr_string (ndo, dao->rpl_dagid);
750                 bp += DAGID_LEN;
751                 length -= DAGID_LEN;
752         }
753 
754         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u%s%s,%02x]",
755                   dagid_str,
756                   dao->rpl_daoseq,
757                   dao->rpl_instanceid,
758                   RPL_DAO_K(dao->rpl_flags) ? ",acK":"",
759                   RPL_DAO_D(dao->rpl_flags) ? ",Dagid":"",
760                   dao->rpl_flags));
761 
762         if(ndo->ndo_vflag > 1) {
763                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
764                 rpl_dio_printopt(ndo, opt, length);
765         }
766 	return;
767 
768 trunc:
769 	ND_PRINT((ndo, "%s", rpl_tstr));
770 	return;
771 
772 tooshort:
773 	ND_PRINT((ndo," [|length too short]"));
774 	return;
775 }
776 
777 static void
rpl_daoack_print(netdissect_options * ndo,const u_char * bp,u_int length)778 rpl_daoack_print(netdissect_options *ndo,
779                  const u_char *bp, u_int length)
780 {
781         const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp;
782         const char *dagid_str = "<elided>";
783 
784         ND_TCHECK2(*daoack, ND_RPL_DAOACK_MIN_LEN);
785         if (length < ND_RPL_DAOACK_MIN_LEN)
786         	goto tooshort;
787 
788         bp += ND_RPL_DAOACK_MIN_LEN;
789         length -= ND_RPL_DAOACK_MIN_LEN;
790         if(RPL_DAOACK_D(daoack->rpl_flags)) {
791                 ND_TCHECK2(daoack->rpl_dagid, DAGID_LEN);
792                 if (length < DAGID_LEN)
793                 	goto tooshort;
794                 dagid_str = ip6addr_string (ndo, daoack->rpl_dagid);
795                 bp += DAGID_LEN;
796                 length -= DAGID_LEN;
797         }
798 
799         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,status:%u]",
800                   dagid_str,
801                   daoack->rpl_daoseq,
802                   daoack->rpl_instanceid,
803                   daoack->rpl_status));
804 
805         /* no officially defined options for DAOACK, but print any we find */
806         if(ndo->ndo_vflag > 1) {
807                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
808                 rpl_dio_printopt(ndo, opt, length);
809         }
810 	return;
811 
812 trunc:
813 	ND_PRINT((ndo, "%s", rpl_tstr));
814 	return;
815 
816 tooshort:
817 	ND_PRINT((ndo," [|dao-length too short]"));
818 	return;
819 }
820 
821 UNALIGNED_OK
822 static void
rpl_print(netdissect_options * ndo,const struct icmp6_hdr * hdr,const u_char * bp,u_int length)823 rpl_print(netdissect_options *ndo,
824           const struct icmp6_hdr *hdr,
825           const u_char *bp, u_int length)
826 {
827         int secured = hdr->icmp6_code & 0x80;
828         int basecode= hdr->icmp6_code & 0x7f;
829 
830         if(secured) {
831                 ND_PRINT((ndo, ", (SEC) [worktodo]"));
832                 /* XXX
833                  * the next header pointer needs to move forward to
834                  * skip the secure part.
835                  */
836                 return;
837         } else {
838                 ND_PRINT((ndo, ", (CLR)"));
839         }
840 
841         switch(basecode) {
842         case ND_RPL_DAG_IS:
843                 ND_PRINT((ndo, "DODAG Information Solicitation"));
844                 if(ndo->ndo_vflag) {
845                 }
846                 break;
847         case ND_RPL_DAG_IO:
848                 ND_PRINT((ndo, "DODAG Information Object"));
849                 if(ndo->ndo_vflag) {
850                         rpl_dio_print(ndo, bp, length);
851                 }
852                 break;
853         case ND_RPL_DAO:
854                 ND_PRINT((ndo, "Destination Advertisement Object"));
855                 if(ndo->ndo_vflag) {
856                         rpl_dao_print(ndo, bp, length);
857                 }
858                 break;
859         case ND_RPL_DAO_ACK:
860                 ND_PRINT((ndo, "Destination Advertisement Object Ack"));
861                 if(ndo->ndo_vflag) {
862                         rpl_daoack_print(ndo, bp, length);
863                 }
864                 break;
865         default:
866                 ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
867                 break;
868         }
869 	return;
870 
871 #if 0
872 trunc:
873 	ND_PRINT((ndo, "%s", rpl_tstr));
874 	return;
875 #endif
876 
877 }
878 
879 
880 UNALIGNED_OK
881 void
icmp6_print(netdissect_options * ndo,const u_char * bp,u_int length,const u_char * bp2,int fragmented)882 icmp6_print(netdissect_options *ndo,
883             const u_char *bp, u_int length, const u_char *bp2, int fragmented)
884 {
885 	const struct icmp6_hdr *dp;
886 	const struct ip6_hdr *ip;
887 	const struct ip6_hdr *oip;
888 	const struct udphdr *ouh;
889 	int dport;
890 	const u_char *ep;
891 	u_int prot;
892 
893 	dp = (const struct icmp6_hdr *)bp;
894 	ip = (const struct ip6_hdr *)bp2;
895 	oip = (const struct ip6_hdr *)(dp + 1);
896 	/* 'ep' points to the end of available data. */
897 	ep = ndo->ndo_snapend;
898 
899 	ND_TCHECK(dp->icmp6_cksum);
900 
901 	if (ndo->ndo_vflag && !fragmented) {
902 		uint16_t sum, udp_sum;
903 
904 		if (ND_TTEST2(bp[0], length)) {
905 			udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
906 			sum = icmp6_cksum(ndo, ip, dp, length);
907 			if (sum != 0)
908 				ND_PRINT((ndo,"[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
909                                                 udp_sum,
910                                                 in_cksum_shouldbe(udp_sum, sum)));
911 			else
912 				ND_PRINT((ndo,"[icmp6 sum ok] "));
913 		}
914 	}
915 
916         ND_PRINT((ndo,"ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)));
917 
918         /* display cosmetics: print the packet length for printer that use the vflag now */
919         if (ndo->ndo_vflag)
920 		switch (dp->icmp6_type)  {
921 		case ND_ROUTER_SOLICIT:
922                 case ND_ROUTER_ADVERT:
923                 case ND_NEIGHBOR_ADVERT:
924                 case ND_NEIGHBOR_SOLICIT:
925                 case ND_REDIRECT:
926                 case ICMP6_HADISCOV_REPLY:
927                 case ICMP6_MOBILEPREFIX_ADVERT:
928 			ND_PRINT((ndo, ", length %u", length));
929 			break;
930 		default:
931 			break;
932 		}
933 
934 	switch (dp->icmp6_type) {
935 	case ICMP6_DST_UNREACH:
936 		ND_TCHECK(oip->ip6_dst);
937                 ND_PRINT((ndo,", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)));
938 		switch (dp->icmp6_code) {
939 
940 		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
941 		case ICMP6_DST_UNREACH_ADMIN:
942 		case ICMP6_DST_UNREACH_ADDR:
943                         ND_PRINT((ndo," %s",ip6addr_string(ndo, &oip->ip6_dst)));
944                         break;
945 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
946 			ND_PRINT((ndo," %s, source address %s",
947 			       ip6addr_string(ndo, &oip->ip6_dst),
948                                   ip6addr_string(ndo, &oip->ip6_src)));
949 			break;
950 		case ICMP6_DST_UNREACH_NOPORT:
951 			if ((ouh = get_upperlayer(ndo, (const u_char *)oip, &prot))
952 			    == NULL)
953 				goto trunc;
954 
955 			dport = EXTRACT_16BITS(&ouh->uh_dport);
956 			switch (prot) {
957 			case IPPROTO_TCP:
958 				ND_PRINT((ndo,", %s tcp port %s",
959 					ip6addr_string(ndo, &oip->ip6_dst),
960                                           tcpport_string(ndo, dport)));
961 				break;
962 			case IPPROTO_UDP:
963 				ND_PRINT((ndo,", %s udp port %s",
964 					ip6addr_string(ndo, &oip->ip6_dst),
965                                           udpport_string(ndo, dport)));
966 				break;
967 			default:
968 				ND_PRINT((ndo,", %s protocol %d port %d unreachable",
969 					ip6addr_string(ndo, &oip->ip6_dst),
970                                           oip->ip6_nxt, dport));
971 				break;
972 			}
973 			break;
974 		default:
975                   if (ndo->ndo_vflag <= 1) {
976                     print_unknown_data(ndo, bp,"\n\t",length);
977                     return;
978                   }
979                     break;
980 		}
981 		break;
982 	case ICMP6_PACKET_TOO_BIG:
983 		ND_TCHECK(dp->icmp6_mtu);
984 		ND_PRINT((ndo,", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)));
985 		break;
986 	case ICMP6_TIME_EXCEEDED:
987 		ND_TCHECK(oip->ip6_dst);
988 		switch (dp->icmp6_code) {
989 		case ICMP6_TIME_EXCEED_TRANSIT:
990 			ND_PRINT((ndo," for %s",
991                                   ip6addr_string(ndo, &oip->ip6_dst)));
992 			break;
993 		case ICMP6_TIME_EXCEED_REASSEMBLY:
994 			ND_PRINT((ndo," (reassembly)"));
995 			break;
996 		default:
997                         ND_PRINT((ndo,", unknown code (%u)", dp->icmp6_code));
998 			break;
999 		}
1000 		break;
1001 	case ICMP6_PARAM_PROB:
1002 		ND_TCHECK(oip->ip6_dst);
1003 		switch (dp->icmp6_code) {
1004 		case ICMP6_PARAMPROB_HEADER:
1005                         ND_PRINT((ndo,", erroneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1006                         break;
1007 		case ICMP6_PARAMPROB_NEXTHEADER:
1008                         ND_PRINT((ndo,", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1009                         break;
1010 		case ICMP6_PARAMPROB_OPTION:
1011                         ND_PRINT((ndo,", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1012                         break;
1013 		default:
1014                         ND_PRINT((ndo,", code-#%d",
1015                                   dp->icmp6_code));
1016                         break;
1017 		}
1018 		break;
1019 	case ICMP6_ECHO_REQUEST:
1020 	case ICMP6_ECHO_REPLY:
1021                 ND_TCHECK(dp->icmp6_seq);
1022                 ND_PRINT((ndo,", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)));
1023 		break;
1024 	case ICMP6_MEMBERSHIP_QUERY:
1025 		if (length == MLD_MINLEN) {
1026 			mld6_print(ndo, (const u_char *)dp);
1027 		} else if (length >= MLDV2_MINLEN) {
1028 			ND_PRINT((ndo," v2"));
1029 			mldv2_query_print(ndo, (const u_char *)dp, length);
1030 		} else {
1031                         ND_PRINT((ndo," unknown-version (len %u) ", length));
1032 		}
1033 		break;
1034 	case ICMP6_MEMBERSHIP_REPORT:
1035 		mld6_print(ndo, (const u_char *)dp);
1036 		break;
1037 	case ICMP6_MEMBERSHIP_REDUCTION:
1038 		mld6_print(ndo, (const u_char *)dp);
1039 		break;
1040 	case ND_ROUTER_SOLICIT:
1041 #define RTSOLLEN 8
1042 		if (ndo->ndo_vflag) {
1043 			icmp6_opt_print(ndo, (const u_char *)dp + RTSOLLEN,
1044 					length - RTSOLLEN);
1045 		}
1046 		break;
1047 	case ND_ROUTER_ADVERT:
1048 #define RTADVLEN 16
1049 		if (ndo->ndo_vflag) {
1050 			const struct nd_router_advert *p;
1051 
1052 			p = (const struct nd_router_advert *)dp;
1053 			ND_TCHECK(p->nd_ra_retransmit);
1054 			ND_PRINT((ndo,"\n\thop limit %u, Flags [%s]" \
1055                                   ", pref %s, router lifetime %us, reachable time %ums, retrans timer %ums",
1056                                   (u_int)p->nd_ra_curhoplimit,
1057                                   bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
1058                                   get_rtpref(p->nd_ra_flags_reserved),
1059                                   EXTRACT_16BITS(&p->nd_ra_router_lifetime),
1060                                   EXTRACT_32BITS(&p->nd_ra_reachable),
1061                                   EXTRACT_32BITS(&p->nd_ra_retransmit)));
1062 
1063 			icmp6_opt_print(ndo, (const u_char *)dp + RTADVLEN,
1064 					length - RTADVLEN);
1065 		}
1066 		break;
1067 	case ND_NEIGHBOR_SOLICIT:
1068 	    {
1069 		const struct nd_neighbor_solicit *p;
1070 		p = (const struct nd_neighbor_solicit *)dp;
1071 		ND_TCHECK(p->nd_ns_target);
1072 		ND_PRINT((ndo,", who has %s", ip6addr_string(ndo, &p->nd_ns_target)));
1073 		if (ndo->ndo_vflag) {
1074 #define NDSOLLEN 24
1075 			icmp6_opt_print(ndo, (const u_char *)dp + NDSOLLEN,
1076 					length - NDSOLLEN);
1077 		}
1078 	    }
1079 		break;
1080 	case ND_NEIGHBOR_ADVERT:
1081 	    {
1082 		const struct nd_neighbor_advert *p;
1083 
1084 		p = (const struct nd_neighbor_advert *)dp;
1085 		ND_TCHECK(p->nd_na_target);
1086 		ND_PRINT((ndo,", tgt is %s",
1087                           ip6addr_string(ndo, &p->nd_na_target)));
1088 		if (ndo->ndo_vflag) {
1089                         ND_PRINT((ndo,", Flags [%s]",
1090                                   bittok2str(icmp6_nd_na_flag_values,
1091                                              "none",
1092                                              EXTRACT_32BITS(&p->nd_na_flags_reserved))));
1093 #define NDADVLEN 24
1094 			icmp6_opt_print(ndo, (const u_char *)dp + NDADVLEN,
1095 					length - NDADVLEN);
1096 #undef NDADVLEN
1097 		}
1098 	    }
1099 		break;
1100 	case ND_REDIRECT:
1101 #define RDR(i) ((const struct nd_redirect *)(i))
1102                          ND_TCHECK(RDR(dp)->nd_rd_dst);
1103                          ND_PRINT((ndo,", %s", ip6addr_string(ndo, &RDR(dp)->nd_rd_dst)));
1104 		ND_TCHECK(RDR(dp)->nd_rd_target);
1105 		ND_PRINT((ndo," to %s",
1106                           ip6addr_string(ndo, &RDR(dp)->nd_rd_target)));
1107 #define REDIRECTLEN 40
1108 		if (ndo->ndo_vflag) {
1109 			icmp6_opt_print(ndo, (const u_char *)dp + REDIRECTLEN,
1110 					length - REDIRECTLEN);
1111 		}
1112 		break;
1113 #undef REDIRECTLEN
1114 #undef RDR
1115 	case ICMP6_ROUTER_RENUMBERING:
1116 		icmp6_rrenum_print(ndo, bp, ep);
1117 		break;
1118 	case ICMP6_NI_QUERY:
1119 	case ICMP6_NI_REPLY:
1120 		icmp6_nodeinfo_print(ndo, length, bp, ep);
1121 		break;
1122 	case IND_SOLICIT:
1123 	case IND_ADVERT:
1124 		break;
1125 	case ICMP6_V2_MEMBERSHIP_REPORT:
1126 		mldv2_report_print(ndo, (const u_char *) dp, length);
1127 		break;
1128 	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
1129 	case ICMP6_HADISCOV_REQUEST:
1130                 ND_TCHECK(dp->icmp6_data16[0]);
1131                 ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1132                 break;
1133 	case ICMP6_HADISCOV_REPLY:
1134 		if (ndo->ndo_vflag) {
1135 			const struct in6_addr *in6;
1136 			const u_char *cp;
1137 
1138 			ND_TCHECK(dp->icmp6_data16[0]);
1139 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1140 			cp = (const u_char *)dp + length;
1141 			in6 = (const struct in6_addr *)(dp + 1);
1142 			for (; (const u_char *)in6 < cp; in6++) {
1143 				ND_TCHECK(*in6);
1144 				ND_PRINT((ndo,", %s", ip6addr_string(ndo, in6)));
1145 			}
1146 		}
1147 		break;
1148 	case ICMP6_MOBILEPREFIX_ADVERT:
1149 		if (ndo->ndo_vflag) {
1150 			ND_TCHECK(dp->icmp6_data16[0]);
1151 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1152 			ND_TCHECK(dp->icmp6_data16[1]);
1153 			if (dp->icmp6_data16[1] & 0xc0)
1154 				ND_PRINT((ndo," "));
1155 			if (dp->icmp6_data16[1] & 0x80)
1156 				ND_PRINT((ndo,"M"));
1157 			if (dp->icmp6_data16[1] & 0x40)
1158 				ND_PRINT((ndo,"O"));
1159 #define MPADVLEN 8
1160 			icmp6_opt_print(ndo, (const u_char *)dp + MPADVLEN,
1161 					length - MPADVLEN);
1162 		}
1163 		break;
1164         case ND_RPL_MESSAGE:
1165                 /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */
1166                 rpl_print(ndo, dp, &dp->icmp6_data8[0], length-sizeof(struct icmp6_hdr)+4);
1167                 break;
1168 	default:
1169                 ND_PRINT((ndo,", length %u", length));
1170                 if (ndo->ndo_vflag <= 1)
1171                         print_unknown_data(ndo, bp,"\n\t", length);
1172                 return;
1173         }
1174         if (!ndo->ndo_vflag)
1175                 ND_PRINT((ndo,", length %u", length));
1176 	return;
1177 trunc:
1178 	ND_PRINT((ndo, "%s", icmp6_tstr));
1179 }
1180 
1181 static const struct udphdr *
get_upperlayer(netdissect_options * ndo,const u_char * bp,u_int * prot)1182 get_upperlayer(netdissect_options *ndo, const u_char *bp, u_int *prot)
1183 {
1184 	const u_char *ep;
1185 	const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
1186 	const struct udphdr *uh;
1187 	const struct ip6_hbh *hbh;
1188 	const struct ip6_frag *fragh;
1189 	const struct ah *ah;
1190 	u_int nh;
1191 	int hlen;
1192 
1193 	/* 'ep' points to the end of available data. */
1194 	ep = ndo->ndo_snapend;
1195 
1196 	if (!ND_TTEST(ip6->ip6_nxt))
1197 		return NULL;
1198 
1199 	nh = ip6->ip6_nxt;
1200 	hlen = sizeof(struct ip6_hdr);
1201 
1202 	while (bp < ep) {
1203 		bp += hlen;
1204 
1205 		switch(nh) {
1206 		case IPPROTO_UDP:
1207 		case IPPROTO_TCP:
1208 			uh = (const struct udphdr *)bp;
1209 			if (ND_TTEST(uh->uh_dport)) {
1210 				*prot = nh;
1211 				return(uh);
1212 			}
1213 			else
1214 				return(NULL);
1215 			/* NOTREACHED */
1216 
1217 		case IPPROTO_HOPOPTS:
1218 		case IPPROTO_DSTOPTS:
1219 		case IPPROTO_ROUTING:
1220 			hbh = (const struct ip6_hbh *)bp;
1221 			if (!ND_TTEST(hbh->ip6h_len))
1222 				return(NULL);
1223 			nh = hbh->ip6h_nxt;
1224 			hlen = (hbh->ip6h_len + 1) << 3;
1225 			break;
1226 
1227 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
1228 			fragh = (const struct ip6_frag *)bp;
1229 			if (!ND_TTEST(fragh->ip6f_offlg))
1230 				return(NULL);
1231 			/* fragments with non-zero offset are meaningless */
1232 			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
1233 				return(NULL);
1234 			nh = fragh->ip6f_nxt;
1235 			hlen = sizeof(struct ip6_frag);
1236 			break;
1237 
1238 		case IPPROTO_AH:
1239 			ah = (const struct ah *)bp;
1240 			if (!ND_TTEST(ah->ah_len))
1241 				return(NULL);
1242 			nh = ah->ah_nxt;
1243 			hlen = (ah->ah_len + 2) << 2;
1244 			break;
1245 
1246 		default:	/* unknown or undecodable header */
1247 			*prot = nh; /* meaningless, but set here anyway */
1248 			return(NULL);
1249 		}
1250 	}
1251 
1252 	return(NULL);		/* should be notreached, though */
1253 }
1254 
1255 static void
icmp6_opt_print(netdissect_options * ndo,const u_char * bp,int resid)1256 icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
1257 {
1258 	const struct nd_opt_hdr *op;
1259 	const struct nd_opt_prefix_info *opp;
1260 	const struct nd_opt_mtu *opm;
1261 	const struct nd_opt_rdnss *oprd;
1262 	const struct nd_opt_dnssl *opds;
1263 	const struct nd_opt_advinterval *opa;
1264 	const struct nd_opt_homeagent_info *oph;
1265 	const struct nd_opt_route_info *opri;
1266 	const u_char *cp, *ep, *domp;
1267 	struct in6_addr in6;
1268 	const struct in6_addr *in6p;
1269 	size_t l;
1270 	u_int i;
1271 
1272 #define ECHECK(var) if ((const u_char *)&(var) > ep - sizeof(var)) return
1273 
1274 	cp = bp;
1275 	/* 'ep' points to the end of available data. */
1276 	ep = ndo->ndo_snapend;
1277 
1278 	while (cp < ep) {
1279 		op = (const struct nd_opt_hdr *)cp;
1280 
1281 		ECHECK(op->nd_opt_len);
1282 		if (resid <= 0)
1283 			return;
1284 		if (op->nd_opt_len == 0)
1285 			goto trunc;
1286 		if (cp + (op->nd_opt_len << 3) > ep)
1287 			goto trunc;
1288 
1289                 ND_PRINT((ndo,"\n\t  %s option (%u), length %u (%u): ",
1290                           tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
1291                           op->nd_opt_type,
1292                           op->nd_opt_len << 3,
1293                           op->nd_opt_len));
1294 
1295 		switch (op->nd_opt_type) {
1296 		case ND_OPT_SOURCE_LINKADDR:
1297 			l = (op->nd_opt_len << 3) - 2;
1298 			print_lladdr(ndo, cp + 2, l);
1299 			break;
1300 		case ND_OPT_TARGET_LINKADDR:
1301 			l = (op->nd_opt_len << 3) - 2;
1302 			print_lladdr(ndo, cp + 2, l);
1303 			break;
1304 		case ND_OPT_PREFIX_INFORMATION:
1305 			opp = (const struct nd_opt_prefix_info *)op;
1306 			ND_TCHECK(opp->nd_opt_pi_prefix);
1307                         ND_PRINT((ndo,"%s/%u%s, Flags [%s], valid time %s",
1308                                   ip6addr_string(ndo, &opp->nd_opt_pi_prefix),
1309                                   opp->nd_opt_pi_prefix_len,
1310                                   (op->nd_opt_len != 4) ? "badlen" : "",
1311                                   bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
1312                                   get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))));
1313                         ND_PRINT((ndo,", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))));
1314 			break;
1315 		case ND_OPT_REDIRECTED_HEADER:
1316                         print_unknown_data(ndo, bp,"\n\t    ",op->nd_opt_len<<3);
1317 			/* xxx */
1318 			break;
1319 		case ND_OPT_MTU:
1320 			opm = (const struct nd_opt_mtu *)op;
1321 			ND_TCHECK(opm->nd_opt_mtu_mtu);
1322 			ND_PRINT((ndo," %u%s",
1323                                EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
1324                                   (op->nd_opt_len != 1) ? "bad option length" : "" ));
1325                         break;
1326 		case ND_OPT_RDNSS:
1327 			oprd = (const struct nd_opt_rdnss *)op;
1328 			l = (op->nd_opt_len - 1) / 2;
1329 			ND_PRINT((ndo," lifetime %us,",
1330                                   EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)));
1331 			for (i = 0; i < l; i++) {
1332 				ND_TCHECK(oprd->nd_opt_rdnss_addr[i]);
1333 				ND_PRINT((ndo," addr: %s",
1334                                           ip6addr_string(ndo, &oprd->nd_opt_rdnss_addr[i])));
1335 			}
1336 			break;
1337 		case ND_OPT_DNSSL:
1338 			opds = (const struct nd_opt_dnssl *)op;
1339 			ND_PRINT((ndo," lifetime %us, domain(s):",
1340                                   EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime)));
1341 			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
1342 			while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0')
1343 			{
1344 				ND_PRINT((ndo, " "));
1345 				if ((domp = ns_nprint (ndo, domp, bp)) == NULL)
1346 					goto trunc;
1347 			}
1348 			break;
1349 		case ND_OPT_ADVINTERVAL:
1350 			opa = (const struct nd_opt_advinterval *)op;
1351 			ND_TCHECK(opa->nd_opt_adv_interval);
1352 			ND_PRINT((ndo," %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval)));
1353 			break;
1354                 case ND_OPT_HOMEAGENT_INFO:
1355 			oph = (const struct nd_opt_homeagent_info *)op;
1356 			ND_TCHECK(oph->nd_opt_hai_lifetime);
1357 			ND_PRINT((ndo," preference %u, lifetime %u",
1358                                   EXTRACT_16BITS(&oph->nd_opt_hai_preference),
1359                                   EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)));
1360 			break;
1361 		case ND_OPT_ROUTE_INFO:
1362 			opri = (const struct nd_opt_route_info *)op;
1363 			ND_TCHECK(opri->nd_opt_rti_lifetime);
1364 			memset(&in6, 0, sizeof(in6));
1365 			in6p = (const struct in6_addr *)(opri + 1);
1366 			switch (op->nd_opt_len) {
1367 			case 1:
1368 				break;
1369 			case 2:
1370 				ND_TCHECK2(*in6p, 8);
1371 				memcpy(&in6, opri + 1, 8);
1372 				break;
1373 			case 3:
1374 				ND_TCHECK(*in6p);
1375 				memcpy(&in6, opri + 1, sizeof(in6));
1376 				break;
1377 			default:
1378 				goto trunc;
1379 			}
1380 			ND_PRINT((ndo," %s/%u", ip6addr_string(ndo, &in6),
1381                                   opri->nd_opt_rti_prefixlen));
1382 			ND_PRINT((ndo,", pref=%s", get_rtpref(opri->nd_opt_rti_flags)));
1383 			ND_PRINT((ndo,", lifetime=%s",
1384                                   get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))));
1385 			break;
1386 		default:
1387                         if (ndo->ndo_vflag <= 1) {
1388                                 print_unknown_data(ndo,cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
1389                             return;
1390                         }
1391                         break;
1392 		}
1393                 /* do we want to see an additional hexdump ? */
1394                 if (ndo->ndo_vflag> 1)
1395                         print_unknown_data(ndo, cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
1396 
1397 		cp += op->nd_opt_len << 3;
1398 		resid -= op->nd_opt_len << 3;
1399 	}
1400 	return;
1401 
1402 trunc:
1403 	ND_PRINT((ndo, "%s", icmp6_tstr));
1404 	return;
1405 #undef ECHECK
1406 }
1407 
1408 UNALIGNED_OK
1409 static void
mld6_print(netdissect_options * ndo,const u_char * bp)1410 mld6_print(netdissect_options *ndo, const u_char *bp)
1411 {
1412 	const struct mld6_hdr *mp = (const struct mld6_hdr *)bp;
1413 	const u_char *ep;
1414 
1415 	/* 'ep' points to the end of available data. */
1416 	ep = ndo->ndo_snapend;
1417 
1418 	if ((const u_char *)mp + sizeof(*mp) > ep)
1419 		return;
1420 
1421 	ND_PRINT((ndo,"max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)));
1422 	ND_PRINT((ndo,"addr: %s", ip6addr_string(ndo, &mp->mld6_addr)));
1423 }
1424 
1425 UNALIGNED_OK
1426 static void
mldv2_report_print(netdissect_options * ndo,const u_char * bp,u_int len)1427 mldv2_report_print(netdissect_options *ndo, const u_char *bp, u_int len)
1428 {
1429     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1430     u_int group, nsrcs, ngroups;
1431     u_int i, j;
1432 
1433     /* Minimum len is 8 */
1434     if (len < 8) {
1435             ND_PRINT((ndo," [invalid len %d]", len));
1436             return;
1437     }
1438 
1439     ND_TCHECK(icp->icmp6_data16[1]);
1440     ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
1441     ND_PRINT((ndo,", %d group record(s)", ngroups));
1442     if (ndo->ndo_vflag > 0) {
1443 	/* Print the group records */
1444 	group = 8;
1445         for (i = 0; i < ngroups; i++) {
1446 	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
1447 	    if (len < group + 20) {
1448                     ND_PRINT((ndo," [invalid number of groups]"));
1449                     return;
1450 	    }
1451             ND_TCHECK2(bp[group + 4], sizeof(struct in6_addr));
1452             ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[group + 4])));
1453 	    ND_PRINT((ndo," %s", tok2str(mldv2report2str, " [v2-report-#%d]",
1454                                          bp[group])));
1455             nsrcs = (bp[group + 2] << 8) + bp[group + 3];
1456 	    /* Check the number of sources and print them */
1457 	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
1458                     ND_PRINT((ndo," [invalid number of sources %d]", nsrcs));
1459                     return;
1460 	    }
1461             if (ndo->ndo_vflag == 1)
1462                     ND_PRINT((ndo,", %d source(s)", nsrcs));
1463             else {
1464 		/* Print the sources */
1465                     ND_PRINT((ndo," {"));
1466                 for (j = 0; j < nsrcs; j++) {
1467                     ND_TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
1468                             sizeof(struct in6_addr));
1469 		    ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[group + 20 + j * sizeof(struct in6_addr)])));
1470 		}
1471                 ND_PRINT((ndo," }"));
1472             }
1473 	    /* Next group record */
1474             group += 20 + nsrcs * sizeof(struct in6_addr);
1475 	    ND_PRINT((ndo,"]"));
1476         }
1477     }
1478     return;
1479 trunc:
1480     ND_PRINT((ndo, "%s", mldv2_tstr));
1481     return;
1482 }
1483 
1484 UNALIGNED_OK
1485 static void
mldv2_query_print(netdissect_options * ndo,const u_char * bp,u_int len)1486 mldv2_query_print(netdissect_options *ndo, const u_char *bp, u_int len)
1487 {
1488     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1489     u_int mrc;
1490     int mrt, qqi;
1491     u_int nsrcs;
1492     register u_int i;
1493 
1494     /* Minimum len is 28 */
1495     if (len < 28) {
1496             ND_PRINT((ndo," [invalid len %d]", len));
1497 	return;
1498     }
1499     ND_TCHECK(icp->icmp6_data16[0]);
1500     mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
1501     if (mrc < 32768) {
1502 	mrt = mrc;
1503     } else {
1504         mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
1505     }
1506     if (ndo->ndo_vflag) {
1507             ND_PRINT((ndo," [max resp delay=%d]", mrt));
1508     }
1509     ND_TCHECK2(bp[8], sizeof(struct in6_addr));
1510     ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[8])));
1511 
1512     if (ndo->ndo_vflag) {
1513         ND_TCHECK(bp[25]);
1514 	if (bp[24] & 0x08) {
1515 		ND_PRINT((ndo," sflag"));
1516 	}
1517 	if (bp[24] & 0x07) {
1518 		ND_PRINT((ndo," robustness=%d", bp[24] & 0x07));
1519 	}
1520 	if (bp[25] < 128) {
1521 		qqi = bp[25];
1522 	} else {
1523 		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
1524 	}
1525 	ND_PRINT((ndo," qqi=%d", qqi));
1526     }
1527 
1528     ND_TCHECK2(bp[26], 2);
1529     nsrcs = EXTRACT_16BITS(&bp[26]);
1530     if (nsrcs > 0) {
1531 	if (len < 28 + nsrcs * sizeof(struct in6_addr))
1532 	    ND_PRINT((ndo," [invalid number of sources]"));
1533 	else if (ndo->ndo_vflag > 1) {
1534 	    ND_PRINT((ndo," {"));
1535 	    for (i = 0; i < nsrcs; i++) {
1536 		ND_TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
1537                         sizeof(struct in6_addr));
1538 		ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[28 + i * sizeof(struct in6_addr)])));
1539 	    }
1540 	    ND_PRINT((ndo," }"));
1541 	} else
1542                 ND_PRINT((ndo,", %d source(s)", nsrcs));
1543     }
1544     ND_PRINT((ndo,"]"));
1545     return;
1546 trunc:
1547     ND_PRINT((ndo, "%s", mldv2_tstr));
1548     return;
1549 }
1550 
1551 static void
dnsname_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)1552 dnsname_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
1553 {
1554 	int i;
1555 
1556 	/* DNS name decoding - no decompression */
1557 	ND_PRINT((ndo,", \""));
1558 	while (cp < ep) {
1559 		i = *cp++;
1560 		if (i) {
1561 			if (i > ep - cp) {
1562 				ND_PRINT((ndo,"???"));
1563 				break;
1564 			}
1565 			while (i-- && cp < ep) {
1566 				safeputchar(ndo, *cp);
1567 				cp++;
1568 			}
1569 			if (cp + 1 < ep && *cp)
1570 				ND_PRINT((ndo,"."));
1571 		} else {
1572 			if (cp == ep) {
1573 				/* FQDN */
1574 				ND_PRINT((ndo,"."));
1575 			} else if (cp + 1 == ep && *cp == '\0') {
1576 				/* truncated */
1577 			} else {
1578 				/* invalid */
1579 				ND_PRINT((ndo,"???"));
1580 			}
1581 			break;
1582 		}
1583 	}
1584 	ND_PRINT((ndo,"\""));
1585 }
1586 
1587 static void
icmp6_nodeinfo_print(netdissect_options * ndo,u_int icmp6len,const u_char * bp,const u_char * ep)1588 icmp6_nodeinfo_print(netdissect_options *ndo, u_int icmp6len, const u_char *bp, const u_char *ep)
1589 {
1590 	const struct icmp6_nodeinfo *ni6;
1591 	const struct icmp6_hdr *dp;
1592 	const u_char *cp;
1593 	size_t siz, i;
1594 	int needcomma;
1595 
1596 	if (ep < bp)
1597 		return;
1598 	dp = (const struct icmp6_hdr *)bp;
1599 	ni6 = (const struct icmp6_nodeinfo *)bp;
1600 	siz = ep - bp;
1601 
1602 	switch (ni6->ni_type) {
1603 	case ICMP6_NI_QUERY:
1604 		if (siz == sizeof(*dp) + 4) {
1605 			/* KAME who-are-you */
1606 			ND_PRINT((ndo," who-are-you request"));
1607 			break;
1608 		}
1609 		ND_PRINT((ndo," node information query"));
1610 
1611 		ND_TCHECK2(*dp, sizeof(*ni6));
1612 		ni6 = (const struct icmp6_nodeinfo *)dp;
1613 		ND_PRINT((ndo," ("));	/*)*/
1614 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1615 		case NI_QTYPE_NOOP:
1616 			ND_PRINT((ndo,"noop"));
1617 			break;
1618 		case NI_QTYPE_SUPTYPES:
1619 			ND_PRINT((ndo,"supported qtypes"));
1620 			i = EXTRACT_16BITS(&ni6->ni_flags);
1621 			if (i)
1622 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1623 			break;
1624 		case NI_QTYPE_FQDN:
1625 			ND_PRINT((ndo,"DNS name"));
1626 			break;
1627 		case NI_QTYPE_NODEADDR:
1628 			ND_PRINT((ndo,"node addresses"));
1629 			i = ni6->ni_flags;
1630 			if (!i)
1631 				break;
1632 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
1633 			ND_PRINT((ndo," [%s%s%s%s%s%s]",
1634 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1635 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1636 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1637 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1638 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1639 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""));
1640 			break;
1641 		default:
1642 			ND_PRINT((ndo,"unknown"));
1643 			break;
1644 		}
1645 
1646 		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
1647 		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
1648 			if (siz != sizeof(*ni6))
1649 				if (ndo->ndo_vflag)
1650 					ND_PRINT((ndo,", invalid len"));
1651 			/*(*/
1652 			ND_PRINT((ndo,")"));
1653 			break;
1654 		}
1655 
1656 
1657 		/* XXX backward compat, icmp-name-lookup-03 */
1658 		if (siz == sizeof(*ni6)) {
1659 			ND_PRINT((ndo,", 03 draft"));
1660 			/*(*/
1661 			ND_PRINT((ndo,")"));
1662 			break;
1663 		}
1664 
1665 		switch (ni6->ni_code) {
1666 		case ICMP6_NI_SUBJ_IPV6:
1667 			if (!ND_TTEST2(*dp,
1668 			    sizeof(*ni6) + sizeof(struct in6_addr)))
1669 				break;
1670 			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
1671 				if (ndo->ndo_vflag)
1672 					ND_PRINT((ndo,", invalid subject len"));
1673 				break;
1674 			}
1675 			ND_PRINT((ndo,", subject=%s",
1676                                   ip6addr_string(ndo, ni6 + 1)));
1677 			break;
1678 		case ICMP6_NI_SUBJ_FQDN:
1679 			ND_PRINT((ndo,", subject=DNS name"));
1680 			cp = (const u_char *)(ni6 + 1);
1681 			if (cp[0] == ep - cp - 1) {
1682 				/* icmp-name-lookup-03, pascal string */
1683 				if (ndo->ndo_vflag)
1684 					ND_PRINT((ndo,", 03 draft"));
1685 				cp++;
1686 				ND_PRINT((ndo,", \""));
1687 				while (cp < ep) {
1688 					safeputchar(ndo, *cp);
1689 					cp++;
1690 				}
1691 				ND_PRINT((ndo,"\""));
1692 			} else
1693 				dnsname_print(ndo, cp, ep);
1694 			break;
1695 		case ICMP6_NI_SUBJ_IPV4:
1696 			if (!ND_TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1697 				break;
1698 			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
1699 				if (ndo->ndo_vflag)
1700 					ND_PRINT((ndo,", invalid subject len"));
1701 				break;
1702 			}
1703 			ND_PRINT((ndo,", subject=%s",
1704                                   ipaddr_string(ndo, ni6 + 1)));
1705 			break;
1706 		default:
1707 			ND_PRINT((ndo,", unknown subject"));
1708 			break;
1709 		}
1710 
1711 		/*(*/
1712 		ND_PRINT((ndo,")"));
1713 		break;
1714 
1715 	case ICMP6_NI_REPLY:
1716 		if (icmp6len > siz) {
1717 			ND_PRINT((ndo,"[|icmp6: node information reply]"));
1718 			break;
1719 		}
1720 
1721 		needcomma = 0;
1722 
1723 		ND_TCHECK2(*dp, sizeof(*ni6));
1724 		ni6 = (const struct icmp6_nodeinfo *)dp;
1725 		ND_PRINT((ndo," node information reply"));
1726 		ND_PRINT((ndo," ("));	/*)*/
1727 		switch (ni6->ni_code) {
1728 		case ICMP6_NI_SUCCESS:
1729 			if (ndo->ndo_vflag) {
1730 				ND_PRINT((ndo,"success"));
1731 				needcomma++;
1732 			}
1733 			break;
1734 		case ICMP6_NI_REFUSED:
1735 			ND_PRINT((ndo,"refused"));
1736 			needcomma++;
1737 			if (siz != sizeof(*ni6))
1738 				if (ndo->ndo_vflag)
1739 					ND_PRINT((ndo,", invalid length"));
1740 			break;
1741 		case ICMP6_NI_UNKNOWN:
1742 			ND_PRINT((ndo,"unknown"));
1743 			needcomma++;
1744 			if (siz != sizeof(*ni6))
1745 				if (ndo->ndo_vflag)
1746 					ND_PRINT((ndo,", invalid length"));
1747 			break;
1748 		}
1749 
1750 		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1751 			/*(*/
1752 			ND_PRINT((ndo,")"));
1753 			break;
1754 		}
1755 
1756 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1757 		case NI_QTYPE_NOOP:
1758 			if (needcomma)
1759 				ND_PRINT((ndo,", "));
1760 			ND_PRINT((ndo,"noop"));
1761 			if (siz != sizeof(*ni6))
1762 				if (ndo->ndo_vflag)
1763 					ND_PRINT((ndo,", invalid length"));
1764 			break;
1765 		case NI_QTYPE_SUPTYPES:
1766 			if (needcomma)
1767 				ND_PRINT((ndo,", "));
1768 			ND_PRINT((ndo,"supported qtypes"));
1769 			i = EXTRACT_16BITS(&ni6->ni_flags);
1770 			if (i)
1771 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1772 			break;
1773 		case NI_QTYPE_FQDN:
1774 			if (needcomma)
1775 				ND_PRINT((ndo,", "));
1776 			ND_PRINT((ndo,"DNS name"));
1777 			cp = (const u_char *)(ni6 + 1) + 4;
1778 			ND_TCHECK(cp[0]);
1779 			if (cp[0] == ep - cp - 1) {
1780 				/* icmp-name-lookup-03, pascal string */
1781 				if (ndo->ndo_vflag)
1782 					ND_PRINT((ndo,", 03 draft"));
1783 				cp++;
1784 				ND_PRINT((ndo,", \""));
1785 				while (cp < ep) {
1786 					safeputchar(ndo, *cp);
1787 					cp++;
1788 				}
1789 				ND_PRINT((ndo,"\""));
1790 			} else
1791 				dnsname_print(ndo, cp, ep);
1792 			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1793 				ND_PRINT((ndo," [TTL=%u]", EXTRACT_32BITS(ni6 + 1)));
1794 			break;
1795 		case NI_QTYPE_NODEADDR:
1796 			if (needcomma)
1797 				ND_PRINT((ndo,", "));
1798 			ND_PRINT((ndo,"node addresses"));
1799 			i = sizeof(*ni6);
1800 			while (i < siz) {
1801 				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1802 					break;
1803 				ND_PRINT((ndo," %s", ip6addr_string(ndo, bp + i)));
1804 				i += sizeof(struct in6_addr);
1805 				ND_PRINT((ndo,"(%d)", (int32_t)EXTRACT_32BITS(bp + i)));
1806 				i += sizeof(int32_t);
1807 			}
1808 			i = ni6->ni_flags;
1809 			if (!i)
1810 				break;
1811 			ND_PRINT((ndo," [%s%s%s%s%s%s%s]",
1812                                   (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1813                                   (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1814                                   (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1815                                   (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1816                                   (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1817                                   (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
1818                                   (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""));
1819 			break;
1820 		default:
1821 			if (needcomma)
1822 				ND_PRINT((ndo,", "));
1823 			ND_PRINT((ndo,"unknown"));
1824 			break;
1825 		}
1826 
1827 		/*(*/
1828 		ND_PRINT((ndo,")"));
1829 		break;
1830 	}
1831 	return;
1832 
1833 trunc:
1834 	ND_PRINT((ndo, "%s", icmp6_tstr));
1835 }
1836 
1837 static void
icmp6_rrenum_print(netdissect_options * ndo,const u_char * bp,const u_char * ep)1838 icmp6_rrenum_print(netdissect_options *ndo, const u_char *bp, const u_char *ep)
1839 {
1840 	const struct icmp6_router_renum *rr6;
1841 	const char *cp;
1842 	const struct rr_pco_match *match;
1843 	const struct rr_pco_use *use;
1844 	char hbuf[NI_MAXHOST];
1845 	int n;
1846 
1847 	if (ep < bp)
1848 		return;
1849 	rr6 = (const struct icmp6_router_renum *)bp;
1850 	cp = (const char *)(rr6 + 1);
1851 
1852 	ND_TCHECK(rr6->rr_reserved);
1853 	switch (rr6->rr_code) {
1854 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
1855 		ND_PRINT((ndo,"router renum: command"));
1856 		break;
1857 	case ICMP6_ROUTER_RENUMBERING_RESULT:
1858 		ND_PRINT((ndo,"router renum: result"));
1859 		break;
1860 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1861 		ND_PRINT((ndo,"router renum: sequence number reset"));
1862 		break;
1863 	default:
1864 		ND_PRINT((ndo,"router renum: code-#%d", rr6->rr_code));
1865 		break;
1866 	}
1867 
1868         ND_PRINT((ndo,", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)));
1869 
1870 	if (ndo->ndo_vflag) {
1871 #define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
1872 		ND_PRINT((ndo,"["));	/*]*/
1873 		if (rr6->rr_flags) {
1874 			ND_PRINT((ndo,"%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1875                                   F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1876                                   F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1877                                   F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1878                                   F(ICMP6_RR_FLAGS_PREVDONE, "P")));
1879 		}
1880                 ND_PRINT((ndo,"seg=%u,", rr6->rr_segnum));
1881                 ND_PRINT((ndo,"maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)));
1882 		if (rr6->rr_reserved)
1883 			ND_PRINT((ndo,"rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)));
1884 		/*[*/
1885 		ND_PRINT((ndo,"]"));
1886 #undef F
1887 	}
1888 
1889 	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1890 		match = (const struct rr_pco_match *)cp;
1891 		cp = (const char *)(match + 1);
1892 
1893 		ND_TCHECK(match->rpm_prefix);
1894 
1895 		if (ndo->ndo_vflag > 1)
1896 			ND_PRINT((ndo,"\n\t"));
1897 		else
1898 			ND_PRINT((ndo," "));
1899 		ND_PRINT((ndo,"match("));	/*)*/
1900 		switch (match->rpm_code) {
1901 		case RPM_PCO_ADD:	ND_PRINT((ndo,"add")); break;
1902 		case RPM_PCO_CHANGE:	ND_PRINT((ndo,"change")); break;
1903 		case RPM_PCO_SETGLOBAL:	ND_PRINT((ndo,"setglobal")); break;
1904 		default:		ND_PRINT((ndo,"#%u", match->rpm_code)); break;
1905 		}
1906 
1907 		if (ndo->ndo_vflag) {
1908 			ND_PRINT((ndo,",ord=%u", match->rpm_ordinal));
1909 			ND_PRINT((ndo,",min=%u", match->rpm_minlen));
1910 			ND_PRINT((ndo,",max=%u", match->rpm_maxlen));
1911 		}
1912 		if (addrtostr6(&match->rpm_prefix, hbuf, sizeof(hbuf)))
1913 			ND_PRINT((ndo,",%s/%u", hbuf, match->rpm_matchlen));
1914 		else
1915 			ND_PRINT((ndo,",?/%u", match->rpm_matchlen));
1916 		/*(*/
1917 		ND_PRINT((ndo,")"));
1918 
1919 		n = match->rpm_len - 3;
1920 		if (n % 4)
1921 			goto trunc;
1922 		n /= 4;
1923 		while (n-- > 0) {
1924 			use = (const struct rr_pco_use *)cp;
1925 			cp = (const char *)(use + 1);
1926 
1927 			ND_TCHECK(use->rpu_prefix);
1928 
1929 			if (ndo->ndo_vflag > 1)
1930 				ND_PRINT((ndo,"\n\t"));
1931 			else
1932 				ND_PRINT((ndo," "));
1933 			ND_PRINT((ndo,"use("));	/*)*/
1934 			if (use->rpu_flags) {
1935 #define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
1936 				ND_PRINT((ndo,"%s%s,",
1937                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1938                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")));
1939 #undef F
1940 			}
1941 			if (ndo->ndo_vflag) {
1942 				ND_PRINT((ndo,"mask=0x%x,", use->rpu_ramask));
1943 				ND_PRINT((ndo,"raflags=0x%x,", use->rpu_raflags));
1944 				if (~use->rpu_vltime == 0)
1945 					ND_PRINT((ndo,"vltime=infty,"));
1946 				else
1947 					ND_PRINT((ndo,"vltime=%u,",
1948                                                   EXTRACT_32BITS(&use->rpu_vltime)));
1949 				if (~use->rpu_pltime == 0)
1950 					ND_PRINT((ndo,"pltime=infty,"));
1951 				else
1952 					ND_PRINT((ndo,"pltime=%u,",
1953                                                   EXTRACT_32BITS(&use->rpu_pltime)));
1954 			}
1955 			if (addrtostr6(&use->rpu_prefix, hbuf, sizeof(hbuf)))
1956 				ND_PRINT((ndo,"%s/%u/%u", hbuf, use->rpu_uselen,
1957                                           use->rpu_keeplen));
1958 			else
1959 				ND_PRINT((ndo,"?/%u/%u", use->rpu_uselen,
1960                                           use->rpu_keeplen));
1961 			/*(*/
1962                         ND_PRINT((ndo,")"));
1963 		}
1964 	}
1965 
1966 	return;
1967 
1968 trunc:
1969 	ND_PRINT((ndo, "%s", icmp6_tstr));
1970 }
1971 
1972 /*
1973  * Local Variables:
1974  * c-style: whitesmith
1975  * c-basic-offset: 8
1976  * End:
1977  */
1978