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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Dynamic Host Configuration Protocol version 6, for IPv6. Supports 31 * RFCs 3315, 3319, 3646, 3898, 4075, 4242, 4280, 4580, 4649, and 4704. 32 */ 33 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_NISP_SERVERS: 281 return ("Network Information Service V2 Servers"); 282 case DHCPV6_OPT_NIS_DOMAIN: 283 return ("Network Information Service Domain Name"); 284 case DHCPV6_OPT_NISP_DOMAIN: 285 return ("Network Information Service V2 Domain Name"); 286 case DHCPV6_OPT_SNTP_SERVERS: 287 return ("Simple Network Time Protocol Servers"); 288 case DHCPV6_OPT_INFO_REFTIME: 289 return ("Information Refresh Time"); 290 case DHCPV6_OPT_BCMCS_SRV_D: 291 return ("BCMCS Controller Domain Name List"); 292 case DHCPV6_OPT_BCMCS_SRV_A: 293 return ("BCMCS Controller IPv6 Address"); 294 case DHCPV6_OPT_GEOCONF_CVC: 295 return ("Civic Location"); 296 case DHCPV6_OPT_REMOTE_ID: 297 return ("Relay Agent Remote-ID"); 298 case DHCPV6_OPT_SUBSCRIBER: 299 return ("Relay Agent Subscriber-ID"); 300 case DHCPV6_OPT_CLIENT_FQDN: 301 return ("Client FQDN"); 302 default: 303 return ("Unknown"); 304 } 305 } 306 307 static const char * 308 duidtype_to_str(uint16_t dtype) 309 { 310 switch (dtype) { 311 case DHCPV6_DUID_LLT: 312 return ("Link-layer Address Plus Time"); 313 case DHCPV6_DUID_EN: 314 return ("Enterprise Number"); 315 case DHCPV6_DUID_LL: 316 return ("Link-layer Address"); 317 default: 318 return ("Unknown"); 319 } 320 } 321 322 static const char * 323 status_to_str(uint16_t status) 324 { 325 switch (status) { 326 case DHCPV6_STAT_SUCCESS: 327 return ("Success"); 328 case DHCPV6_STAT_UNSPECFAIL: 329 return ("Failure, reason unspecified"); 330 case DHCPV6_STAT_NOADDRS: 331 return ("No addresses for IAs"); 332 case DHCPV6_STAT_NOBINDING: 333 return ("Client binding unavailable"); 334 case DHCPV6_STAT_NOTONLINK: 335 return ("Prefix not on link"); 336 case DHCPV6_STAT_USEMCAST: 337 return ("Use multicast"); 338 case DHCPV6_STAT_NOPREFIX: 339 return ("No prefix available"); 340 default: 341 return ("Unknown"); 342 } 343 } 344 345 static const char * 346 entr_to_str(uint32_t entr) 347 { 348 switch (entr) { 349 case DHCPV6_SUN_ENT: 350 return ("Sun Microsystems"); 351 default: 352 return ("Unknown"); 353 } 354 } 355 356 static const char * 357 reconf_to_str(uint8_t msgtype) 358 { 359 switch (msgtype) { 360 case DHCPV6_RECONF_RENEW: 361 return ("Renew"); 362 case DHCPV6_RECONF_INFO: 363 return ("Information-request"); 364 default: 365 return ("Unknown"); 366 } 367 } 368 369 static const char * 370 authproto_to_str(uint8_t aproto) 371 { 372 switch (aproto) { 373 case DHCPV6_PROTO_DELAYED: 374 return ("Delayed"); 375 case DHCPV6_PROTO_RECONFIG: 376 return ("Reconfigure Key"); 377 default: 378 return ("Unknown"); 379 } 380 } 381 382 static const char * 383 authalg_to_str(uint8_t aproto, uint8_t aalg) 384 { 385 switch (aproto) { 386 case DHCPV6_PROTO_DELAYED: 387 case DHCPV6_PROTO_RECONFIG: 388 switch (aalg) { 389 case DHCPV6_ALG_HMAC_MD5: 390 return ("HMAC-MD5 Signature"); 391 default: 392 return ("Unknown"); 393 } 394 break; 395 default: 396 return ("Unknown"); 397 } 398 } 399 400 static const char * 401 authrdm_to_str(uint8_t ardm) 402 { 403 switch (ardm) { 404 case DHCPV6_RDM_MONOCNT: 405 return ("Monotonic Counter"); 406 default: 407 return ("Unknown"); 408 } 409 } 410 411 static const char * 412 cwhat_to_str(uint8_t what) 413 { 414 switch (what) { 415 case DHCPV6_CWHAT_SERVER: 416 return ("Server"); 417 case DHCPV6_CWHAT_NETWORK: 418 return ("Network"); 419 case DHCPV6_CWHAT_CLIENT: 420 return ("Client"); 421 default: 422 return ("Unknown"); 423 } 424 } 425 426 static const char * 427 catype_to_str(uint8_t catype) 428 { 429 switch (catype) { 430 case CIVICADDR_LANG: 431 return ("Language; RFC 2277"); 432 case CIVICADDR_A1: 433 return ("National division (state)"); 434 case CIVICADDR_A2: 435 return ("County"); 436 case CIVICADDR_A3: 437 return ("City"); 438 case CIVICADDR_A4: 439 return ("City division"); 440 case CIVICADDR_A5: 441 return ("Neighborhood"); 442 case CIVICADDR_A6: 443 return ("Street group"); 444 case CIVICADDR_PRD: 445 return ("Leading street direction"); 446 case CIVICADDR_POD: 447 return ("Trailing street suffix"); 448 case CIVICADDR_STS: 449 return ("Street suffix or type"); 450 case CIVICADDR_HNO: 451 return ("House number"); 452 case CIVICADDR_HNS: 453 return ("House number suffix"); 454 case CIVICADDR_LMK: 455 return ("Landmark"); 456 case CIVICADDR_LOC: 457 return ("Additional location information"); 458 case CIVICADDR_NAM: 459 return ("Name/occupant"); 460 case CIVICADDR_PC: 461 return ("Postal Code/ZIP"); 462 case CIVICADDR_BLD: 463 return ("Building"); 464 case CIVICADDR_UNIT: 465 return ("Unit/apt/suite"); 466 case CIVICADDR_FLR: 467 return ("Floor"); 468 case CIVICADDR_ROOM: 469 return ("Room number"); 470 case CIVICADDR_TYPE: 471 return ("Place type"); 472 case CIVICADDR_PCN: 473 return ("Postal community name"); 474 case CIVICADDR_POBOX: 475 return ("Post office box"); 476 case CIVICADDR_ADDL: 477 return ("Additional code"); 478 case CIVICADDR_SEAT: 479 return ("Seat/desk"); 480 case CIVICADDR_ROAD: 481 return ("Primary road or street"); 482 case CIVICADDR_RSEC: 483 return ("Road section"); 484 case CIVICADDR_RBRA: 485 return ("Road branch"); 486 case CIVICADDR_RSBR: 487 return ("Road sub-branch"); 488 case CIVICADDR_SPRE: 489 return ("Street name pre-modifier"); 490 case CIVICADDR_SPOST: 491 return ("Street name post-modifier"); 492 case CIVICADDR_SCRIPT: 493 return ("Script"); 494 default: 495 return ("Unknown"); 496 } 497 } 498 499 static void 500 show_hex(const uint8_t *data, int len, const char *name) 501 { 502 char buffer[16 * 3 + 1]; 503 int nlen; 504 int i; 505 char sep; 506 507 nlen = strlen(name); 508 sep = '='; 509 while (len > 0) { 510 for (i = 0; i < 16 && i < len; i++) 511 (void) snprintf(buffer + 3 * i, 4, " %02x", *data++); 512 (void) snprintf(get_line(0, 0), get_line_remain(), "%*s %c%s", 513 nlen, name, sep, buffer); 514 name = ""; 515 sep = ' '; 516 len -= i; 517 } 518 } 519 520 static void 521 show_ascii(const uint8_t *data, int len, const char *name) 522 { 523 char buffer[64], *bp; 524 int nlen; 525 int i; 526 char sep; 527 528 nlen = strlen(name); 529 sep = '='; 530 while (len > 0) { 531 bp = buffer; 532 for (i = 0; i < sizeof (buffer) - 4 && len > 0; len--) { 533 if (!isascii(*data) || !isprint(*data)) 534 bp += snprintf(bp, 5, "\\%03o", *data++); 535 else 536 *bp++; 537 } 538 *bp = '\0'; 539 (void) snprintf(get_line(0, 0), get_line_remain(), 540 "%*s %c \"%s\"", nlen, name, sep, buffer); 541 sep = ' '; 542 name = ""; 543 } 544 } 545 546 static void 547 show_address(const char *addrname, const void *aptr) 548 { 549 char *hname; 550 char addrstr[INET6_ADDRSTRLEN]; 551 in6_addr_t addr; 552 553 (void) memcpy(&addr, aptr, sizeof (in6_addr_t)); 554 (void) inet_ntop(AF_INET6, &addr, addrstr, sizeof (addrstr)); 555 hname = addrtoname(AF_INET6, &addr); 556 if (strcmp(hname, addrstr) == 0) { 557 (void) snprintf(get_line(0, 0), get_line_remain(), "%s = %s", 558 addrname, addrstr); 559 } else { 560 (void) snprintf(get_line(0, 0), get_line_remain(), 561 "%s = %s (%s)", addrname, addrstr, hname); 562 } 563 } 564 565 static void 566 nest_options(const uint8_t *data, uint_t olen, char *prefix, char *title) 567 { 568 char *str, *oldnest, *oldprefix; 569 570 if (olen <= 0) 571 return; 572 oldprefix = prot_prefix; 573 oldnest = prot_nest_prefix; 574 str = malloc(strlen(prot_nest_prefix) + strlen(prot_prefix) + 1); 575 if (str == NULL) { 576 prot_nest_prefix = prot_prefix; 577 } else { 578 (void) sprintf(str, "%s%s", prot_nest_prefix, prot_prefix); 579 prot_nest_prefix = str; 580 } 581 show_header(prefix, title, 0); 582 show_options(data, olen); 583 free(str); 584 prot_prefix = oldprefix; 585 prot_nest_prefix = oldnest; 586 } 587 588 static void 589 show_options(const uint8_t *data, int len) 590 { 591 dhcpv6_option_t d6o; 592 uint_t olen, retlen; 593 uint16_t val16; 594 uint16_t type; 595 uint32_t val32; 596 const uint8_t *ostart; 597 char *str, *sp; 598 char *oldnest; 599 600 /* 601 * Be very careful with negative numbers; ANSI signed/unsigned 602 * comparison doesn't work as expected. 603 */ 604 while (len >= (signed)sizeof (d6o)) { 605 (void) memcpy(&d6o, data, sizeof (d6o)); 606 d6o.d6o_code = ntohs(d6o.d6o_code); 607 d6o.d6o_len = olen = ntohs(d6o.d6o_len); 608 (void) snprintf(get_line(0, 0), get_line_remain(), 609 "Option Code = %u (%s)", d6o.d6o_code, 610 option_to_str(d6o.d6o_code)); 611 ostart = data += sizeof (d6o); 612 len -= sizeof (d6o); 613 if (olen > len) { 614 (void) strlcpy(get_line(0, 0), "Option truncated", 615 get_line_remain()); 616 olen = len; 617 } 618 switch (d6o.d6o_code) { 619 case DHCPV6_OPT_CLIENTID: 620 case DHCPV6_OPT_SERVERID: 621 if (olen < sizeof (val16)) 622 break; 623 (void) memcpy(&val16, data, sizeof (val16)); 624 data += sizeof (val16); 625 olen -= sizeof (val16); 626 type = ntohs(val16); 627 (void) snprintf(get_line(0, 0), get_line_remain(), 628 " DUID Type = %u (%s)", type, 629 duidtype_to_str(type)); 630 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 631 if (olen < sizeof (val16)) 632 break; 633 (void) memcpy(&val16, data, sizeof (val16)); 634 data += sizeof (val16); 635 olen -= sizeof (val16); 636 val16 = ntohs(val16); 637 (void) snprintf(get_line(0, 0), 638 get_line_remain(), 639 " Hardware Type = %u (%s)", val16, 640 arp_htype(type)); 641 } 642 if (type == DHCPV6_DUID_LLT) { 643 time_t timevalue; 644 645 if (olen < sizeof (val32)) 646 break; 647 (void) memcpy(&val32, data, sizeof (val32)); 648 data += sizeof (val32); 649 olen -= sizeof (val32); 650 timevalue = ntohl(val32) + DUID_TIME_BASE; 651 (void) snprintf(get_line(0, 0), 652 get_line_remain(), 653 " Time = %lu (%.24s)", ntohl(val32), 654 ctime(&timevalue)); 655 } 656 if (type == DHCPV6_DUID_EN) { 657 if (olen < sizeof (val32)) 658 break; 659 (void) memcpy(&val32, data, sizeof (val32)); 660 data += sizeof (val32); 661 olen -= sizeof (val32); 662 val32 = ntohl(val32); 663 (void) snprintf(get_line(0, 0), 664 get_line_remain(), 665 " Enterprise Number = %lu (%s)", val32, 666 entr_to_str(val32)); 667 } 668 if (olen == 0) 669 break; 670 if ((str = malloc(olen * 3)) == NULL) 671 pr_err("interpret_dhcpv6: no mem"); 672 sp = str + snprintf(str, 3, "%02x", *data++); 673 while (--olen > 0) { 674 *sp++ = (type == DHCPV6_DUID_LLT || 675 type == DHCPV6_DUID_LL) ? ':' : ' '; 676 sp = sp + snprintf(sp, 3, "%02x", *data++); 677 } 678 (void) snprintf(get_line(0, 0), get_line_remain(), 679 (type == DHCPV6_DUID_LLT || 680 type == DHCPV6_DUID_LL) ? 681 " Link Layer Address = %s" : 682 " Identifier = %s", str); 683 free(str); 684 break; 685 case DHCPV6_OPT_IA_NA: 686 case DHCPV6_OPT_IA_PD: { 687 dhcpv6_ia_na_t d6in; 688 689 if (olen < sizeof (d6in) - sizeof (d6o)) 690 break; 691 (void) memcpy(&d6in, data - sizeof (d6o), 692 sizeof (d6in)); 693 data += sizeof (d6in) - sizeof (d6o); 694 olen -= sizeof (d6in) - sizeof (d6o); 695 (void) snprintf(get_line(0, 0), get_line_remain(), 696 " IAID = %u", ntohl(d6in.d6in_iaid)); 697 (void) snprintf(get_line(0, 0), get_line_remain(), 698 " T1 (renew) = %u seconds", ntohl(d6in.d6in_t1)); 699 (void) snprintf(get_line(0, 0), get_line_remain(), 700 " T2 (rebind) = %u seconds", ntohl(d6in.d6in_t2)); 701 nest_options(data, olen, "IA: ", 702 "Identity Association"); 703 break; 704 } 705 case DHCPV6_OPT_IA_TA: { 706 dhcpv6_ia_ta_t d6it; 707 708 if (olen < sizeof (d6it) - sizeof (d6o)) 709 break; 710 (void) memcpy(&d6it, data - sizeof (d6o), 711 sizeof (d6it)); 712 data += sizeof (d6it) - sizeof (d6o); 713 olen -= sizeof (d6it) - sizeof (d6o); 714 (void) snprintf(get_line(0, 0), get_line_remain(), 715 " IAID = %u", ntohl(d6it.d6it_iaid)); 716 nest_options(data, olen, "IA: ", 717 "Identity Association"); 718 break; 719 } 720 case DHCPV6_OPT_IAADDR: { 721 dhcpv6_iaaddr_t d6ia; 722 723 if (olen < sizeof (d6ia) - sizeof (d6o)) 724 break; 725 (void) memcpy(&d6ia, data - sizeof (d6o), 726 sizeof (d6ia)); 727 data += sizeof (d6ia) - sizeof (d6o); 728 olen -= sizeof (d6ia) - sizeof (d6o); 729 show_address(" Address", &d6ia.d6ia_addr); 730 (void) snprintf(get_line(0, 0), get_line_remain(), 731 " Preferred lifetime = %u seconds", 732 ntohl(d6ia.d6ia_preflife)); 733 (void) snprintf(get_line(0, 0), get_line_remain(), 734 " Valid lifetime = %u seconds", 735 ntohl(d6ia.d6ia_vallife)); 736 nest_options(data, olen, "ADDR: ", "Address"); 737 break; 738 } 739 case DHCPV6_OPT_ORO: 740 while (olen >= sizeof (val16)) { 741 (void) memcpy(&val16, data, sizeof (val16)); 742 val16 = ntohs(val16); 743 (void) snprintf(get_line(0, 0), 744 get_line_remain(), 745 " Requested Option Code = %u (%s)", val16, 746 option_to_str(val16)); 747 data += sizeof (val16); 748 olen -= sizeof (val16); 749 } 750 break; 751 case DHCPV6_OPT_PREFERENCE: 752 if (olen > 0) { 753 (void) snprintf(get_line(0, 0), 754 get_line_remain(), 755 *data == 255 ? 756 " Preference = %u (immediate)" : 757 " Preference = %u", *data); 758 } 759 break; 760 case DHCPV6_OPT_ELAPSED_TIME: 761 if (olen == sizeof (val16)) { 762 (void) memcpy(&val16, data, sizeof (val16)); 763 val16 = ntohs(val16); 764 (void) snprintf(get_line(0, 0), 765 get_line_remain(), 766 " Elapsed Time = %u.%02u seconds", 767 val16 / 100, val16 % 100); 768 } 769 break; 770 case DHCPV6_OPT_RELAY_MSG: 771 if (olen > 0) { 772 oldnest = prot_nest_prefix; 773 prot_nest_prefix = prot_prefix; 774 retlen = interpret_dhcpv6(F_DTAIL, data, olen); 775 prot_prefix = prot_nest_prefix; 776 prot_nest_prefix = oldnest; 777 } 778 break; 779 case DHCPV6_OPT_AUTH: { 780 dhcpv6_auth_t d6a; 781 782 if (olen < DHCPV6_AUTH_SIZE - sizeof (d6o)) 783 break; 784 (void) memcpy(&d6a, data - sizeof (d6o), 785 DHCPV6_AUTH_SIZE); 786 data += DHCPV6_AUTH_SIZE - sizeof (d6o); 787 olen += DHCPV6_AUTH_SIZE - sizeof (d6o); 788 (void) snprintf(get_line(0, 0), get_line_remain(), 789 " Protocol = %u (%s)", d6a.d6a_proto, 790 authproto_to_str(d6a.d6a_proto)); 791 (void) snprintf(get_line(0, 0), get_line_remain(), 792 " Algorithm = %u (%s)", d6a.d6a_alg, 793 authalg_to_str(d6a.d6a_proto, d6a.d6a_alg)); 794 (void) snprintf(get_line(0, 0), get_line_remain(), 795 " Replay Detection Method = %u (%s)", d6a.d6a_rdm, 796 authrdm_to_str(d6a.d6a_rdm)); 797 show_hex(d6a.d6a_replay, sizeof (d6a.d6a_replay), 798 " RDM Data"); 799 if (olen > 0) 800 show_hex(data, olen, " Auth Info"); 801 break; 802 } 803 case DHCPV6_OPT_UNICAST: 804 if (olen >= sizeof (in6_addr_t)) 805 show_address(" Server Address", data); 806 break; 807 case DHCPV6_OPT_STATUS_CODE: 808 if (olen < sizeof (val16)) 809 break; 810 (void) memcpy(&val16, data, sizeof (val16)); 811 val16 = ntohs(val16); 812 (void) snprintf(get_line(0, 0), get_line_remain(), 813 " Status Code = %u (%s)", val16, 814 status_to_str(val16)); 815 data += sizeof (val16); 816 olen -= sizeof (val16); 817 if (olen > 0) 818 (void) snprintf(get_line(0, 0), 819 get_line_remain(), " Text = \"%.*s\"", 820 olen, data); 821 break; 822 case DHCPV6_OPT_VENDOR_CLASS: 823 if (olen < sizeof (val32)) 824 break; 825 (void) memcpy(&val32, data, sizeof (val32)); 826 data += sizeof (val32); 827 olen -= sizeof (val32); 828 val32 = ntohl(val32); 829 (void) snprintf(get_line(0, 0), get_line_remain(), 830 " Enterprise Number = %lu (%s)", val32, 831 entr_to_str(val32)); 832 /* FALLTHROUGH */ 833 case DHCPV6_OPT_USER_CLASS: 834 while (olen >= sizeof (val16)) { 835 (void) memcpy(&val16, data, sizeof (val16)); 836 data += sizeof (val16); 837 olen -= sizeof (val16); 838 val16 = ntohs(val16); 839 if (val16 > olen) { 840 (void) strlcpy(get_line(0, 0), 841 " Truncated class", 842 get_line_remain()); 843 val16 = olen; 844 } 845 show_hex(data, olen, " Class"); 846 data += val16; 847 olen -= val16; 848 } 849 break; 850 case DHCPV6_OPT_VENDOR_OPT: { 851 dhcpv6_option_t sd6o; 852 853 if (olen < sizeof (val32)) 854 break; 855 (void) memcpy(&val32, data, sizeof (val32)); 856 data += sizeof (val32); 857 olen -= sizeof (val32); 858 val32 = ntohl(val32); 859 (void) snprintf(get_line(0, 0), get_line_remain(), 860 " Enterprise Number = %lu (%s)", val32, 861 entr_to_str(val32)); 862 while (olen >= sizeof (sd6o)) { 863 (void) memcpy(&sd6o, data, sizeof (sd6o)); 864 sd6o.d6o_code = ntohs(sd6o.d6o_code); 865 sd6o.d6o_len = ntohs(sd6o.d6o_len); 866 (void) snprintf(get_line(0, 0), 867 get_line_remain(), 868 " Vendor Option Code = %u", d6o.d6o_code); 869 data += sizeof (d6o); 870 olen -= sizeof (d6o); 871 if (sd6o.d6o_len > olen) { 872 (void) strlcpy(get_line(0, 0), 873 " Vendor Option truncated", 874 get_line_remain()); 875 sd6o.d6o_len = olen; 876 } 877 if (sd6o.d6o_len > 0) { 878 show_hex(data, sd6o.d6o_len, 879 " Data"); 880 data += sd6o.d6o_len; 881 olen -= sd6o.d6o_len; 882 } 883 } 884 break; 885 } 886 case DHCPV6_OPT_REMOTE_ID: 887 if (olen < sizeof (val32)) 888 break; 889 (void) memcpy(&val32, data, sizeof (val32)); 890 data += sizeof (val32); 891 olen -= sizeof (val32); 892 val32 = ntohl(val32); 893 (void) snprintf(get_line(0, 0), get_line_remain(), 894 " Enterprise Number = %lu (%s)", val32, 895 entr_to_str(val32)); 896 /* FALLTHROUGH */ 897 case DHCPV6_OPT_INTERFACE_ID: 898 case DHCPV6_OPT_SUBSCRIBER: 899 if (olen > 0) 900 show_hex(data, olen, " ID"); 901 break; 902 case DHCPV6_OPT_RECONF_MSG: 903 if (olen > 0) { 904 (void) snprintf(get_line(0, 0), 905 get_line_remain(), 906 " Message Type = %u (%s)", *data, 907 reconf_to_str(*data)); 908 } 909 break; 910 case DHCPV6_OPT_SIP_NAMES: 911 case DHCPV6_OPT_DNS_SEARCH: 912 case DHCPV6_OPT_NIS_DOMAIN: 913 case DHCPV6_OPT_NISP_DOMAIN: 914 case DHCPV6_OPT_BCMCS_SRV_D: { 915 dhcp_symbol_t *symp; 916 char *sp2; 917 918 symp = inittab_getbycode( 919 ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP, 920 d6o.d6o_code); 921 if (symp != NULL) { 922 str = inittab_decode(symp, data, olen, B_TRUE); 923 if (str != NULL) { 924 sp = str; 925 do { 926 sp2 = strchr(sp, ' '); 927 if (sp2 != NULL) 928 *sp2++ = '\0'; 929 (void) snprintf(get_line(0, 0), 930 get_line_remain(), 931 " Name = %s", sp); 932 } while ((sp = sp2) != NULL); 933 free(str); 934 } 935 free(symp); 936 } 937 break; 938 } 939 case DHCPV6_OPT_SIP_ADDR: 940 case DHCPV6_OPT_DNS_ADDR: 941 case DHCPV6_OPT_NIS_SERVERS: 942 case DHCPV6_OPT_NISP_SERVERS: 943 case DHCPV6_OPT_SNTP_SERVERS: 944 case DHCPV6_OPT_BCMCS_SRV_A: 945 while (olen >= sizeof (in6_addr_t)) { 946 show_address(" Address", data); 947 data += sizeof (in6_addr_t); 948 olen -= sizeof (in6_addr_t); 949 } 950 break; 951 case DHCPV6_OPT_IAPREFIX: { 952 dhcpv6_iaprefix_t d6ip; 953 954 if (olen < DHCPV6_IAPREFIX_SIZE - sizeof (d6o)) 955 break; 956 (void) memcpy(&d6ip, data - sizeof (d6o), 957 DHCPV6_IAPREFIX_SIZE); 958 data += DHCPV6_IAPREFIX_SIZE - sizeof (d6o); 959 olen -= DHCPV6_IAPREFIX_SIZE - sizeof (d6o); 960 show_address(" Prefix", d6ip.d6ip_addr); 961 (void) snprintf(get_line(0, 0), get_line_remain(), 962 " Preferred lifetime = %u seconds", 963 ntohl(d6ip.d6ip_preflife)); 964 (void) snprintf(get_line(0, 0), get_line_remain(), 965 " Valid lifetime = %u seconds", 966 ntohl(d6ip.d6ip_vallife)); 967 (void) snprintf(get_line(0, 0), get_line_remain(), 968 " Prefix length = %u", d6ip.d6ip_preflen); 969 nest_options(data, olen, "ADDR: ", "Address"); 970 break; 971 } 972 case DHCPV6_OPT_INFO_REFTIME: 973 if (olen < sizeof (val32)) 974 break; 975 (void) memcpy(&val32, data, sizeof (val32)); 976 (void) snprintf(get_line(0, 0), get_line_remain(), 977 " Refresh Time = %lu seconds", ntohl(val32)); 978 break; 979 case DHCPV6_OPT_GEOCONF_CVC: { 980 dhcpv6_civic_t d6c; 981 int solen; 982 983 if (olen < DHCPV6_CIVIC_SIZE - sizeof (d6o)) 984 break; 985 (void) memcpy(&d6c, data - sizeof (d6o), 986 DHCPV6_CIVIC_SIZE); 987 data += DHCPV6_CIVIC_SIZE - sizeof (d6o); 988 olen -= DHCPV6_CIVIC_SIZE - sizeof (d6o); 989 (void) snprintf(get_line(0, 0), get_line_remain(), 990 " What Location = %u (%s)", d6c.d6c_what, 991 cwhat_to_str(d6c.d6c_what)); 992 (void) snprintf(get_line(0, 0), get_line_remain(), 993 " Country Code = %.*s", sizeof (d6c.d6c_cc), 994 d6c.d6c_cc); 995 while (olen >= 2) { 996 (void) snprintf(get_line(0, 0), 997 get_line_remain(), 998 " CA Element = %u (%s)", *data, 999 catype_to_str(*data)); 1000 solen = data[1]; 1001 data += 2; 1002 olen -= 2; 1003 if (solen > olen) { 1004 (void) strlcpy(get_line(0, 0), 1005 " CA Element truncated", 1006 get_line_remain()); 1007 solen = olen; 1008 } 1009 if (solen > 0) { 1010 show_ascii(data, solen, " CA Data"); 1011 data += solen; 1012 olen -= solen; 1013 } 1014 } 1015 break; 1016 } 1017 case DHCPV6_OPT_CLIENT_FQDN: { 1018 dhcp_symbol_t *symp; 1019 1020 if (olen == 0) 1021 break; 1022 (void) snprintf(get_line(0, 0), get_line_remain(), 1023 " Flags = %02x", *data); 1024 (void) snprintf(get_line(0, 0), get_line_remain(), 1025 " %s", getflag(*data, DHCPV6_FQDNF_S, 1026 "Perform AAAA RR updates", "No AAAA RR updates")); 1027 (void) snprintf(get_line(0, 0), get_line_remain(), 1028 " %s", getflag(*data, DHCPV6_FQDNF_O, 1029 "Server override updates", 1030 "No server override updates")); 1031 (void) snprintf(get_line(0, 0), get_line_remain(), 1032 " %s", getflag(*data, DHCPV6_FQDNF_N, 1033 "Server performs no updates", 1034 "Server performs updates")); 1035 symp = inittab_getbycode( 1036 ITAB_CAT_STANDARD | ITAB_CAT_V6, ITAB_CONS_SNOOP, 1037 d6o.d6o_code); 1038 if (symp != NULL) { 1039 str = inittab_decode(symp, data, olen, B_TRUE); 1040 if (str != NULL) { 1041 (void) snprintf(get_line(0, 0), 1042 get_line_remain(), 1043 " FQDN = %s", str); 1044 free(str); 1045 } 1046 free(symp); 1047 } 1048 break; 1049 } 1050 } 1051 data = ostart + d6o.d6o_len; 1052 len -= d6o.d6o_len; 1053 } 1054 if (len != 0) { 1055 (void) strlcpy(get_line(0, 0), "Option entry truncated", 1056 get_line_remain()); 1057 } 1058 } 1059