1 /* 2 * Copyright (C) 1998 and 1999 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* \summary: IPv6 DHCP printer */ 31 32 /* 33 * RFC3315: DHCPv6 34 * supported DHCPv6 options: 35 * RFC3319: Session Initiation Protocol (SIP) Servers options, 36 * RFC3633: IPv6 Prefix options, 37 * RFC3646: DNS Configuration options, 38 * RFC3898: Network Information Service (NIS) Configuration options, 39 * RFC4075: Simple Network Time Protocol (SNTP) Configuration option, 40 * RFC4242: Information Refresh Time option, 41 * RFC4280: Broadcast and Multicast Control Servers options, 42 * RFC5908: Network Time Protocol (NTP) Server Option for DHCPv6 43 * RFC6334: Dual-Stack Lite option, 44 */ 45 46 #include <sys/cdefs.h> 47 #ifndef lint 48 __RCSID("$NetBSD: print-dhcp6.c,v 1.10 2024/09/02 16:15:31 christos Exp $"); 49 #endif 50 51 #include <config.h> 52 53 #include "netdissect-stdinc.h" 54 55 #include "netdissect.h" 56 #include "addrtoname.h" 57 #include "extract.h" 58 59 /* lease duration */ 60 #define DHCP6_DURATION_INFINITE 0xffffffff 61 62 /* Error Values */ 63 #define DH6ERR_FAILURE 16 64 #define DH6ERR_AUTHFAIL 17 65 #define DH6ERR_POORLYFORMED 18 66 #define DH6ERR_UNAVAIL 19 67 #define DH6ERR_OPTUNAVAIL 20 68 69 /* Message type */ 70 #define DH6_SOLICIT 1 71 #define DH6_ADVERTISE 2 72 #define DH6_REQUEST 3 73 #define DH6_CONFIRM 4 74 #define DH6_RENEW 5 75 #define DH6_REBIND 6 76 #define DH6_REPLY 7 77 #define DH6_RELEASE 8 78 #define DH6_DECLINE 9 79 #define DH6_RECONFIGURE 10 80 #define DH6_INFORM_REQ 11 81 #define DH6_RELAY_FORW 12 82 #define DH6_RELAY_REPLY 13 83 #define DH6_LEASEQUERY 14 84 #define DH6_LQ_REPLY 15 85 86 static const struct tok dh6_msgtype_str[] = { 87 { DH6_SOLICIT, "solicit" }, 88 { DH6_ADVERTISE, "advertise" }, 89 { DH6_REQUEST, "request" }, 90 { DH6_CONFIRM, "confirm" }, 91 { DH6_RENEW, "renew" }, 92 { DH6_REBIND, "rebind" }, 93 { DH6_REPLY, "reply" }, 94 { DH6_RELEASE, "release" }, 95 { DH6_DECLINE, "decline" }, 96 { DH6_RECONFIGURE, "reconfigure" }, 97 { DH6_INFORM_REQ, "inf-req" }, 98 { DH6_RELAY_FORW, "relay-fwd" }, 99 { DH6_RELAY_REPLY, "relay-reply" }, 100 { DH6_LEASEQUERY, "leasequery" }, 101 { DH6_LQ_REPLY, "leasequery-reply" }, 102 { 0, NULL } 103 }; 104 105 /* DHCP6 base packet format */ 106 struct dhcp6 { 107 union { 108 nd_uint8_t msgtype; 109 nd_uint32_t xid; 110 } dh6_msgtypexid; 111 /* options follow */ 112 }; 113 #define DH6_XIDMASK 0x00ffffff 114 115 /* DHCPv6 relay messages */ 116 struct dhcp6_relay { 117 nd_uint8_t dh6relay_msgtype; 118 nd_uint8_t dh6relay_hcnt; 119 nd_ipv6 dh6relay_linkaddr; /* XXX: badly aligned */ 120 nd_ipv6 dh6relay_peeraddr; 121 /* options follow */ 122 }; 123 124 /* options */ 125 #define DH6OPT_CLIENTID 1 126 #define DH6OPT_SERVERID 2 127 # define DUID_LLT 1 /* RFC8415 */ 128 # define DUID_EN 2 /* RFC8415 */ 129 # define DUID_LL 3 /* RFC8415 */ 130 # define DUID_UUID 4 /* RFC6355 */ 131 #define DH6OPT_IA_NA 3 132 #define DH6OPT_IA_TA 4 133 #define DH6OPT_IA_ADDR 5 134 #define DH6OPT_ORO 6 135 #define DH6OPT_PREFERENCE 7 136 # define DH6OPT_PREF_MAX 255 137 #define DH6OPT_ELAPSED_TIME 8 138 #define DH6OPT_RELAY_MSG 9 139 /*#define DH6OPT_SERVER_MSG 10 deprecated */ 140 #define DH6OPT_AUTH 11 141 # define DH6OPT_AUTHPROTO_DELAYED 2 142 # define DH6OPT_AUTHPROTO_RECONFIG 3 143 # define DH6OPT_AUTHALG_HMACMD5 1 144 # define DH6OPT_AUTHRDM_MONOCOUNTER 0 145 # define DH6OPT_AUTHRECONFIG_KEY 1 146 # define DH6OPT_AUTHRECONFIG_HMACMD5 2 147 #define DH6OPT_UNICAST 12 148 #define DH6OPT_STATUS_CODE 13 149 # define DH6OPT_STCODE_SUCCESS 0 150 # define DH6OPT_STCODE_UNSPECFAIL 1 151 # define DH6OPT_STCODE_NOADDRAVAIL 2 152 # define DH6OPT_STCODE_NOBINDING 3 153 # define DH6OPT_STCODE_NOTONLINK 4 154 # define DH6OPT_STCODE_USEMULTICAST 5 155 # define DH6OPT_STCODE_NOPREFIXAVAIL 6 156 # define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7 157 # define DH6OPT_STCODE_MALFORMEDQUERY 8 158 # define DH6OPT_STCODE_NOTCONFIGURED 9 159 # define DH6OPT_STCODE_NOTALLOWED 10 160 #define DH6OPT_RAPID_COMMIT 14 161 #define DH6OPT_USER_CLASS 15 162 #define DH6OPT_VENDOR_CLASS 16 163 #define DH6OPT_VENDOR_OPTS 17 164 #define DH6OPT_INTERFACE_ID 18 165 #define DH6OPT_RECONF_MSG 19 166 #define DH6OPT_RECONF_ACCEPT 20 167 #define DH6OPT_SIP_SERVER_D 21 168 #define DH6OPT_SIP_SERVER_A 22 169 #define DH6OPT_DNS_SERVERS 23 170 #define DH6OPT_DOMAIN_LIST 24 171 #define DH6OPT_IA_PD 25 172 #define DH6OPT_IA_PD_PREFIX 26 173 #define DH6OPT_NIS_SERVERS 27 174 #define DH6OPT_NISP_SERVERS 28 175 #define DH6OPT_NIS_NAME 29 176 #define DH6OPT_NISP_NAME 30 177 #define DH6OPT_SNTP_SERVERS 31 178 #define DH6OPT_LIFETIME 32 179 #define DH6OPT_BCMCS_SERVER_D 33 180 #define DH6OPT_BCMCS_SERVER_A 34 181 #define DH6OPT_GEOCONF_CIVIC 36 182 #define DH6OPT_REMOTE_ID 37 183 #define DH6OPT_SUBSCRIBER_ID 38 184 #define DH6OPT_CLIENT_FQDN 39 185 #define DH6OPT_PANA_AGENT 40 186 #define DH6OPT_NEW_POSIX_TIMEZONE 41 187 #define DH6OPT_NEW_TZDB_TIMEZONE 42 188 #define DH6OPT_ERO 43 189 #define DH6OPT_LQ_QUERY 44 190 #define DH6OPT_CLIENT_DATA 45 191 #define DH6OPT_CLT_TIME 46 192 #define DH6OPT_LQ_RELAY_DATA 47 193 #define DH6OPT_LQ_CLIENT_LINK 48 194 #define DH6OPT_NTP_SERVER 56 195 # define DH6OPT_NTP_SUBOPTION_SRV_ADDR 1 196 # define DH6OPT_NTP_SUBOPTION_MC_ADDR 2 197 # define DH6OPT_NTP_SUBOPTION_SRV_FQDN 3 198 #define DH6OPT_BOOTFILE_URL 59 /* RFC5970 */ 199 #define DH6OPT_AFTR_NAME 64 200 #define DH6OPT_MUDURL 112 201 #define DH6OPT_SZTP_REDIRECT 136 /* RFC8572 */ 202 203 static const struct tok dh6opt_str[] = { 204 { DH6OPT_CLIENTID, "client-ID" }, 205 { DH6OPT_SERVERID, "server-ID" }, 206 { DH6OPT_IA_NA, "IA_NA" }, 207 { DH6OPT_IA_TA, "IA_TA" }, 208 { DH6OPT_IA_ADDR, "IA_ADDR" }, 209 { DH6OPT_ORO, "option-request" }, 210 { DH6OPT_PREFERENCE, "preference" }, 211 { DH6OPT_ELAPSED_TIME, "elapsed-time" }, 212 { DH6OPT_RELAY_MSG, "relay-message" }, 213 { DH6OPT_AUTH, "authentication" }, 214 { DH6OPT_UNICAST, "server-unicast" }, 215 { DH6OPT_STATUS_CODE, "status-code" }, 216 { DH6OPT_RAPID_COMMIT, "rapid-commit" }, 217 { DH6OPT_USER_CLASS, "user-class" }, 218 { DH6OPT_VENDOR_CLASS, "vendor-class" }, 219 { DH6OPT_VENDOR_OPTS, "vendor-specific-info" }, 220 { DH6OPT_INTERFACE_ID, "interface-ID" }, 221 { DH6OPT_RECONF_MSG, "reconfigure-message" }, 222 { DH6OPT_RECONF_ACCEPT, "reconfigure-accept" }, 223 { DH6OPT_SIP_SERVER_D, "SIP-servers-domain" }, 224 { DH6OPT_SIP_SERVER_A, "SIP-servers-address" }, 225 { DH6OPT_DNS_SERVERS, "DNS-server" }, 226 { DH6OPT_DOMAIN_LIST, "DNS-search-list" }, 227 { DH6OPT_IA_PD, "IA_PD" }, 228 { DH6OPT_IA_PD_PREFIX, "IA_PD-prefix" }, 229 { DH6OPT_SNTP_SERVERS, "SNTP-servers" }, 230 { DH6OPT_LIFETIME, "lifetime" }, 231 { DH6OPT_NIS_SERVERS, "NIS-server" }, 232 { DH6OPT_NISP_SERVERS, "NIS+-server" }, 233 { DH6OPT_NIS_NAME, "NIS-domain-name" }, 234 { DH6OPT_NISP_NAME, "NIS+-domain-name" }, 235 { DH6OPT_BCMCS_SERVER_D, "BCMCS-domain-name" }, 236 { DH6OPT_BCMCS_SERVER_A, "BCMCS-server" }, 237 { DH6OPT_GEOCONF_CIVIC, "Geoconf-Civic" }, 238 { DH6OPT_REMOTE_ID, "Remote-ID" }, 239 { DH6OPT_SUBSCRIBER_ID, "Subscriber-ID" }, 240 { DH6OPT_CLIENT_FQDN, "Client-FQDN" }, 241 { DH6OPT_PANA_AGENT, "PANA-agent" }, 242 { DH6OPT_NEW_POSIX_TIMEZONE, "POSIX-timezone" }, 243 { DH6OPT_NEW_TZDB_TIMEZONE, "POSIX-tz-database" }, 244 { DH6OPT_ERO, "Echo-request-option" }, 245 { DH6OPT_LQ_QUERY, "Lease-query" }, 246 { DH6OPT_CLIENT_DATA, "LQ-client-data" }, 247 { DH6OPT_CLT_TIME, "Clt-time" }, 248 { DH6OPT_LQ_RELAY_DATA, "LQ-relay-data" }, 249 { DH6OPT_LQ_CLIENT_LINK, "LQ-client-link" }, 250 { DH6OPT_NTP_SERVER, "NTP-server" }, 251 { DH6OPT_BOOTFILE_URL, "Bootfile-URL" }, 252 { DH6OPT_AFTR_NAME, "AFTR-Name" }, 253 { DH6OPT_MUDURL, "MUD-URL" }, 254 { DH6OPT_SZTP_REDIRECT, "SZTP-redirect" }, 255 { 0, NULL } 256 }; 257 258 static const struct tok dh6opt_stcode_str[] = { 259 { DH6OPT_STCODE_SUCCESS, "Success" }, /* RFC3315 */ 260 { DH6OPT_STCODE_UNSPECFAIL, "UnspecFail" }, /* RFC3315 */ 261 { DH6OPT_STCODE_NOADDRAVAIL, "NoAddrsAvail" }, /* RFC3315 */ 262 { DH6OPT_STCODE_NOBINDING, "NoBinding" }, /* RFC3315 */ 263 { DH6OPT_STCODE_NOTONLINK, "NotOnLink" }, /* RFC3315 */ 264 { DH6OPT_STCODE_USEMULTICAST, "UseMulticast" }, /* RFC3315 */ 265 { DH6OPT_STCODE_NOPREFIXAVAIL, "NoPrefixAvail" }, /* RFC3633 */ 266 { DH6OPT_STCODE_UNKNOWNQUERYTYPE, "UnknownQueryType" }, /* RFC5007 */ 267 { DH6OPT_STCODE_MALFORMEDQUERY, "MalformedQuery" }, /* RFC5007 */ 268 { DH6OPT_STCODE_NOTCONFIGURED, "NotConfigured" }, /* RFC5007 */ 269 { DH6OPT_STCODE_NOTALLOWED, "NotAllowed" }, /* RFC5007 */ 270 { 0, NULL } 271 }; 272 273 struct dhcp6opt { 274 nd_uint16_t dh6opt_type; 275 nd_uint16_t dh6opt_len; 276 /* type-dependent data follows */ 277 }; 278 279 static const char * 280 dhcp6stcode(const uint16_t code) 281 { 282 return code > 255 ? "INVALID code" : tok2str(dh6opt_stcode_str, "code%u", code); 283 } 284 285 static void 286 dhcp6opt_print(netdissect_options *ndo, 287 const u_char *cp, const u_char *ep) 288 { 289 const struct dhcp6opt *dh6o; 290 const u_char *tp; 291 u_int i; 292 uint16_t opttype; 293 uint16_t optlen; 294 uint8_t auth_proto; 295 uint8_t auth_alg; 296 uint8_t auth_rdm; 297 u_int authinfolen, authrealmlen; 298 u_int remain_len; /* Length of remaining options */ 299 u_int label_len; /* Label length */ 300 uint16_t subopt_code; 301 uint16_t subopt_len; 302 uint8_t dh6_reconf_type; 303 uint8_t dh6_lq_query_type; 304 u_int first_list_value; 305 uint16_t remainder_len; 306 307 if (cp == ep) 308 return; 309 while (cp < ep) { 310 if (ep < cp + sizeof(*dh6o)) 311 goto trunc; 312 dh6o = (const struct dhcp6opt *)cp; 313 ND_TCHECK_SIZE(dh6o); 314 optlen = GET_BE_U_2(dh6o->dh6opt_len); 315 if (ep < cp + sizeof(*dh6o) + optlen) 316 goto trunc; 317 opttype = GET_BE_U_2(dh6o->dh6opt_type); 318 ND_PRINT(" (%s", tok2str(dh6opt_str, "opt_%u", opttype)); 319 ND_TCHECK_LEN(cp + sizeof(*dh6o), optlen); 320 switch (opttype) { 321 case DH6OPT_CLIENTID: 322 case DH6OPT_SERVERID: 323 if (optlen < 2) { 324 /*(*/ 325 ND_PRINT(" ?)"); 326 break; 327 } 328 tp = (const u_char *)(dh6o + 1); 329 switch (GET_BE_U_2(tp)) { 330 case DUID_LLT: 331 if (optlen >= 2 + 6) { 332 ND_PRINT(" hwaddr/time type %u time %u ", 333 GET_BE_U_2(tp + 2), 334 GET_BE_U_4(tp + 4)); 335 for (i = 8; i < optlen; i++) 336 ND_PRINT("%02x", 337 GET_U_1(tp + i)); 338 /*(*/ 339 ND_PRINT(")"); 340 } else { 341 /*(*/ 342 ND_PRINT(" ?)"); 343 } 344 break; 345 case DUID_EN: 346 if (optlen >= 2 + 4) { 347 ND_PRINT(" enterprise %u ", GET_BE_U_4(tp + 2)); 348 for (i = 2 + 4; i < optlen; i++) 349 ND_PRINT("%02x", 350 GET_U_1(tp + i)); 351 /*(*/ 352 ND_PRINT(")"); 353 } else { 354 /*(*/ 355 ND_PRINT(" ?)"); 356 } 357 break; 358 case DUID_LL: 359 if (optlen >= 2 + 2) { 360 ND_PRINT(" hwaddr type %u ", 361 GET_BE_U_2(tp + 2)); 362 for (i = 4; i < optlen; i++) 363 ND_PRINT("%02x", 364 GET_U_1(tp + i)); 365 /*(*/ 366 ND_PRINT(")"); 367 } else { 368 /*(*/ 369 ND_PRINT(" ?)"); 370 } 371 break; 372 case DUID_UUID: 373 ND_PRINT(" uuid "); 374 if (optlen == 2 + 16) { 375 for (i = 2; i < optlen; i++) 376 ND_PRINT("%02x", 377 GET_U_1(tp + i)); 378 /*(*/ 379 ND_PRINT(")"); 380 } else { 381 /*(*/ 382 ND_PRINT(" ?)"); 383 } 384 break; 385 default: 386 ND_PRINT(" type %u)", GET_BE_U_2(tp)); 387 break; 388 } 389 break; 390 case DH6OPT_IA_ADDR: 391 if (optlen < 24) { 392 /*(*/ 393 ND_PRINT(" ?)"); 394 break; 395 } 396 tp = (const u_char *)(dh6o + 1); 397 ND_PRINT(" %s", GET_IP6ADDR_STRING(tp)); 398 ND_PRINT(" pltime:%u vltime:%u", 399 GET_BE_U_4(tp + 16), 400 GET_BE_U_4(tp + 20)); 401 if (optlen > 24) { 402 /* there are sub-options */ 403 dhcp6opt_print(ndo, tp + 24, tp + optlen); 404 } 405 ND_PRINT(")"); 406 break; 407 case DH6OPT_ORO: 408 case DH6OPT_ERO: 409 if (optlen % 2) { 410 ND_PRINT(" ?)"); 411 break; 412 } 413 tp = (const u_char *)(dh6o + 1); 414 for (i = 0; i < optlen; i += 2) { 415 ND_PRINT(" %s", 416 tok2str(dh6opt_str, "opt_%u", GET_BE_U_2(tp + i))); 417 } 418 ND_PRINT(")"); 419 break; 420 case DH6OPT_PREFERENCE: 421 if (optlen != 1) { 422 ND_PRINT(" ?)"); 423 break; 424 } 425 tp = (const u_char *)(dh6o + 1); 426 ND_PRINT(" %u)", GET_U_1(tp)); 427 break; 428 case DH6OPT_ELAPSED_TIME: 429 if (optlen != 2) { 430 ND_PRINT(" ?)"); 431 break; 432 } 433 tp = (const u_char *)(dh6o + 1); 434 ND_PRINT(" %u)", GET_BE_U_2(tp)); 435 break; 436 case DH6OPT_RELAY_MSG: 437 { 438 const u_char *snapend_save; 439 440 ND_PRINT(" ("); 441 tp = (const u_char *)(dh6o + 1); 442 /* 443 * Update the snapend to the end of the option before 444 * calling recursively dhcp6_print() for the nested 445 * packet. Other options may be present after the 446 * nested DHCPv6 packet. This prevents that, in 447 * dhcp6_print(), for the nested DHCPv6 packet, the 448 * remaining length < remaining caplen. 449 */ 450 snapend_save = ndo->ndo_snapend; 451 ndo->ndo_snapend = ND_MIN(tp + optlen, ndo->ndo_snapend); 452 dhcp6_print(ndo, tp, optlen); 453 ndo->ndo_snapend = snapend_save; 454 ND_PRINT(")"); 455 break; 456 } 457 case DH6OPT_AUTH: 458 if (optlen < 11) { 459 ND_PRINT(" ?)"); 460 break; 461 } 462 tp = (const u_char *)(dh6o + 1); 463 auth_proto = GET_U_1(tp); 464 switch (auth_proto) { 465 case DH6OPT_AUTHPROTO_DELAYED: 466 ND_PRINT(" proto: delayed"); 467 break; 468 case DH6OPT_AUTHPROTO_RECONFIG: 469 ND_PRINT(" proto: reconfigure"); 470 break; 471 default: 472 ND_PRINT(" proto: %u", auth_proto); 473 break; 474 } 475 tp++; 476 auth_alg = GET_U_1(tp); 477 switch (auth_alg) { 478 case DH6OPT_AUTHALG_HMACMD5: 479 /* XXX: may depend on the protocol */ 480 ND_PRINT(", alg: HMAC-MD5"); 481 break; 482 default: 483 ND_PRINT(", alg: %u", auth_alg); 484 break; 485 } 486 tp++; 487 auth_rdm = GET_U_1(tp); 488 switch (auth_rdm) { 489 case DH6OPT_AUTHRDM_MONOCOUNTER: 490 ND_PRINT(", RDM: mono"); 491 break; 492 default: 493 ND_PRINT(", RDM: %u", auth_rdm); 494 break; 495 } 496 tp++; 497 ND_PRINT(", RD:"); 498 for (i = 0; i < 4; i++, tp += 2) 499 ND_PRINT(" %04x", GET_BE_U_2(tp)); 500 501 /* protocol dependent part */ 502 authinfolen = optlen - 11; 503 switch (auth_proto) { 504 case DH6OPT_AUTHPROTO_DELAYED: 505 if (authinfolen == 0) 506 break; 507 if (authinfolen < 20) { 508 ND_PRINT(" ??"); 509 break; 510 } 511 authrealmlen = authinfolen - 20; 512 if (authrealmlen > 0) { 513 ND_PRINT(", realm: "); 514 } 515 for (i = 0; i < authrealmlen; i++, tp++) 516 ND_PRINT("%02x", GET_U_1(tp)); 517 ND_PRINT(", key ID: %08x", GET_BE_U_4(tp)); 518 tp += 4; 519 ND_PRINT(", HMAC-MD5:"); 520 for (i = 0; i < 4; i++, tp+= 4) 521 ND_PRINT(" %08x", GET_BE_U_4(tp)); 522 break; 523 case DH6OPT_AUTHPROTO_RECONFIG: 524 if (authinfolen != 17) { 525 ND_PRINT(" ??"); 526 break; 527 } 528 switch (GET_U_1(tp)) { 529 case DH6OPT_AUTHRECONFIG_KEY: 530 ND_PRINT(" reconfig-key"); 531 break; 532 case DH6OPT_AUTHRECONFIG_HMACMD5: 533 ND_PRINT(" type: HMAC-MD5"); 534 break; 535 default: 536 ND_PRINT(" type: ??"); 537 break; 538 } 539 tp++; 540 ND_PRINT(" value:"); 541 for (i = 0; i < 4; i++, tp+= 4) 542 ND_PRINT(" %08x", GET_BE_U_4(tp)); 543 break; 544 default: 545 ND_PRINT(" ??"); 546 break; 547 } 548 549 ND_PRINT(")"); 550 break; 551 case DH6OPT_RAPID_COMMIT: /* nothing todo */ 552 ND_PRINT(")"); 553 break; 554 case DH6OPT_INTERFACE_ID: 555 case DH6OPT_SUBSCRIBER_ID: 556 /* 557 * Since we cannot predict the encoding, print hex dump 558 * at most 10 characters. 559 */ 560 tp = (const u_char *)(dh6o + 1); 561 ND_PRINT(" "); 562 for (i = 0; i < optlen && i < 10; i++) 563 ND_PRINT("%02x", GET_U_1(tp + i)); 564 ND_PRINT("...)"); 565 break; 566 case DH6OPT_RECONF_MSG: 567 if (optlen != 1) { 568 ND_PRINT(" ?)"); 569 break; 570 } 571 tp = (const u_char *)(dh6o + 1); 572 dh6_reconf_type = GET_U_1(tp); 573 switch (dh6_reconf_type) { 574 case DH6_RENEW: 575 ND_PRINT(" for renew)"); 576 break; 577 case DH6_INFORM_REQ: 578 ND_PRINT(" for inf-req)"); 579 break; 580 default: 581 ND_PRINT(" for ?\?\?(%02x))", dh6_reconf_type); 582 break; 583 } 584 break; 585 case DH6OPT_RECONF_ACCEPT: /* nothing todo */ 586 ND_PRINT(")"); 587 break; 588 case DH6OPT_SIP_SERVER_A: 589 case DH6OPT_DNS_SERVERS: 590 case DH6OPT_SNTP_SERVERS: 591 case DH6OPT_NIS_SERVERS: 592 case DH6OPT_NISP_SERVERS: 593 case DH6OPT_BCMCS_SERVER_A: 594 case DH6OPT_PANA_AGENT: 595 case DH6OPT_LQ_CLIENT_LINK: 596 if (optlen % 16) { 597 ND_PRINT(" ?)"); 598 break; 599 } 600 tp = (const u_char *)(dh6o + 1); 601 for (i = 0; i < optlen; i += 16) 602 ND_PRINT(" %s", GET_IP6ADDR_STRING(tp + i)); 603 ND_PRINT(")"); 604 break; 605 case DH6OPT_SIP_SERVER_D: 606 case DH6OPT_DOMAIN_LIST: 607 tp = (const u_char *)(dh6o + 1); 608 while (tp < cp + sizeof(*dh6o) + optlen) { 609 ND_PRINT(" "); 610 if ((tp = fqdn_print(ndo, tp, cp + sizeof(*dh6o) + optlen)) == NULL) 611 goto trunc; 612 } 613 ND_PRINT(")"); 614 break; 615 case DH6OPT_STATUS_CODE: 616 if (optlen < 2) { 617 ND_PRINT(" ?)"); 618 break; 619 } 620 tp = (const u_char *)(dh6o + 1); 621 ND_PRINT(" %s)", dhcp6stcode(GET_BE_U_2(tp))); 622 break; 623 case DH6OPT_IA_NA: 624 case DH6OPT_IA_PD: 625 if (optlen < 12) { 626 ND_PRINT(" ?)"); 627 break; 628 } 629 tp = (const u_char *)(dh6o + 1); 630 ND_PRINT(" IAID:%u T1:%u T2:%u", 631 GET_BE_U_4(tp), 632 GET_BE_U_4(tp + 4), 633 GET_BE_U_4(tp + 8)); 634 if (optlen > 12) { 635 /* there are sub-options */ 636 dhcp6opt_print(ndo, tp + 12, tp + optlen); 637 } 638 ND_PRINT(")"); 639 break; 640 case DH6OPT_IA_TA: 641 if (optlen < 4) { 642 ND_PRINT(" ?)"); 643 break; 644 } 645 tp = (const u_char *)(dh6o + 1); 646 ND_PRINT(" IAID:%u", GET_BE_U_4(tp)); 647 if (optlen > 4) { 648 /* there are sub-options */ 649 dhcp6opt_print(ndo, tp + 4, tp + optlen); 650 } 651 ND_PRINT(")"); 652 break; 653 case DH6OPT_IA_PD_PREFIX: 654 if (optlen < 25) { 655 ND_PRINT(" ?)"); 656 break; 657 } 658 tp = (const u_char *)(dh6o + 1); 659 ND_PRINT(" %s/%u", GET_IP6ADDR_STRING(tp + 9), 660 GET_U_1(tp + 8)); 661 ND_PRINT(" pltime:%u vltime:%u", 662 GET_BE_U_4(tp), 663 GET_BE_U_4(tp + 4)); 664 if (optlen > 25) { 665 /* there are sub-options */ 666 dhcp6opt_print(ndo, tp + 25, tp + optlen); 667 } 668 ND_PRINT(")"); 669 break; 670 case DH6OPT_LIFETIME: 671 case DH6OPT_CLT_TIME: 672 if (optlen != 4) { 673 ND_PRINT(" ?)"); 674 break; 675 } 676 tp = (const u_char *)(dh6o + 1); 677 ND_PRINT(" %u)", GET_BE_U_4(tp)); 678 break; 679 case DH6OPT_REMOTE_ID: 680 if (optlen < 4) { 681 ND_PRINT(" ?)"); 682 break; 683 } 684 tp = (const u_char *)(dh6o + 1); 685 ND_PRINT(" %u ", GET_BE_U_4(tp)); 686 /* 687 * Print hex dump first 10 characters. 688 */ 689 for (i = 4; i < optlen && i < 14; i++) 690 ND_PRINT("%02x", GET_U_1(tp + i)); 691 ND_PRINT("...)"); 692 break; 693 case DH6OPT_LQ_QUERY: 694 if (optlen < 17) { 695 ND_PRINT(" ?)"); 696 break; 697 } 698 tp = (const u_char *)(dh6o + 1); 699 dh6_lq_query_type = GET_U_1(tp); 700 switch (dh6_lq_query_type) { 701 case 1: 702 ND_PRINT(" by-address"); 703 break; 704 case 2: 705 ND_PRINT(" by-clientID"); 706 break; 707 default: 708 ND_PRINT(" type_%u", dh6_lq_query_type); 709 break; 710 } 711 ND_PRINT(" %s", GET_IP6ADDR_STRING(tp + 1)); 712 if (optlen > 17) { 713 /* there are query-options */ 714 dhcp6opt_print(ndo, tp + 17, tp + optlen); 715 } 716 ND_PRINT(")"); 717 break; 718 case DH6OPT_CLIENT_DATA: 719 tp = (const u_char *)(dh6o + 1); 720 if (optlen > 0) { 721 /* there are encapsulated options */ 722 dhcp6opt_print(ndo, tp, tp + optlen); 723 } 724 ND_PRINT(")"); 725 break; 726 case DH6OPT_LQ_RELAY_DATA: 727 if (optlen < 16) { 728 ND_PRINT(" ?)"); 729 break; 730 } 731 tp = (const u_char *)(dh6o + 1); 732 ND_PRINT(" %s ", GET_IP6ADDR_STRING(tp)); 733 /* 734 * Print hex dump first 10 characters. 735 */ 736 for (i = 16; i < optlen && i < 26; i++) 737 ND_PRINT("%02x", GET_U_1(tp + i)); 738 ND_PRINT("...)"); 739 break; 740 case DH6OPT_NTP_SERVER: 741 if (optlen < 4) { 742 ND_PRINT(" ?)"); 743 break; 744 } 745 tp = (const u_char *)(dh6o + 1); 746 while (tp < cp + sizeof(*dh6o) + optlen - 4) { 747 subopt_code = GET_BE_U_2(tp); 748 tp += 2; 749 subopt_len = GET_BE_U_2(tp); 750 tp += 2; 751 if (tp + subopt_len > cp + sizeof(*dh6o) + optlen) 752 goto trunc; 753 ND_PRINT(" subopt:%u", subopt_code); 754 switch (subopt_code) { 755 case DH6OPT_NTP_SUBOPTION_SRV_ADDR: 756 case DH6OPT_NTP_SUBOPTION_MC_ADDR: 757 if (subopt_len != 16) { 758 ND_PRINT(" ?"); 759 break; 760 } 761 ND_PRINT(" %s", GET_IP6ADDR_STRING(tp)); 762 break; 763 case DH6OPT_NTP_SUBOPTION_SRV_FQDN: 764 ND_PRINT(" "); 765 if (fqdn_print(ndo, tp, tp + subopt_len) == NULL) 766 goto trunc; 767 break; 768 default: 769 ND_PRINT(" ?"); 770 break; 771 } 772 tp += subopt_len; 773 } 774 ND_PRINT(")"); 775 break; 776 case DH6OPT_AFTR_NAME: 777 if (optlen < 3) { 778 ND_PRINT(" ?)"); 779 break; 780 } 781 tp = (const u_char *)(dh6o + 1); 782 remain_len = optlen; 783 ND_PRINT(" "); 784 /* Encoding is described in section 3.1 of RFC 1035 */ 785 while (remain_len && GET_U_1(tp)) { 786 label_len = GET_U_1(tp); 787 tp++; 788 if (label_len < remain_len - 1) { 789 nd_printjnp(ndo, tp, label_len); 790 tp += label_len; 791 remain_len -= (label_len + 1); 792 if(GET_U_1(tp)) ND_PRINT("."); 793 } else { 794 ND_PRINT(" ?"); 795 break; 796 } 797 } 798 ND_PRINT(")"); 799 break; 800 case DH6OPT_NEW_POSIX_TIMEZONE: /* all three of these options */ 801 case DH6OPT_NEW_TZDB_TIMEZONE: /* are encoded similarly */ 802 case DH6OPT_MUDURL: /* although GMT might not work */ 803 if (optlen < 5) { 804 ND_PRINT(" ?)"); 805 break; 806 } 807 tp = (const u_char *)(dh6o + 1); 808 ND_PRINT(" "); 809 nd_printjnp(ndo, tp, optlen); 810 ND_PRINT(")"); 811 break; 812 813 case DH6OPT_BOOTFILE_URL: 814 tp = (const u_char *)(dh6o + 1); 815 ND_PRINT(" "); 816 nd_printjn(ndo, tp, optlen); 817 ND_PRINT(")"); 818 break; 819 820 case DH6OPT_SZTP_REDIRECT: 821 case DH6OPT_USER_CLASS: 822 ND_PRINT(" "); 823 tp = (const u_char *)(dh6o + 1); 824 first_list_value = TRUE; 825 remainder_len = optlen; 826 while (remainder_len >= 2) { 827 if (first_list_value == FALSE) { 828 ND_PRINT(","); 829 } 830 first_list_value = FALSE; 831 subopt_len = GET_BE_U_2(tp); 832 if (subopt_len > remainder_len-2) { 833 break; 834 } 835 tp += 2; 836 nd_printjn(ndo, tp, subopt_len); 837 tp += subopt_len; 838 remainder_len -= (subopt_len+2); 839 } 840 if (remainder_len != 0 ) { 841 ND_PRINT(" ?"); 842 } 843 ND_PRINT(")"); 844 break; 845 846 default: 847 ND_PRINT(")"); 848 break; 849 } 850 851 cp += sizeof(*dh6o) + optlen; 852 } 853 return; 854 855 trunc: 856 nd_print_trunc(ndo); 857 } 858 859 /* 860 * Print dhcp6 packets 861 */ 862 void 863 dhcp6_print(netdissect_options *ndo, 864 const u_char *cp, u_int length) 865 { 866 const struct dhcp6 *dh6; 867 const struct dhcp6_relay *dh6relay; 868 uint8_t msgtype; 869 const u_char *ep; 870 const u_char *extp; 871 const char *name; 872 873 ndo->ndo_protocol = "dhcp6"; 874 ND_PRINT("dhcp6"); 875 876 ep = ndo->ndo_snapend; 877 if (cp + length < ep) 878 ep = cp + length; 879 880 dh6 = (const struct dhcp6 *)cp; 881 dh6relay = (const struct dhcp6_relay *)cp; 882 ND_TCHECK_4(dh6->dh6_msgtypexid.xid); 883 msgtype = GET_U_1(dh6->dh6_msgtypexid.msgtype); 884 name = tok2str(dh6_msgtype_str, "msgtype-%u", msgtype); 885 886 if (!ndo->ndo_vflag) { 887 ND_PRINT(" %s", name); 888 return; 889 } 890 891 /* XXX relay agent messages have to be handled differently */ 892 893 ND_PRINT(" %s (", name); /*)*/ 894 if (msgtype != DH6_RELAY_FORW && msgtype != DH6_RELAY_REPLY) { 895 ND_PRINT("xid=%x", 896 GET_BE_U_4(dh6->dh6_msgtypexid.xid) & DH6_XIDMASK); 897 extp = (const u_char *)(dh6 + 1); 898 dhcp6opt_print(ndo, extp, ep); 899 } else { /* relay messages */ 900 ND_PRINT("linkaddr=%s", GET_IP6ADDR_STRING(dh6relay->dh6relay_linkaddr)); 901 902 ND_PRINT(" peeraddr=%s", GET_IP6ADDR_STRING(dh6relay->dh6relay_peeraddr)); 903 904 dhcp6opt_print(ndo, (const u_char *)(dh6relay + 1), ep); 905 } 906 /*(*/ 907 ND_PRINT(")"); 908 return; 909 910 trunc: 911 nd_print_trunc(ndo); 912 } 913