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