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