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