Home | History | Annotate | Download | only in tcpdump
      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 *
    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 *
    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
    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
    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