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
interpret_dhcpv6(int flags,const uint8_t * data,int len)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 *
mtype_to_str(uint8_t mtype)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 *
option_to_str(uint8_t mtype)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 *
duidtype_to_str(uint16_t dtype)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 *
status_to_str(uint16_t status)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 *
entr_to_str(uint32_t entr)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 *
reconf_to_str(uint8_t msgtype)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 *
authproto_to_str(uint8_t aproto)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 *
authalg_to_str(uint8_t aproto,uint8_t aalg)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 *
authrdm_to_str(uint8_t ardm)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 *
cwhat_to_str(uint8_t what)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 *
catype_to_str(uint8_t catype)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
show_hex(const uint8_t * data,int len,const char * name)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
show_ascii(const uint8_t * data,int len,const char * name)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
show_address(const char * addrname,const void * aptr)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
nest_options(const uint8_t * data,uint_t olen,char * prefix,char * title)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
show_options(const uint8_t * data,int len)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 }
1051