xref: /netbsd-src/external/bsd/tcpdump/dist/print-dhcp6.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*
2  * Copyright (C) 1998 and 1999 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 /*
30  * RFC3315: DHCPv6
31  * supported DHCPv6 options:
32  *  RFC3319: Session Initiation Protocol (SIP) Servers options,
33  *  RFC3633: IPv6 Prefix options,
34  *  RFC3646: DNS Configuration options,
35  *  RFC3898: Network Information Service (NIS) Configuration options,
36  *  RFC4075: Simple Network Time Protocol (SNTP) Configuration option,
37  *  RFC4242: Information Refresh Time option,
38  *  RFC4280: Broadcast and Multicast Control Servers options,
39  *  RFC5908: Network Time Protocol (NTP) Server Option for DHCPv6
40  *  RFC6334: Dual-Stack Lite option,
41  */
42 
43 #include <sys/cdefs.h>
44 #ifndef lint
45 #if 0
46 static const char rcsid[] _U_ =
47     "@(#) Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.37 2008-02-06 10:26:09 guy Exp ";
48 #else
49 __RCSID("$NetBSD: print-dhcp6.c,v 1.4 2013/12/31 17:33:31 christos Exp $");
50 #endif
51 #endif
52 
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56 
57 #include <tcpdump-stdinc.h>
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include "interface.h"
63 #include "addrtoname.h"
64 #include "extract.h"
65 
66 /* lease duration */
67 #define DHCP6_DURATITION_INFINITE 0xffffffff
68 
69 /* Error Values */
70 #define DH6ERR_FAILURE		16
71 #define DH6ERR_AUTHFAIL		17
72 #define DH6ERR_POORLYFORMED	18
73 #define DH6ERR_UNAVAIL		19
74 #define DH6ERR_OPTUNAVAIL	20
75 
76 /* Message type */
77 #define DH6_SOLICIT	1
78 #define DH6_ADVERTISE	2
79 #define DH6_REQUEST	3
80 #define DH6_CONFIRM	4
81 #define DH6_RENEW	5
82 #define DH6_REBIND	6
83 #define DH6_REPLY	7
84 #define DH6_RELEASE	8
85 #define DH6_DECLINE	9
86 #define DH6_RECONFIGURE	10
87 #define DH6_INFORM_REQ	11
88 #define DH6_RELAY_FORW	12
89 #define DH6_RELAY_REPLY	13
90 #define DH6_LEASEQUERY	14
91 #define DH6_LQ_REPLY	15
92 
93 /* DHCP6 base packet format */
94 struct dhcp6 {
95 	union {
96 		u_int8_t m;
97 		u_int32_t x;
98 	} dh6_msgtypexid;
99 	/* options follow */
100 };
101 #define dh6_msgtype	dh6_msgtypexid.m
102 #define dh6_xid		dh6_msgtypexid.x
103 #define DH6_XIDMASK	0x00ffffff
104 
105 /* DHCPv6 relay messages */
106 struct dhcp6_relay {
107 	u_int8_t dh6relay_msgtype;
108 	u_int8_t dh6relay_hcnt;
109 	u_int8_t dh6relay_linkaddr[16];	/* XXX: badly aligned */
110 	u_int8_t dh6relay_peeraddr[16];
111 	/* options follow */
112 };
113 
114 /* options */
115 #define DH6OPT_CLIENTID	1
116 #define DH6OPT_SERVERID	2
117 #define DH6OPT_IA_NA 3
118 #define DH6OPT_IA_TA 4
119 #define DH6OPT_IA_ADDR 5
120 #define DH6OPT_ORO 6
121 #define DH6OPT_PREFERENCE 7
122 #  define DH6OPT_PREF_MAX 255
123 #define DH6OPT_ELAPSED_TIME 8
124 #define DH6OPT_RELAY_MSG 9
125 /*#define DH6OPT_SERVER_MSG 10 deprecated */
126 #define DH6OPT_AUTH 11
127 #  define DH6OPT_AUTHPROTO_DELAYED 2
128 #  define DH6OPT_AUTHPROTO_RECONFIG 3
129 #  define DH6OPT_AUTHALG_HMACMD5 1
130 #  define DH6OPT_AUTHRDM_MONOCOUNTER 0
131 #  define DH6OPT_AUTHRECONFIG_KEY 1
132 #  define DH6OPT_AUTHRECONFIG_HMACMD5 2
133 #define DH6OPT_UNICAST 12
134 #define DH6OPT_STATUS_CODE 13
135 #  define DH6OPT_STCODE_SUCCESS 0
136 #  define DH6OPT_STCODE_UNSPECFAIL 1
137 #  define DH6OPT_STCODE_NOADDRAVAIL 2
138 #  define DH6OPT_STCODE_NOBINDING 3
139 #  define DH6OPT_STCODE_NOTONLINK 4
140 #  define DH6OPT_STCODE_USEMULTICAST 5
141 #  define DH6OPT_STCODE_NOPREFIXAVAIL 6
142 #  define DH6OPT_STCODE_UNKNOWNQUERYTYPE 7
143 #  define DH6OPT_STCODE_MALFORMEDQUERY 8
144 #  define DH6OPT_STCODE_NOTCONFIGURED 9
145 #  define DH6OPT_STCODE_NOTALLOWED 10
146 #define DH6OPT_RAPID_COMMIT 14
147 #define DH6OPT_USER_CLASS 15
148 #define DH6OPT_VENDOR_CLASS 16
149 #define DH6OPT_VENDOR_OPTS 17
150 #define DH6OPT_INTERFACE_ID 18
151 #define DH6OPT_RECONF_MSG 19
152 #define DH6OPT_RECONF_ACCEPT 20
153 #define DH6OPT_SIP_SERVER_D 21
154 #define DH6OPT_SIP_SERVER_A 22
155 #define DH6OPT_DNS_SERVERS 23
156 #define DH6OPT_DOMAIN_LIST 24
157 #define DH6OPT_IA_PD 25
158 #define DH6OPT_IA_PD_PREFIX 26
159 #define DH6OPT_NIS_SERVERS 27
160 #define DH6OPT_NISP_SERVERS 28
161 #define DH6OPT_NIS_NAME 29
162 #define DH6OPT_NISP_NAME 30
163 #define DH6OPT_SNTP_SERVERS 31
164 #define DH6OPT_LIFETIME 32
165 #define DH6OPT_BCMCS_SERVER_D 33
166 #define DH6OPT_BCMCS_SERVER_A 34
167 #define DH6OPT_GEOCONF_CIVIC 36
168 #define DH6OPT_REMOTE_ID 37
169 #define DH6OPT_SUBSCRIBER_ID 38
170 #define DH6OPT_CLIENT_FQDN 39
171 #define DH6OPT_PANA_AGENT 40
172 #define DH6OPT_NEW_POSIX_TIMEZONE 41
173 #define DH6OPT_NEW_TZDB_TIMEZONE 42
174 #define DH6OPT_ERO 43
175 #define DH6OPT_LQ_QUERY 44
176 #define DH6OPT_CLIENT_DATA 45
177 #define DH6OPT_CLT_TIME 46
178 #define DH6OPT_LQ_RELAY_DATA 47
179 #define DH6OPT_LQ_CLIENT_LINK 48
180 #define DH6OPT_NTP_SERVER 56
181 #  define DH6OPT_NTP_SUBOPTION_SRV_ADDR 1
182 #  define DH6OPT_NTP_SUBOPTION_MC_ADDR 2
183 #  define DH6OPT_NTP_SUBOPTION_SRV_FQDN 3
184 #define DH6OPT_AFTR_NAME 64
185 
186 struct dhcp6opt {
187 	u_int16_t dh6opt_type;
188 	u_int16_t dh6opt_len;
189 	/* type-dependent data follows */
190 };
191 
192 static const char *
193 dhcp6opt_name(int type)
194 {
195 	static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
196 
197 	if (type > 65535)
198 		return "INVALID-option";
199 
200 	switch(type) {
201 	case DH6OPT_CLIENTID:
202 		return "client-ID";
203 	case DH6OPT_SERVERID:
204 		return "server-ID";
205 	case DH6OPT_IA_NA:
206 		return "IA_NA";
207 	case DH6OPT_IA_TA:
208 		return "IA_TA";
209 	case DH6OPT_IA_ADDR:
210 		return "IA_ADDR";
211 	case DH6OPT_ORO:
212 		return "option-request";
213 	case DH6OPT_PREFERENCE:
214 		return "preference";
215 	case DH6OPT_ELAPSED_TIME:
216 		return "elapsed-time";
217 	case DH6OPT_RELAY_MSG:
218 		return "relay-message";
219 	case DH6OPT_AUTH:
220 		return "authentication";
221 	case DH6OPT_UNICAST:
222 		return "server-unicast";
223 	case DH6OPT_STATUS_CODE:
224 		return "status-code";
225 	case DH6OPT_RAPID_COMMIT:
226 		return "rapid-commit";
227 	case DH6OPT_USER_CLASS:
228 		return "user-class";
229 	case DH6OPT_VENDOR_CLASS:
230 		return "vendor-class";
231 	case DH6OPT_VENDOR_OPTS:
232 		return "vendor-specific-info";
233 	case DH6OPT_INTERFACE_ID:
234 		return "interface-ID";
235 	case DH6OPT_RECONF_MSG:
236 		return "reconfigure-message";
237 	case DH6OPT_RECONF_ACCEPT:
238 		return "reconfigure-accept";
239 	case DH6OPT_SIP_SERVER_D:
240 		return "SIP-servers-domain";
241 	case DH6OPT_SIP_SERVER_A:
242 		return "SIP-servers-address";
243 	case DH6OPT_DNS_SERVERS:
244 		return "DNS-server";
245 	case DH6OPT_DOMAIN_LIST:
246 		return "DNS-search-list";
247 	case DH6OPT_IA_PD:
248 		return "IA_PD";
249 	case DH6OPT_IA_PD_PREFIX:
250 		return "IA_PD-prefix";
251 	case DH6OPT_SNTP_SERVERS:
252 		return "SNTP-servers";
253 	case DH6OPT_LIFETIME:
254 		return "lifetime";
255 	case DH6OPT_NIS_SERVERS:
256 		return "NIS-server";
257 	case DH6OPT_NISP_SERVERS:
258 		return "NIS+-server";
259 	case DH6OPT_NIS_NAME:
260 		return "NIS-domain-name";
261 	case DH6OPT_NISP_NAME:
262 		return "NIS+-domain-name";
263 	case DH6OPT_BCMCS_SERVER_D:
264 		return "BCMCS-domain-name";
265 	case DH6OPT_BCMCS_SERVER_A:
266 		return "BCMCS-server";
267 	case DH6OPT_GEOCONF_CIVIC:
268 		return "Geoconf-Civic";
269 	case DH6OPT_REMOTE_ID:
270 		return "Remote-ID";
271 	case DH6OPT_SUBSCRIBER_ID:
272 		return "Subscriber-ID";
273 	case DH6OPT_CLIENT_FQDN:
274 		return "Client-FQDN";
275 	case DH6OPT_PANA_AGENT:
276 		return "PANA-agent";
277 	case DH6OPT_NEW_POSIX_TIMEZONE:
278 		return "POSIX-timezone";
279 	case DH6OPT_NEW_TZDB_TIMEZONE:
280 		return "POSIX-tz-database";
281 	case DH6OPT_ERO:
282 		return "Echo-request-option";
283 	case DH6OPT_LQ_QUERY:
284 		return "Lease-query";
285 	case DH6OPT_CLIENT_DATA:
286 		return "LQ-client-data";
287 	case DH6OPT_CLT_TIME:
288 		return "Clt-time";
289 	case DH6OPT_LQ_RELAY_DATA:
290 		return "LQ-relay-data";
291 	case DH6OPT_LQ_CLIENT_LINK:
292 		return "LQ-client-link";
293 	case DH6OPT_NTP_SERVER:
294 		return "NTP-server";
295 	case DH6OPT_AFTR_NAME:
296 		return "AFTR-Name";
297 	default:
298 		snprintf(genstr, sizeof(genstr), "opt_%d", type);
299 		return(genstr);
300 	}
301 }
302 
303 static const char *
304 dhcp6stcode(int code)
305 {
306 	static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
307 
308 	if (code > 255)
309 		return "INVALID code";
310 
311 	switch(code) {
312 	case DH6OPT_STCODE_SUCCESS:
313 		return "success";
314 	case DH6OPT_STCODE_UNSPECFAIL:
315 		return "unspec failure";
316 	case DH6OPT_STCODE_NOADDRAVAIL:
317 		return "no addresses";
318 	case DH6OPT_STCODE_NOBINDING:
319 		return "no binding";
320 	case DH6OPT_STCODE_NOTONLINK:
321 		return "not on-link";
322 	case DH6OPT_STCODE_USEMULTICAST:
323 		return "use multicast";
324 	case DH6OPT_STCODE_NOPREFIXAVAIL:
325 		return "no prefixes";
326 	case DH6OPT_STCODE_UNKNOWNQUERYTYPE:
327 		return "unknown query type";
328 	case DH6OPT_STCODE_MALFORMEDQUERY:
329 		return "malformed query";
330 	case DH6OPT_STCODE_NOTCONFIGURED:
331 		return "not configured";
332 	case DH6OPT_STCODE_NOTALLOWED:
333 		return "not allowed";
334 	default:
335 		snprintf(genstr, sizeof(genstr), "code%d", code);
336 		return(genstr);
337 	}
338 }
339 
340 static void
341 dhcp6opt_print(const u_char *cp, const u_char *ep)
342 {
343 	const struct dhcp6opt *dh6o;
344 	const u_char *tp;
345 	size_t i;
346 	u_int16_t opttype;
347 	size_t optlen;
348 	u_int8_t auth_proto;
349 	u_int authinfolen, authrealmlen;
350 	int remain_len;  /* Length of remaining options */
351 	int label_len;   /* Label length */
352 	u_int16_t subopt_code;
353 	u_int16_t subopt_len;
354 
355 	if (cp == ep)
356 		return;
357 	while (cp < ep) {
358 		if (ep < cp + sizeof(*dh6o))
359 			goto trunc;
360 		dh6o = (struct dhcp6opt *)cp;
361 		TCHECK(*dh6o);
362 		optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
363 		if (ep < cp + sizeof(*dh6o) + optlen)
364 			goto trunc;
365 		opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
366 		printf(" (%s", dhcp6opt_name(opttype));
367 		switch (opttype) {
368 		case DH6OPT_CLIENTID:
369 		case DH6OPT_SERVERID:
370 			if (optlen < 2) {
371 				/*(*/
372 				printf(" ?)");
373 				break;
374 			}
375 			tp = (u_char *)(dh6o + 1);
376 			switch (EXTRACT_16BITS(tp)) {
377 			case 1:
378 				if (optlen >= 2 + 6) {
379 					printf(" hwaddr/time type %u time %u ",
380 					    EXTRACT_16BITS(&tp[2]),
381 					    EXTRACT_32BITS(&tp[4]));
382 					for (i = 8; i < optlen; i++)
383 						printf("%02x", tp[i]);
384 					/*(*/
385 					printf(")");
386 				} else {
387 					/*(*/
388 					printf(" ?)");
389 				}
390 				break;
391 			case 2:
392 				if (optlen >= 2 + 8) {
393 					printf(" vid ");
394 					for (i = 2; i < 2 + 8; i++)
395 						printf("%02x", tp[i]);
396 					/*(*/
397 					printf(")");
398 				} else {
399 					/*(*/
400 					printf(" ?)");
401 				}
402 				break;
403 			case 3:
404 				if (optlen >= 2 + 2) {
405 					printf(" hwaddr type %u ",
406 					    EXTRACT_16BITS(&tp[2]));
407 					for (i = 4; i < optlen; i++)
408 						printf("%02x", tp[i]);
409 					/*(*/
410 					printf(")");
411 				} else {
412 					/*(*/
413 					printf(" ?)");
414 				}
415 				break;
416 			default:
417 				printf(" type %d)", EXTRACT_16BITS(tp));
418 				break;
419 			}
420 			break;
421 		case DH6OPT_IA_ADDR:
422 			if (optlen < 24) {
423 				/*(*/
424 				printf(" ?)");
425 				break;
426 			}
427 			tp = (u_char *)(dh6o + 1);
428 			printf(" %s", ip6addr_string(&tp[0]));
429 			printf(" pltime:%u vltime:%u",
430 			    EXTRACT_32BITS(&tp[16]),
431 			    EXTRACT_32BITS(&tp[20]));
432 			if (optlen > 24) {
433 				/* there are sub-options */
434 				dhcp6opt_print(tp + 24, tp + optlen);
435 			}
436 			printf(")");
437 			break;
438 		case DH6OPT_ORO:
439 		case DH6OPT_ERO:
440 			if (optlen % 2) {
441 				printf(" ?)");
442 				break;
443 			}
444 			tp = (u_char *)(dh6o + 1);
445 			for (i = 0; i < optlen; i += 2) {
446 				printf(" %s",
447 				    dhcp6opt_name(EXTRACT_16BITS(&tp[i])));
448 			}
449 			printf(")");
450 			break;
451 		case DH6OPT_PREFERENCE:
452 			if (optlen != 1) {
453 				printf(" ?)");
454 				break;
455 			}
456 			tp = (u_char *)(dh6o + 1);
457 			printf(" %d)", *tp);
458 			break;
459 		case DH6OPT_ELAPSED_TIME:
460 			if (optlen != 2) {
461 				printf(" ?)");
462 				break;
463 			}
464 			tp = (u_char *)(dh6o + 1);
465 			printf(" %d)", EXTRACT_16BITS(tp));
466 			break;
467 		case DH6OPT_RELAY_MSG:
468 			printf(" (");
469 			tp = (u_char *)(dh6o + 1);
470 			dhcp6_print(tp, optlen);
471 			printf(")");
472 			break;
473 		case DH6OPT_AUTH:
474 			if (optlen < 11) {
475 				printf(" ?)");
476 				break;
477 			}
478 			tp = (u_char *)(dh6o + 1);
479 			auth_proto = *tp;
480 			switch (auth_proto) {
481 			case DH6OPT_AUTHPROTO_DELAYED:
482 				printf(" proto: delayed");
483 				break;
484 			case DH6OPT_AUTHPROTO_RECONFIG:
485 				printf(" proto: reconfigure");
486 				break;
487 			default:
488 				printf(" proto: %d", auth_proto);
489 				break;
490 			}
491 			tp++;
492 			switch (*tp) {
493 			case DH6OPT_AUTHALG_HMACMD5:
494 				/* XXX: may depend on the protocol */
495 				printf(", alg: HMAC-MD5");
496 				break;
497 			default:
498 				printf(", alg: %d", *tp);
499 				break;
500 			}
501 			tp++;
502 			switch (*tp) {
503 			case DH6OPT_AUTHRDM_MONOCOUNTER:
504 				printf(", RDM: mono");
505 				break;
506 			default:
507 				printf(", RDM: %d", *tp);
508 				break;
509 			}
510 			tp++;
511 			printf(", RD:");
512 			for (i = 0; i < 4; i++, tp += 2)
513 				printf(" %04x", EXTRACT_16BITS(tp));
514 
515 			/* protocol dependent part */
516 			authinfolen = optlen - 11;
517 			switch (auth_proto) {
518 			case DH6OPT_AUTHPROTO_DELAYED:
519 				if (authinfolen == 0)
520 					break;
521 				if (authinfolen < 20) {
522 					printf(" ??");
523 					break;
524 				}
525 				authrealmlen = authinfolen - 20;
526 				if (authrealmlen > 0) {
527 					printf(", realm: ");
528 				}
529 				for (i = 0; i < authrealmlen; i++, tp++)
530 					printf("%02x", *tp);
531 				printf(", key ID: %08x", EXTRACT_32BITS(tp));
532 				tp += 4;
533 				printf(", HMAC-MD5:");
534 				for (i = 0; i < 4; i++, tp+= 4)
535 					printf(" %08x", EXTRACT_32BITS(tp));
536 				break;
537 			case DH6OPT_AUTHPROTO_RECONFIG:
538 				if (authinfolen != 17) {
539 					printf(" ??");
540 					break;
541 				}
542 				switch (*tp++) {
543 				case DH6OPT_AUTHRECONFIG_KEY:
544 					printf(" reconfig-key");
545 					break;
546 				case DH6OPT_AUTHRECONFIG_HMACMD5:
547 					printf(" type: HMAC-MD5");
548 					break;
549 				default:
550 					printf(" type: ??");
551 					break;
552 				}
553 				printf(" value:");
554 				for (i = 0; i < 4; i++, tp+= 4)
555 					printf(" %08x", EXTRACT_32BITS(tp));
556 				break;
557 			default:
558 				printf(" ??");
559 				break;
560 			}
561 
562 			printf(")");
563 			break;
564 		case DH6OPT_RAPID_COMMIT: /* nothing todo */
565 			printf(")");
566 			break;
567 		case DH6OPT_INTERFACE_ID:
568 		case DH6OPT_SUBSCRIBER_ID:
569 			/*
570 			 * Since we cannot predict the encoding, print hex dump
571 			 * at most 10 characters.
572 			 */
573 			tp = (u_char *)(dh6o + 1);
574 			printf(" ");
575 			for (i = 0; i < optlen && i < 10; i++)
576 				printf("%02x", tp[i]);
577 			printf("...)");
578 			break;
579 		case DH6OPT_RECONF_MSG:
580 			tp = (u_char *)(dh6o + 1);
581 			switch (*tp) {
582 			case DH6_RENEW:
583 				printf(" for renew)");
584 				break;
585 			case DH6_INFORM_REQ:
586 				printf(" for inf-req)");
587 				break;
588 			default:
589 				printf(" for ?\?\?(%02x))", *tp);
590 				break;
591 			}
592 			break;
593 		case DH6OPT_RECONF_ACCEPT: /* nothing todo */
594 			printf(")");
595 			break;
596 		case DH6OPT_SIP_SERVER_A:
597 		case DH6OPT_DNS_SERVERS:
598 		case DH6OPT_SNTP_SERVERS:
599 		case DH6OPT_NIS_SERVERS:
600 		case DH6OPT_NISP_SERVERS:
601 		case DH6OPT_BCMCS_SERVER_A:
602 		case DH6OPT_PANA_AGENT:
603 		case DH6OPT_LQ_CLIENT_LINK:
604 			if (optlen % 16) {
605 				printf(" ?)");
606 				break;
607 			}
608 			tp = (u_char *)(dh6o + 1);
609 			for (i = 0; i < optlen; i += 16)
610 				printf(" %s", ip6addr_string(&tp[i]));
611 			printf(")");
612 			break;
613 		case DH6OPT_SIP_SERVER_D:
614 		case DH6OPT_DOMAIN_LIST:
615 			tp = (u_char *)(dh6o + 1);
616 			while (tp < cp + sizeof(*dh6o) + optlen) {
617 				putchar(' ');
618 				if ((tp = ns_nprint(tp, cp + sizeof(*dh6o) + optlen)) == NULL)
619 					goto trunc;
620 			}
621 			printf(")");
622 			break;
623 		case DH6OPT_STATUS_CODE:
624 			if (optlen < 2) {
625 				printf(" ?)");
626 				break;
627 			}
628 			tp = (u_char *)(dh6o + 1);
629 			printf(" %s)", dhcp6stcode(EXTRACT_16BITS(&tp[0])));
630 			break;
631 		case DH6OPT_IA_NA:
632 		case DH6OPT_IA_PD:
633 			if (optlen < 12) {
634 				printf(" ?)");
635 				break;
636 			}
637 			tp = (u_char *)(dh6o + 1);
638 			printf(" IAID:%u T1:%u T2:%u",
639 			    EXTRACT_32BITS(&tp[0]),
640 			    EXTRACT_32BITS(&tp[4]),
641 			    EXTRACT_32BITS(&tp[8]));
642 			if (optlen > 12) {
643 				/* there are sub-options */
644 				dhcp6opt_print(tp + 12, tp + optlen);
645 			}
646 			printf(")");
647 			break;
648 		case DH6OPT_IA_TA:
649 			if (optlen < 4) {
650 				printf(" ?)");
651 				break;
652 			}
653 			tp = (u_char *)(dh6o + 1);
654 			printf(" IAID:%u", EXTRACT_32BITS(tp));
655 			if (optlen > 4) {
656 				/* there are sub-options */
657 				dhcp6opt_print(tp + 4, tp + optlen);
658 			}
659 			printf(")");
660 			break;
661 		case DH6OPT_IA_PD_PREFIX:
662 			if (optlen < 25) {
663 				printf(" ?)");
664 				break;
665 			}
666 			tp = (u_char *)(dh6o + 1);
667 			printf(" %s/%d", ip6addr_string(&tp[9]), tp[8]);
668 			printf(" pltime:%u vltime:%u",
669 			    EXTRACT_32BITS(&tp[0]),
670 			    EXTRACT_32BITS(&tp[4]));
671 			if (optlen > 25) {
672 				/* there are sub-options */
673 				dhcp6opt_print(tp + 25, tp + optlen);
674 			}
675 			printf(")");
676 			break;
677 		case DH6OPT_LIFETIME:
678 		case DH6OPT_CLT_TIME:
679 			if (optlen != 4) {
680 				printf(" ?)");
681 				break;
682 			}
683 			tp = (u_char *)(dh6o + 1);
684 			printf(" %d)", EXTRACT_32BITS(tp));
685 			break;
686 		case DH6OPT_REMOTE_ID:
687 			if (optlen < 4) {
688 				printf(" ?)");
689 				break;
690 			}
691 			tp = (u_char *)(dh6o + 1);
692 			printf(" %d ", EXTRACT_32BITS(tp));
693 			/*
694 			 * Print hex dump first 10 characters.
695 			 */
696 			for (i = 4; i < optlen && i < 14; i++)
697 				printf("%02x", tp[i]);
698 			printf("...)");
699 			break;
700 		case DH6OPT_LQ_QUERY:
701 			if (optlen < 17) {
702 				printf(" ?)");
703 				break;
704 			}
705 			tp = (u_char *)(dh6o + 1);
706 			switch (*tp) {
707 			case 1:
708 				printf(" by-address");
709 				break;
710 			case 2:
711 				printf(" by-clientID");
712 				break;
713 			default:
714 				printf(" type_%d", (int)*tp);
715 				break;
716 			}
717 			printf(" %s", ip6addr_string(&tp[1]));
718 			if (optlen > 17) {
719 				/* there are query-options */
720 				dhcp6opt_print(tp + 17, tp + optlen);
721 			}
722 			printf(")");
723 			break;
724 		case DH6OPT_CLIENT_DATA:
725 			tp = (u_char *)(dh6o + 1);
726 			if (optlen > 0) {
727 				/* there are encapsulated options */
728 				dhcp6opt_print(tp, tp + optlen);
729 			}
730 			printf(")");
731 			break;
732 		case DH6OPT_LQ_RELAY_DATA:
733 			if (optlen < 16) {
734 				printf(" ?)");
735 				break;
736 			}
737 			tp = (u_char *)(dh6o + 1);
738 			printf(" %s ", ip6addr_string(&tp[0]));
739 			/*
740 			 * Print hex dump first 10 characters.
741 			 */
742 			for (i = 16; i < optlen && i < 26; i++)
743 				printf("%02x", tp[i]);
744 			printf("...)");
745 			break;
746 		case DH6OPT_NTP_SERVER:
747 			if (optlen < 4) {
748 				printf(" ?)");
749 				break;
750 			}
751 			tp = (u_char *)(dh6o + 1);
752 			while (tp < cp + sizeof(*dh6o) + optlen - 4) {
753 				subopt_code = EXTRACT_16BITS(tp);
754 				tp += 2;
755 				subopt_len = EXTRACT_16BITS(tp);
756 				tp += 2;
757 				if (tp + subopt_len > cp + sizeof(*dh6o) + optlen)
758 					goto trunc;
759 				printf(" subopt:%d", subopt_code);
760 				switch (subopt_code) {
761 				case DH6OPT_NTP_SUBOPTION_SRV_ADDR:
762 				case DH6OPT_NTP_SUBOPTION_MC_ADDR:
763 					if (subopt_len != 16) {
764 						printf(" ?");
765 						break;
766 					}
767 					printf(" %s", ip6addr_string(&tp[0]));
768 					break;
769 				case DH6OPT_NTP_SUBOPTION_SRV_FQDN:
770 					putchar(' ');
771 					if (ns_nprint(tp, tp + subopt_len) == NULL)
772 						goto trunc;
773 					break;
774 				default:
775 					printf(" ?");
776 					break;
777 				}
778 				tp += subopt_len;
779 			}
780 			printf(")");
781 			break;
782 		case DH6OPT_AFTR_NAME:
783 			if (optlen < 3) {
784 				printf(" ?)");
785 				break;
786 			}
787 			tp = (u_char *)(dh6o + 1);
788 			remain_len = optlen;
789 			printf(" ");
790 			/* Encoding is described in section 3.1 of RFC 1035 */
791 			while (remain_len && *tp) {
792 				label_len =  *tp++;
793 				if (label_len < remain_len - 1) {
794 					printf("%.*s", label_len, tp);
795 					tp += label_len;
796 					remain_len -= (label_len + 1);
797 					if(*tp) printf(".");
798 				} else {
799 					printf(" ?");
800 					break;
801 				}
802 			}
803 			printf(")");
804 			break;
805 		default:
806 			printf(")");
807 			break;
808 		}
809 
810 		cp += sizeof(*dh6o) + optlen;
811 	}
812 	return;
813 
814 trunc:
815 	printf("[|dhcp6ext]");
816 }
817 
818 /*
819  * Print dhcp6 packets
820  */
821 void
822 dhcp6_print(const u_char *cp, u_int length)
823 {
824 	struct dhcp6 *dh6;
825 	struct dhcp6_relay *dh6relay;
826 	const u_char *ep;
827 	u_char *extp;
828 	const char *name;
829 
830 	printf("dhcp6");
831 
832 	ep = (u_char *)snapend;
833 	if (cp + length < ep)
834 		ep = cp + length;
835 
836 	dh6 = (struct dhcp6 *)cp;
837 	dh6relay = (struct dhcp6_relay *)cp;
838 	TCHECK(dh6->dh6_xid);
839 	switch (dh6->dh6_msgtype) {
840 	case DH6_SOLICIT:
841 		name = "solicit";
842 		break;
843 	case DH6_ADVERTISE:
844 		name = "advertise";
845 		break;
846 	case DH6_REQUEST:
847 		name = "request";
848 		break;
849 	case DH6_CONFIRM:
850 		name = "confirm";
851 		break;
852 	case DH6_RENEW:
853 		name = "renew";
854 		break;
855 	case DH6_REBIND:
856 		name = "rebind";
857 		break;
858 	case DH6_REPLY:
859 		name = "reply";
860 		break;
861 	case DH6_RELEASE:
862 		name = "release";
863 		break;
864 	case DH6_DECLINE:
865 		name = "decline";
866 		break;
867 	case DH6_RECONFIGURE:
868 		name = "reconfigure";
869 		break;
870 	case DH6_INFORM_REQ:
871 		name= "inf-req";
872 		break;
873 	case DH6_RELAY_FORW:
874 		name= "relay-fwd";
875 		break;
876 	case DH6_RELAY_REPLY:
877 		name= "relay-reply";
878 		break;
879 	case DH6_LEASEQUERY:
880 		name= "leasequery";
881 		break;
882 	case DH6_LQ_REPLY:
883 		name= "leasequery-reply";
884 		break;
885 	default:
886 		name = NULL;
887 		break;
888 	}
889 
890 	if (!vflag) {
891 		if (name)
892 			printf(" %s", name);
893 		else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
894 		    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
895 			printf(" msgtype-%u", dh6->dh6_msgtype);
896 		}
897 		return;
898 	}
899 
900 	/* XXX relay agent messages have to be handled differently */
901 
902 	if (name)
903 		printf(" %s (", name);	/*)*/
904 	else
905 		printf(" msgtype-%u (", dh6->dh6_msgtype);	/*)*/
906 	if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
907 	    dh6->dh6_msgtype != DH6_RELAY_REPLY) {
908 		printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
909 		extp = (u_char *)(dh6 + 1);
910 		dhcp6opt_print(extp, ep);
911 	} else {		/* relay messages */
912 		struct in6_addr addr6;
913 
914 		TCHECK(dh6relay->dh6relay_peeraddr);
915 
916 		memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
917 		printf("linkaddr=%s", ip6addr_string(&addr6));
918 
919 		memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
920 		printf(" peeraddr=%s", ip6addr_string(&addr6));
921 
922 		dhcp6opt_print((u_char *)(dh6relay + 1), ep);
923 	}
924 	/*(*/
925 	printf(")");
926 	return;
927 
928 trunc:
929 	printf("[|dhcp6]");
930 }
931