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