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