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