1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Dynamic Host Configuration Protocol version 6, for IPv6. Supports 29 * RFCs 3315, 3319, 3646, 3898, 4075, 4242, 4280, 4580, 4649, and 4704. 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 #include <netinet/dhcp6.h> 40 #include <arpa/inet.h> 41 #include <dhcp_impl.h> 42 #include <dhcp_inittab.h> 43 44 #include "snoop.h" 45 46 static const char *mtype_to_str(uint8_t); 47 static const char *option_to_str(uint8_t); 48 static const char *duidtype_to_str(uint16_t); 49 static const char *status_to_str(uint16_t); 50 static const char *entr_to_str(uint32_t); 51 static const char *reconf_to_str(uint8_t); 52 static const char *authproto_to_str(uint8_t); 53 static const char *authalg_to_str(uint8_t, uint8_t); 54 static const char *authrdm_to_str(uint8_t); 55 static const char *cwhat_to_str(uint8_t); 56 static const char *catype_to_str(uint8_t); 57 static void show_hex(const uint8_t *, int, const char *); 58 static void show_ascii(const uint8_t *, int, const char *); 59 static void show_address(const char *, const void *); 60 static void show_options(const uint8_t *, int); 61 62 int 63 interpret_dhcpv6(int flags, const uint8_t *data, int len) 64 { 65 int olen = len; 66 char *line, *lstart; 67 dhcpv6_relay_t d6r; 68 dhcpv6_message_t d6m; 69 uint_t optlen; 70 uint16_t statuscode; 71 72 if (len <= 0) { 73 (void) strlcpy(get_sum_line(), "DHCPv6?", MAXLINE); 74 return (0); 75 } 76 if (flags & F_SUM) { 77 uint_t ias; 78 dhcpv6_option_t *d6o; 79 in6_addr_t link, peer; 80 char linkstr[INET6_ADDRSTRLEN]; 81 char peerstr[INET6_ADDRSTRLEN]; 82 83 line = lstart = get_sum_line(); 84 line += snprintf(line, MAXLINE, "DHCPv6 %s", 85 mtype_to_str(data[0])); 86 if (data[0] == DHCPV6_MSG_RELAY_FORW || 87 data[0] == DHCPV6_MSG_RELAY_REPL) { 88 if (len < sizeof (d6r)) { 89 (void) strlcpy(line, "?", 90 MAXLINE - (line - lstart)); 91 return (olen); 92 } 93 /* Not much in DHCPv6 is aligned. */ 94 (void) memcpy(&d6r, data, sizeof (d6r)); 95 (void) memcpy(&link, d6r.d6r_linkaddr, sizeof (link)); 96 (void) memcpy(&peer, d6r.d6r_peeraddr, sizeof (peer)); 97 line += snprintf(line, MAXLINE - (line - lstart), 98 " HC=%d link=%s peer=%s", d6r.d6r_hop_count, 99 inet_ntop(AF_INET6, &link, linkstr, 100 sizeof (linkstr)), 101 inet_ntop(AF_INET6, &peer, peerstr, 102 sizeof (peerstr))); 103 data += sizeof (d6r); 104 len -= sizeof (d6r); 105 } else { 106 if (len < sizeof (d6m)) { 107 (void) strlcpy(line, "?", 108 MAXLINE - (line - lstart)); 109 return (olen); 110 } 111 (void) memcpy(&d6m, data, sizeof (d6m)); 112 line += snprintf(line, MAXLINE - (line - lstart), 113 " xid=%x", DHCPV6_GET_TRANSID(&d6m)); 114 data += sizeof (d6m); 115 len -= sizeof (d6m); 116 } 117 ias = 0; 118 d6o = NULL; 119 while ((d6o = dhcpv6_find_option(data, len, d6o, 120 DHCPV6_OPT_IA_NA, NULL)) != NULL) 121 ias++; 122 if (ias > 0) 123 line += snprintf(line, MAXLINE - (line - lstart), 124 " IAs=%u", ias); 125 d6o = dhcpv6_find_option(data, len, NULL, 126 DHCPV6_OPT_STATUS_CODE, &optlen); 127 optlen -= sizeof (*d6o); 128 if (d6o != NULL && optlen >= sizeof (statuscode)) { 129 (void) memcpy(&statuscode, d6o + 1, 130 sizeof (statuscode)); 131 line += snprintf(line, MAXLINE - (line - lstart), 132 " status=%u", ntohs(statuscode)); 133 optlen -= sizeof (statuscode); 134 if (optlen > 0) { 135 line += snprintf(line, 136 MAXLINE - (line - lstart), " \"%.*s\"", 137 optlen, (char *)(d6o + 1) + 2); 138 } 139 } 140 d6o = dhcpv6_find_option(data, len, NULL, 141 DHCPV6_OPT_RELAY_MSG, &optlen); 142 optlen -= sizeof (*d6o); 143 if (d6o != NULL && optlen >= 1) { 144 line += snprintf(line, MAXLINE - (line - lstart), 145 " relay=%s", mtype_to_str(*(uint8_t *)(d6o + 1))); 146 } 147 } else if (flags & F_DTAIL) { 148 show_header("DHCPv6: ", 149 "Dynamic Host Configuration Protocol Version 6", len); 150 show_space(); 151 (void) snprintf(get_line(0, 0), get_line_remain(), 152 "Message type (msg-type) = %u (%s)", data[0], 153 mtype_to_str(data[0])); 154 if (data[0] == DHCPV6_MSG_RELAY_FORW || 155 data[0] == DHCPV6_MSG_RELAY_REPL) { 156 if (len < sizeof (d6r)) { 157 (void) strlcpy(get_line(0, 0), "Truncated", 158 get_line_remain()); 159 return (olen); 160 } 161 (void) memcpy(&d6r, data, sizeof (d6r)); 162 (void) snprintf(get_line(0, 0), get_line_remain(), 163 "Hop count = %u", d6r.d6r_hop_count); 164 show_address("Link address", d6r.d6r_linkaddr); 165 show_address("Peer address", d6r.d6r_peeraddr); 166 data += sizeof (d6r); 167 len -= sizeof (d6r); 168 } else { 169 if (len < sizeof (d6m)) { 170 (void) strlcpy(get_line(0, 0), "Truncated", 171 get_line_remain()); 172 return (olen); 173 } 174 (void) memcpy(&d6m, data, sizeof (d6m)); 175 (void) snprintf(get_line(0, 0), get_line_remain(), 176 "Transaction ID = %x", DHCPV6_GET_TRANSID(&d6m)); 177 data += sizeof (d6m); 178 len -= sizeof (d6m); 179 } 180 show_space(); 181 show_options(data, len); 182 show_space(); 183 } 184 return (olen); 185 } 186 187 static const char * 188 mtype_to_str(uint8_t mtype) 189 { 190 switch (mtype) { 191 case DHCPV6_MSG_SOLICIT: 192 return ("Solicit"); 193 case DHCPV6_MSG_ADVERTISE: 194 return ("Advertise"); 195 case DHCPV6_MSG_REQUEST: 196 return ("Request"); 197 case DHCPV6_MSG_CONFIRM: 198 return ("Confirm"); 199 case DHCPV6_MSG_RENEW: 200 return ("Renew"); 201 case DHCPV6_MSG_REBIND: 202 return ("Rebind"); 203 case DHCPV6_MSG_REPLY: 204 return ("Reply"); 205 case DHCPV6_MSG_RELEASE: 206 return ("Release"); 207 case DHCPV6_MSG_DECLINE: 208 return ("Decline"); 209 case DHCPV6_MSG_RECONFIGURE: 210 return ("Reconfigure"); 211 case DHCPV6_MSG_INFO_REQ: 212 return ("Information-Request"); 213 case DHCPV6_MSG_RELAY_FORW: 214 return ("Relay-Forward"); 215 case DHCPV6_MSG_RELAY_REPL: 216 return ("Relay-Reply"); 217 default: 218 return ("Unknown"); 219 } 220 } 221 222 static const char * 223 option_to_str(uint8_t mtype) 224 { 225 switch (mtype) { 226 case DHCPV6_OPT_CLIENTID: 227 return ("Client Identifier"); 228 case DHCPV6_OPT_SERVERID: 229 return ("Server Identifier"); 230 case DHCPV6_OPT_IA_NA: 231 return ("Identity Association for Non-temporary Addresses"); 232 case DHCPV6_OPT_IA_TA: 233 return ("Identity Association for Temporary Addresses"); 234 case DHCPV6_OPT_IAADDR: 235 return ("IA Address"); 236 case DHCPV6_OPT_ORO: 237 return ("Option Request"); 238 case DHCPV6_OPT_PREFERENCE: 239 return ("Preference"); 240 case DHCPV6_OPT_ELAPSED_TIME: 241 return ("Elapsed Time"); 242 case DHCPV6_OPT_RELAY_MSG: 243 return ("Relay Message"); 244 case DHCPV6_OPT_AUTH: 245 return ("Authentication"); 246 case DHCPV6_OPT_UNICAST: 247 return ("Server Unicast"); 248 case DHCPV6_OPT_STATUS_CODE: 249 return ("Status Code"); 250 case DHCPV6_OPT_RAPID_COMMIT: 251 return ("Rapid Commit"); 252 case DHCPV6_OPT_USER_CLASS: 253 return ("User Class"); 254 case DHCPV6_OPT_VENDOR_CLASS: 255 return ("Vendor Class"); 256 case DHCPV6_OPT_VENDOR_OPT: 257 return ("Vendor-specific Information"); 258 case DHCPV6_OPT_INTERFACE_ID: 259 return ("Interface-Id"); 260 case DHCPV6_OPT_RECONF_MSG: 261 return ("Reconfigure Message"); 262 case DHCPV6_OPT_RECONF_ACC: 263 return ("Reconfigure Accept"); 264 case DHCPV6_OPT_SIP_NAMES: 265 return ("SIP Servers Domain Name List"); 266 case DHCPV6_OPT_SIP_ADDR: 267 return ("SIP Servers IPv6 Address List"); 268 case DHCPV6_OPT_DNS_ADDR: 269 return ("DNS Recursive Name Server"); 270 case DHCPV6_OPT_DNS_SEARCH: 271 return ("Domain Search List"); 272 case DHCPV6_OPT_IA_PD: 273 return ("Identity Association for Prefix Delegation"); 274 case DHCPV6_OPT_IAPREFIX: 275 return ("IA_PD Prefix"); 276 case DHCPV6_OPT_NIS_SERVERS: 277 return ("Network Information Service Servers"); 278 case DHCPV6_OPT_NIS_DOMAIN: 279 return ("Network Information Service Domain Name"); 280 case DHCPV6_OPT_SNTP_SERVERS: 281 return ("Simple Network Time Protocol Servers"); 282 case DHCPV6_OPT_INFO_REFTIME: 283 return ("Information Refresh Time"); 284 case DHCPV6_OPT_BCMCS_SRV_D: 285 return ("BCMCS Controller Domain Name List"); 286 case DHCPV6_OPT_BCMCS_SRV_A: 287 return ("BCMCS Controller IPv6 Address"); 288 case DHCPV6_OPT_GEOCONF_CVC: 289 return ("Civic Location"); 290 case DHCPV6_OPT_REMOTE_ID: 291 return ("Relay Agent Remote-ID"); 292 case DHCPV6_OPT_SUBSCRIBER: 293 return ("Relay Agent Subscriber-ID"); 294 case DHCPV6_OPT_CLIENT_FQDN: 295 return ("Client FQDN"); 296 default: 297 return ("Unknown"); 298 } 299 } 300 301 static const char * 302 duidtype_to_str(uint16_t dtype) 303 { 304 switch (dtype) { 305 case DHCPV6_DUID_LLT: 306 return ("Link-layer Address Plus Time"); 307 case DHCPV6_DUID_EN: 308 return ("Enterprise Number"); 309 case DHCPV6_DUID_LL: 310 return ("Link-layer Address"); 311 default: 312 return ("Unknown"); 313 } 314 } 315 316 static const char * 317 status_to_str(uint16_t status) 318 { 319 switch (status) { 320 case DHCPV6_STAT_SUCCESS: 321 return ("Success"); 322 case DHCPV6_STAT_UNSPECFAIL: 323 return ("Failure, reason unspecified"); 324 case DHCPV6_STAT_NOADDRS: 325 return ("No addresses for IAs"); 326 case DHCPV6_STAT_NOBINDING: 327 return ("Client binding unavailable"); 328 case DHCPV6_STAT_NOTONLINK: 329 return ("Prefix not on link"); 330 case DHCPV6_STAT_USEMCAST: 331 return ("Use multicast"); 332 case DHCPV6_STAT_NOPREFIX: 333 return ("No prefix available"); 334 default: 335 return ("Unknown"); 336 } 337 } 338 339 static const char * 340 entr_to_str(uint32_t entr) 341 { 342 switch (entr) { 343 case DHCPV6_SUN_ENT: 344 return ("Sun Microsystems"); 345 default: 346 return ("Unknown"); 347 } 348 } 349 350 static const char * 351 reconf_to_str(uint8_t msgtype) 352 { 353 switch (msgtype) { 354 case DHCPV6_RECONF_RENEW: 355 return ("Renew"); 356 case DHCPV6_RECONF_INFO: 357 return ("Information-request"); 358 default: 359 return ("Unknown"); 360 } 361 } 362 363 static const char * 364 authproto_to_str(uint8_t aproto) 365 { 366 switch (aproto) { 367 case DHCPV6_PROTO_DELAYED: 368 return ("Delayed"); 369 case DHCPV6_PROTO_RECONFIG: 370 return ("Reconfigure Key"); 371 default: 372 return ("Unknown"); 373 } 374 } 375 376 static const char * 377 authalg_to_str(uint8_t aproto, uint8_t aalg) 378 { 379 switch (aproto) { 380 case DHCPV6_PROTO_DELAYED: 381 case DHCPV6_PROTO_RECONFIG: 382 switch (aalg) { 383 case DHCPV6_ALG_HMAC_MD5: 384 return ("HMAC-MD5 Signature"); 385 default: 386 return ("Unknown"); 387 } 388 break; 389 default: 390 return ("Unknown"); 391 } 392 } 393 394 static const char * 395 authrdm_to_str(uint8_t ardm) 396 { 397 switch (ardm) { 398 case DHCPV6_RDM_MONOCNT: 399 return ("Monotonic Counter"); 400 default: 401 return ("Unknown"); 402 } 403 } 404 405 static const char * 406 cwhat_to_str(uint8_t what) 407 { 408 switch (what) { 409 case DHCPV6_CWHAT_SERVER: 410 return ("Server"); 411 case DHCPV6_CWHAT_NETWORK: 412 return ("Network"); 413 case DHCPV6_CWHAT_CLIENT: 414 return ("Client"); 415 default: 416 return ("Unknown"); 417 } 418 } 419 420 static const char * 421 catype_to_str(uint8_t catype) 422 { 423 switch (catype) { 424 case CIVICADDR_LANG: 425 return ("Language; RFC 2277"); 426 case CIVICADDR_A1: 427 return ("National division (state)"); 428 case CIVICADDR_A2: 429 return ("County"); 430 case CIVICADDR_A3: 431 return ("City"); 432 case CIVICADDR_A4: 433 return ("City division"); 434 case CIVICADDR_A5: 435 return ("Neighborhood"); 436 case CIVICADDR_A6: 437 return ("Street group"); 438 case CIVICADDR_PRD: 439 return ("Leading street direction"); 440 case CIVICADDR_POD: 441 return ("Trailing street suffix"); 442 case CIVICADDR_STS: 443 return ("Street suffix or type"); 444 case CIVICADDR_HNO: 445 return ("House number"); 446 case CIVICADDR_HNS: 447 return ("House number suffix"); 448 case CIVICADDR_LMK: 449 return ("Landmark"); 450 case CIVICADDR_LOC: 451 return ("Additional location information"); 452 case CIVICADDR_NAM: 453 return ("Name/occupant"); 454 case CIVICADDR_PC: 455 return ("Postal Code/ZIP"); 456 case CIVICADDR_BLD: 457 return ("Building"); 458 case CIVICADDR_UNIT: 459 return ("Unit/apt/suite"); 460 case CIVICADDR_FLR: 461 return ("Floor"); 462 case CIVICADDR_ROOM: 463 return ("Room number"); 464 case CIVICADDR_TYPE: 465 return ("Place type"); 466 case CIVICADDR_PCN: 467 return ("Postal community name"); 468 case CIVICADDR_POBOX: 469 return ("Post office box"); 470 case CIVICADDR_ADDL: 471 return ("Additional code"); 472 case CIVICADDR_SEAT: 473 return ("Seat/desk"); 474 case CIVICADDR_ROAD: 475 return ("Primary road or street"); 476 case CIVICADDR_RSEC: 477 return ("Road section"); 478 case CIVICADDR_RBRA: 479 return ("Road branch"); 480 case CIVICADDR_RSBR: 481 return ("Road sub-branch"); 482 case CIVICADDR_SPRE: 483 return ("Street name pre-modifier"); 484 case CIVICADDR_SPOST: 485 return ("Street name post-modifier"); 486 case CIVICADDR_SCRIPT: 487 return ("Script"); 488 default: 489 return ("Unknown"); 490 } 491 } 492 493 static void 494 show_hex(const uint8_t *data, int len, const char *name) 495 { 496 char buffer[16 * 3 + 1]; 497 int nlen; 498 int i; 499 char sep; 500 501 nlen = strlen(name); 502 sep = '='; 503 while (len > 0) { 504 for (i = 0; i < 16 && i < len; i++) 505 (void) snprintf(buffer + 3 * i, 4, " %02x", *data++); 506 (void) snprintf(get_line(0, 0), get_line_remain(), "%*s %c%s", 507 nlen, name, sep, buffer); 508 name = ""; 509 sep = ' '; 510 len -= i; 511 } 512 } 513 514 static void 515 show_ascii(const uint8_t *data, int len, const char *name) 516 { 517 char buffer[64], *bp; 518 int nlen; 519 int i; 520 char sep; 521 522 nlen = strlen(name); 523 sep = '='; 524 while (len > 0) { 525 bp = buffer; 526 for (i = 0; i < sizeof (buffer) - 4 && len > 0; len--) { 527 if (!isascii(*data) || !isprint(*data)) 528 bp += snprintf(bp, 5, "\\%03o", *data++); 529 else 530 *bp++; 531 } 532 *bp = '\0'; 533 (void) snprintf(get_line(0, 0), get_line_remain(), 534 "%*s %c \"%s\"", nlen, name, sep, buffer); 535 sep = ' '; 536 name = ""; 537 } 538 } 539 540 static void 541 show_address(const char *addrname, const void *aptr) 542 { 543 char *hname; 544 char addrstr[INET6_ADDRSTRLEN]; 545 in6_addr_t addr; 546 547 (void) memcpy(&addr, aptr, sizeof (in6_addr_t)); 548 (void) inet_ntop(AF_INET6, &addr, addrstr, sizeof (addrstr)); 549 hname = addrtoname(AF_INET6, &addr); 550 if (strcmp(hname, addrstr) == 0) { 551 (void) snprintf(get_line(0, 0), get_line_remain(), "%s = %s", 552 addrname, addrstr); 553 } else { 554 (void) snprintf(get_line(0, 0), get_line_remain(), 555 "%s = %s (%s)", addrname, addrstr, hname); 556 } 557 } 558 559 static void 560 nest_options(const uint8_t *data, uint_t olen, char *prefix, char *title) 561 { 562 char *str, *oldnest, *oldprefix; 563 564 if (olen <= 0) 565 return; 566 oldprefix = prot_prefix; 567 oldnest = prot_nest_prefix; 568 str = malloc(strlen(prot_nest_prefix) + strlen(prot_prefix) + 1); 569 if (str == NULL) { 570 prot_nest_prefix = prot_prefix; 571 } else { 572 (void) sprintf(str, "%s%s", prot_nest_prefix, prot_prefix); 573 prot_nest_prefix = str; 574 } 575 show_header(prefix, title, 0); 576 show_options(data, olen); 577 free(str); 578 prot_prefix = oldprefix; 579 prot_nest_prefix = oldnest; 580 } 581 582 static void 583 show_options(const uint8_t *data, int len) 584 { 585 dhcpv6_option_t d6o; 586 uint_t olen, retlen; 587 uint16_t val16; 588 uint16_t type; 589 uint32_t val32; 590 const uint8_t *ostart; 591 char *str, *sp; 592 char *oldnest; 593 594 /* 595 * Be very careful with negative numbers; ANSI signed/unsigned 596 * comparison doesn't work as expected. 597 */ 598 while (len >= (signed)sizeof (d6o)) { 599 (void) memcpy(&d6o, data, sizeof (d6o)); 600 d6o.d6o_code = ntohs(d6o.d6o_code); 601 d6o.d6o_len = olen = ntohs(d6o.d6o_len); 602 (void) snprintf(get_line(0, 0), get_line_remain(), 603 "Option Code = %u (%s)", d6o.d6o_code, 604 option_to_str(d6o.d6o_code)); 605 ostart = data += sizeof (d6o); 606 len -= sizeof (d6o); 607 if (olen > len) { 608 (void) strlcpy(get_line(0, 0), "Option truncated", 609 get_line_remain()); 610 olen = len; 611 } 612 switch (d6o.d6o_code) { 613 case DHCPV6_OPT_CLIENTID: 614 case DHCPV6_OPT_SERVERID: 615 if (olen < sizeof (val16)) 616 break; 617 (void) memcpy(&val16, data, sizeof (val16)); 618 data += sizeof (val16); 619 olen -= sizeof (val16); 620 type = ntohs(val16); 621 (void) snprintf(get_line(0, 0), get_line_remain(), 622 " DUID Type = %u (%s)", type, 623 duidtype_to_str(type)); 624 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 625 if (olen < sizeof (val16)) 626 break; 627 (void) memcpy(&val16, data, sizeof (val16)); 628 data += sizeof (val16); 629 olen -= sizeof (val16); 630 val16 = ntohs(val16); 631 (void) snprintf(get_line(0, 0), 632 get_line_remain(), 633 " Hardware Type = %u (%s)", val16, 634 arp_htype(type)); 635 } 636 if (type == DHCPV6_DUID_LLT) { 637 time_t timevalue; 638 639 if (olen < sizeof (val32)) 640 break; 641 (void) memcpy(&val32, data, sizeof (val32)); 642 data += sizeof (val32); 643 olen -= sizeof (val32); 644 timevalue = ntohl(val32) + DUID_TIME_BASE; 645 (void) snprintf(get_line(0, 0), 646 get_line_remain(), 647 " Time = %lu (%.24s)", ntohl(val32), 648 ctime(&timevalue)); 649 } 650 if (type == DHCPV6_DUID_EN) { 651 if (olen < sizeof (val32)) 652 break; 653 (void) memcpy(&val32, data, sizeof (val32)); 654 data += sizeof (val32); 655 olen -= sizeof (val32); 656 val32 = ntohl(val32); 657 (void) snprintf(get_line(0, 0), 658 get_line_remain(), 659 " Enterprise Number = %lu (%s)", val32, 660 entr_to_str(val32)); 661 } 662 if (olen == 0) 663 break; 664 if ((str = malloc(olen * 3)) == NULL) 665 pr_err("interpret_dhcpv6: no mem"); 666 sp = str + snprintf(str, 3, "%02x", *data++); 667 while (--olen > 0) { 668 *sp++ = (type == DHCPV6_DUID_LLT || 669 type == DHCPV6_DUID_LL) ? ':' : ' '; 670 sp = sp + snprintf(sp, 3, "%02x", *data++); 671 } 672 (void) snprintf(get_line(0, 0), get_line_remain(), 673 (type == DHCPV6_DUID_LLT || 674 type == DHCPV6_DUID_LL) ? 675 " Link Layer Address = %s" : 676 " Identifier = %s", str); 677 free(str); 678 break; 679 case DHCPV6_OPT_IA_NA: 680 case DHCPV6_OPT_IA_PD: { 681 dhcpv6_ia_na_t d6in; 682 683 if (olen < sizeof (d6in) - sizeof (d6o)) 684 break; 685 (void) memcpy(&d6in, data - sizeof (d6o), 686 sizeof (d6in)); 687 data += sizeof (d6in) - sizeof (d6o); 688 olen -= sizeof (d6in) - sizeof (d6o); 689 (void) snprintf(get_line(0, 0), get_line_remain(), 690 " IAID = %u", ntohl(d6in.d6in_iaid)); 691 (void) snprintf(get_line(0, 0), get_line_remain(), 692 " T1 (renew) = %u seconds", ntohl(d6in.d6in_t1)); 693 (void) snprintf(get_line(0, 0), get_line_remain(), 694 " T2 (rebind) = %u seconds", ntohl(d6in.d6in_t2)); 695 nest_options(data, olen, "IA: ", 696 "Identity Association"); 697 break; 698 } 699 case DHCPV6_OPT_IA_TA: { 700 dhcpv6_ia_ta_t d6it; 701 702 if (olen < sizeof (d6it) - sizeof (d6o)) 703 break; 704 (void) memcpy(&d6it, data - sizeof (d6o), 705 sizeof (d6it)); 706 data += sizeof (d6it) - sizeof (d6o); 707 olen -= sizeof (d6it) - sizeof (d6o); 708 (void) snprintf(get_line(0, 0), get_line_remain(), 709 " IAID = %u", ntohl(d6it.d6it_iaid)); 710 nest_options(data, olen, "IA: ", 711 "Identity Association"); 712 break; 713 } 714 case DHCPV6_OPT_IAADDR: { 715 dhcpv6_iaaddr_t d6ia; 716 717 if (olen < sizeof (d6ia) - sizeof (d6o)) 718 break; 719 (void) memcpy(&d6ia, data - sizeof (d6o), 720 sizeof (d6ia)); 721 data += sizeof (d6ia) - sizeof (d6o); 722 olen -= sizeof (d6ia) - sizeof (d6o); 723 show_address(" Address", &d6ia.d6ia_addr); 724 (void) snprintf(get_line(0, 0), get_line_remain(), 725 " Preferred lifetime = %u seconds", 726 ntohl(d6ia.d6ia_preflife)); 727 (void) snprintf(get_line(0, 0), get_line_remain(), 728 " Valid lifetime = %u seconds", 729 ntohl(d6ia.d6ia_vallife)); 730 nest_options(data, olen, "ADDR: ", "Address"); 731 break; 732 } 733 case DHCPV6_OPT_ORO: 734 while (olen >= sizeof (val16)) { 735 (void) memcpy(&val16, data, sizeof (val16)); 736 val16 = ntohs(val16); 737 (void) snprintf(get_line(0, 0), 738 get_line_remain(), 739 " Requested Option Code = %u (%s)", val16, 740 option_to_str(val16)); 741 data += sizeof (val16); 742 olen -= sizeof (val16); 743 } 744 break; 745 case DHCPV6_OPT_PREFERENCE: 746 if (olen > 0) { 747 (void) snprintf(get_line(0, 0), 748 get_line_remain(), 749 *data == 255 ? 750 " Preference = %u (immediate)" : 751 " Preference = %u", *data); 752 } 753 break; 754 case DHCPV6_OPT_ELAPSED_TIME: 755 if (olen == sizeof (val16)) { 756 (void) memcpy(&val16, data, sizeof (val16)); 757 val16 = ntohs(val16); 758 (void) snprintf(get_line(0, 0), 759 get_line_remain(), 760 " Elapsed Time = %u.%02u seconds", 761 val16 / 100, val16 % 100); 762 } 763 break; 764 case DHCPV6_OPT_RELAY_MSG: 765 if (olen > 0) { 766 oldnest = prot_nest_prefix; 767 prot_nest_prefix = prot_prefix; 768 retlen = interpret_dhcpv6(F_DTAIL, data, olen); 769 prot_prefix = prot_nest_prefix; 770 prot_nest_prefix = oldnest; 771 } 772 break; 773 case DHCPV6_OPT_AUTH: { 774 dhcpv6_auth_t d6a; 775 776 if (olen < DHCPV6_AUTH_SIZE - sizeof (d6o)) 777 break; 778 (void) memcpy(&d6a, data - sizeof (d6o), 779 DHCPV6_AUTH_SIZE); 780 data += DHCPV6_AUTH_SIZE - sizeof (d6o); 781 olen += DHCPV6_AUTH_SIZE - sizeof (d6o); 782 (void) snprintf(get_line(0, 0), get_line_remain(), 783 " Protocol = %u (%s)", d6a.d6a_proto, 784 authproto_to_str(d6a.d6a_proto)); 785 (void) snprintf(get_line(0, 0), get_line_remain(), 786 " Algorithm = %u (%s)", d6a.d6a_alg, 787 authalg_to_str(d6a.d6a_proto, d6a.d6a_alg)); 788 (void) snprintf(get_line(0, 0), get_line_remain(), 789 " Replay Detection Method = %u (%s)", d6a.d6a_rdm, 790 authrdm_to_str(d6a.d6a_rdm)); 791 show_hex(d6a.d6a_replay, sizeof (d6a.d6a_replay), 792 " RDM Data"); 793 if (olen > 0) 794 show_hex(data, olen, " Auth Info"); 795 break; 796 } 797 case DHCPV6_OPT_UNICAST: 798 if (olen >= sizeof (in6_addr_t)) 799 show_address(" Server Address", data); 800 break; 801 case DHCPV6_OPT_STATUS_CODE: 802 if (olen < sizeof (val16)) 803 break; 804 (void) memcpy(&val16, data, sizeof (val16)); 805 val16 = ntohs(val16); 806 (void) snprintf(get_line(0, 0), get_line_remain(), 807 " Status Code = %u (%s)", val16, 808 status_to_str(val16)); 809 data += sizeof (val16); 810 olen -= sizeof (val16); 811 if (olen > 0) 812 (void) snprintf(get_line(0, 0), 813 get_line_remain(), " Text = \"%.*s\"", 814 olen, data); 815 break; 816 case DHCPV6_OPT_VENDOR_CLASS: 817 if (olen < sizeof (val32)) 818 break; 819 (void) memcpy(&val32, data, sizeof (val32)); 820 data += sizeof (val32); 821 olen -= sizeof (val32); 822 val32 = ntohl(val32); 823 (void) snprintf(get_line(0, 0), get_line_remain(), 824 " Enterprise Number = %lu (%s)", val32, 825 entr_to_str(val32)); 826 /* FALLTHROUGH */ 827 case DHCPV6_OPT_USER_CLASS: 828 while (olen >= sizeof (val16)) { 829 (void) memcpy(&val16, data, sizeof (val16)); 830 data += sizeof (val16); 831 olen -= sizeof (val16); 832 val16 = ntohs(val16); 833 if (val16 > olen) { 834 (void) strlcpy(get_line(0, 0), 835 " Truncated class", 836 get_line_remain()); 837 val16 = olen; 838 } 839 show_hex(data, olen, " Class"); 840 data += val16; 841 olen -= val16; 842 } 843 break; 844 case DHCPV6_OPT_VENDOR_OPT: { 845 dhcpv6_option_t sd6o; 846 847 if (olen < sizeof (val32)) 848 break; 849 (void) memcpy(&val32, data, sizeof (val32)); 850 data += sizeof (val32); 851 olen -= sizeof (val32); 852 val32 = ntohl(val32); 853 (void) snprintf(get_line(0, 0), get_line_remain(), 854 " Enterprise Number = %lu (%s)", val32, 855 entr_to_str(val32)); 856 while (olen >= sizeof (sd6o)) { 857 (void) memcpy(&sd6o, data, sizeof (sd6o)); 858 sd6o.d6o_code = ntohs(sd6o.d6o_code); 859 sd6o.d6o_len = ntohs(sd6o.d6o_len); 860 (void) snprintf(get_line(0, 0), 861 get_line_remain(), 862 " Vendor Option Code = %u", d6o.d6o_code); 863 data += sizeof (d6o); 864 olen -= sizeof (d6o); 865 if (sd6o.d6o_len > olen) { 866 (void) strlcpy(get_line(0, 0), 867 " Vendor Option truncated", 868 get_line_remain()); 869 sd6o.d6o_len = olen; 870 } 871 if (sd6o.d6o_len > 0) { 872 show_hex(data, sd6o.d6o_len, 873 " Data"); 874 data += sd6o.d6o_len; 875 olen -= sd6o.d6o_len; 876 } 877 } 878 break; 879 } 880 case DHCPV6_OPT_REMOTE_ID: 881 if (olen < sizeof (val32)) 882 break; 883 (void) memcpy(&val32, data, sizeof (val32)); 884 data += sizeof (val32); 885 olen -= sizeof (val32); 886 val32 = ntohl(val32); 887 (void) snprintf(get_line(0, 0), get_line_remain(), 888 " Enterprise Number = %lu (%s)", val32, 889 entr_to_str(val32)); 890 /* FALLTHROUGH */ 891 case DHCPV6_OPT_INTERFACE_ID: 892 case DHCPV6_OPT_SUBSCRIBER: 893 if (olen > 0) 894 show_hex(data, olen, " ID"); 895 break; 896 case DHCPV6_OPT_RECONF_MSG: 897 if (olen > 0) { 898 (void) snprintf(get_line(0, 0), 899 get_line_remain(), 900 " Message Type = %u (%s)", *data, 901 reconf_to_str(*data)); 902 } 903 break; 904 case DHCPV6_OPT_SIP_NAMES: 905 case DHCPV6_OPT_DNS_SEARCH: 906 case DHCPV6_OPT_NIS_DOMAIN: 907 case DHCPV6_OPT_BCMCS_SRV_D: { 908 dhcp_symbol_t *symp; 909 char *sp2; 910 911 symp = inittab_getbycode( 912 ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP, 913 d6o.d6o_code); 914 if (symp != NULL) { 915 str = inittab_decode(symp, data, olen, B_TRUE); 916 if (str != NULL) { 917 sp = str; 918 do { 919 sp2 = strchr(sp, ' '); 920 if (sp2 != NULL) 921 *sp2++ = '\0'; 922 (void) snprintf(get_line(0, 0), 923 get_line_remain(), 924 " Name = %s", sp); 925 } while ((sp = sp2) != NULL); 926 free(str); 927 } 928 free(symp); 929 } 930 break; 931 } 932 case DHCPV6_OPT_SIP_ADDR: 933 case DHCPV6_OPT_DNS_ADDR: 934 case DHCPV6_OPT_NIS_SERVERS: 935 case DHCPV6_OPT_SNTP_SERVERS: 936 case DHCPV6_OPT_BCMCS_SRV_A: 937 while (olen >= sizeof (in6_addr_t)) { 938 show_address(" Address", data); 939 data += sizeof (in6_addr_t); 940 olen -= sizeof (in6_addr_t); 941 } 942 break; 943 case DHCPV6_OPT_IAPREFIX: { 944 dhcpv6_iaprefix_t d6ip; 945 946 if (olen < DHCPV6_IAPREFIX_SIZE - sizeof (d6o)) 947 break; 948 (void) memcpy(&d6ip, data - sizeof (d6o), 949 DHCPV6_IAPREFIX_SIZE); 950 data += DHCPV6_IAPREFIX_SIZE - sizeof (d6o); 951 olen -= DHCPV6_IAPREFIX_SIZE - sizeof (d6o); 952 show_address(" Prefix", d6ip.d6ip_addr); 953 (void) snprintf(get_line(0, 0), get_line_remain(), 954 " Preferred lifetime = %u seconds", 955 ntohl(d6ip.d6ip_preflife)); 956 (void) snprintf(get_line(0, 0), get_line_remain(), 957 " Valid lifetime = %u seconds", 958 ntohl(d6ip.d6ip_vallife)); 959 (void) snprintf(get_line(0, 0), get_line_remain(), 960 " Prefix length = %u", d6ip.d6ip_preflen); 961 nest_options(data, olen, "ADDR: ", "Address"); 962 break; 963 } 964 case DHCPV6_OPT_INFO_REFTIME: 965 if (olen < sizeof (val32)) 966 break; 967 (void) memcpy(&val32, data, sizeof (val32)); 968 (void) snprintf(get_line(0, 0), get_line_remain(), 969 " Refresh Time = %lu seconds", ntohl(val32)); 970 break; 971 case DHCPV6_OPT_GEOCONF_CVC: { 972 dhcpv6_civic_t d6c; 973 int solen; 974 975 if (olen < DHCPV6_CIVIC_SIZE - sizeof (d6o)) 976 break; 977 (void) memcpy(&d6c, data - sizeof (d6o), 978 DHCPV6_CIVIC_SIZE); 979 data += DHCPV6_CIVIC_SIZE - sizeof (d6o); 980 olen -= DHCPV6_CIVIC_SIZE - sizeof (d6o); 981 (void) snprintf(get_line(0, 0), get_line_remain(), 982 " What Location = %u (%s)", d6c.d6c_what, 983 cwhat_to_str(d6c.d6c_what)); 984 (void) snprintf(get_line(0, 0), get_line_remain(), 985 " Country Code = %.*s", sizeof (d6c.d6c_cc), 986 d6c.d6c_cc); 987 while (olen >= 2) { 988 (void) snprintf(get_line(0, 0), 989 get_line_remain(), 990 " CA Element = %u (%s)", *data, 991 catype_to_str(*data)); 992 solen = data[1]; 993 data += 2; 994 olen -= 2; 995 if (solen > olen) { 996 (void) strlcpy(get_line(0, 0), 997 " CA Element truncated", 998 get_line_remain()); 999 solen = olen; 1000 } 1001 if (solen > 0) { 1002 show_ascii(data, solen, " CA Data"); 1003 data += solen; 1004 olen -= solen; 1005 } 1006 } 1007 break; 1008 } 1009 case DHCPV6_OPT_CLIENT_FQDN: { 1010 dhcp_symbol_t *symp; 1011 1012 if (olen == 0) 1013 break; 1014 (void) snprintf(get_line(0, 0), get_line_remain(), 1015 " Flags = %02x", *data); 1016 (void) snprintf(get_line(0, 0), get_line_remain(), 1017 " %s", getflag(*data, DHCPV6_FQDNF_S, 1018 "Perform AAAA RR updates", "No AAAA RR updates")); 1019 (void) snprintf(get_line(0, 0), get_line_remain(), 1020 " %s", getflag(*data, DHCPV6_FQDNF_O, 1021 "Server override updates", 1022 "No server override updates")); 1023 (void) snprintf(get_line(0, 0), get_line_remain(), 1024 " %s", getflag(*data, DHCPV6_FQDNF_N, 1025 "Server performs no updates", 1026 "Server performs updates")); 1027 symp = inittab_getbycode( 1028 ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP, 1029 d6o.d6o_code); 1030 if (symp != NULL) { 1031 str = inittab_decode(symp, data, olen, B_TRUE); 1032 if (str != NULL) { 1033 (void) snprintf(get_line(0, 0), 1034 get_line_remain(), 1035 " FQDN = %s", str); 1036 free(str); 1037 } 1038 free(symp); 1039 } 1040 break; 1041 } 1042 } 1043 data = ostart + d6o.d6o_len; 1044 len -= d6o.d6o_len; 1045 } 1046 if (len != 0) { 1047 (void) strlcpy(get_line(0, 0), "Option entry truncated", 1048 get_line_remain()); 1049 } 1050 }