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