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