]> The Tcpdump Group git mirrors - tcpdump/blob - print-dhcp6.c
use official assigned numbers for DHCPv6 prefix delegation options. suz@kame
[tcpdump] / print-dhcp6.c
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,
33 * RFC3633,
34 * RFC3646,
35 * draft-ietf-dhc-dhcpv6-opt-timeconfig-03.txt,
36 */
37
38 #ifndef lint
39 static const char rcsid[] _U_ =
40 "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.32 2004-01-21 03:53:08 itojun Exp $";
41 #endif
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include <tcpdump-stdinc.h>
48
49 #include <stdio.h>
50 #include <string.h>
51
52 #include "interface.h"
53 #include "addrtoname.h"
54 #include "extract.h"
55
56 /* lease duration */
57 #define DHCP6_DURATITION_INFINITE 0xffffffff
58
59 /* Error Values */
60 #define DH6ERR_FAILURE 16
61 #define DH6ERR_AUTHFAIL 17
62 #define DH6ERR_POORLYFORMED 18
63 #define DH6ERR_UNAVAIL 19
64 #define DH6ERR_OPTUNAVAIL 20
65
66 /* Message type */
67 #define DH6_SOLICIT 1
68 #define DH6_ADVERTISE 2
69 #define DH6_REQUEST 3
70 #define DH6_CONFIRM 4
71 #define DH6_RENEW 5
72 #define DH6_REBIND 6
73 #define DH6_REPLY 7
74 #define DH6_RELEASE 8
75 #define DH6_DECLINE 9
76 #define DH6_RECONFIGURE 10
77 #define DH6_INFORM_REQ 11
78 #define DH6_RELAY_FORW 12
79 #define DH6_RELAY_REPLY 13
80
81 /* DHCP6 base packet format */
82 struct dhcp6 {
83 union {
84 u_int8_t m;
85 u_int32_t x;
86 } dh6_msgtypexid;
87 /* options follow */
88 };
89 #define dh6_msgtype dh6_msgtypexid.m
90 #define dh6_xid dh6_msgtypexid.x
91 #define DH6_XIDMASK 0x00ffffff
92
93 /* DHCPv6 relay messages */
94 struct dhcp6_relay {
95 u_int8_t dh6relay_msgtype;
96 u_int8_t dh6relay_hcnt;
97 u_int8_t dh6relay_linkaddr[16]; /* XXX: badly aligned */
98 u_int8_t dh6relay_peeraddr[16];
99 /* options follow */
100 };
101
102 /* options */
103 #define DH6OPT_CLIENTID 1
104 #define DH6OPT_SERVERID 2
105 #define DH6OPT_IA_NA 3
106 #define DH6OPT_IA_TMP 4
107 #define DH6OPT_IADDR 5
108 #define DH6OPT_ORO 6
109 #define DH6OPT_PREFERENCE 7
110 # define DH6OPT_PREF_UNDEF -1
111 # define DH6OPT_PREF_MAX 255
112 #define DH6OPT_ELAPSED_TIME 8
113 #define DH6OPT_RELAY_MSG 9
114 /*#define DH6OPT_SERVER_MSG 10 deprecated */
115 #define DH6OPT_AUTH 11
116 #define DH6OPT_UNICAST 12
117 #define DH6OPT_STATUS_CODE 13
118 # define DH6OPT_STCODE_SUCCESS 0
119 # define DH6OPT_STCODE_UNSPECFAIL 1
120 # define DH6OPT_STCODE_NOADDRAVAIL 2
121 # define DH6OPT_STCODE_NOBINDING 3
122 # define DH6OPT_STCODE_NOTONLINK 4
123 # define DH6OPT_STCODE_USEMULTICAST 5
124 # define DH6OPT_STCODE_NOPREFIXAVAIL 6
125 #define DH6OPT_RAPID_COMMIT 14
126 #define DH6OPT_USER_CLASS 15
127 #define DH6OPT_VENDOR_CLASS 16
128 #define DH6OPT_VENDOR_OPTS 17
129 #define DH6OPT_INTERFACE_ID 18
130 #define DH6OPT_RECONF_MSG 19
131 #define DH6OPT_RECONF_ACCEPT 20
132 #define DH6OPT_SIP_SERVER_D 21
133 #define DH6OPT_SIP_SERVER_A 22
134 #define DH6OPT_DNS 23
135 #define DH6OPT_DNSNAME 24
136 #define DH6OPT_IA_PD 25
137 #define DH6OPT_IA_PD_PREFIX 26
138
139 /*
140 * The old prefix delegation option used in the service specification document
141 * (200206xx version) by NTT Communications.
142 */
143 #define DH6OPT_PREFIX_DELEGATION 30
144 #define DH6OPT_PREFIX_INFORMATION 31
145 #define DH6OPT_PREFIX_REQUEST 32
146
147 /*
148 * The following one is an unassigned number.
149 * We temporarily use values as of KAME snap 20031013.
150 */
151 #define DH6OPT_NTP_SERVERS 35
152
153 struct dhcp6opt {
154 u_int16_t dh6opt_type;
155 u_int16_t dh6opt_len;
156 /* type-dependent data follows */
157 };
158
159 struct dhcp6_ia {
160 u_int16_t dh6opt_ia_type;
161 u_int16_t dh6opt_ia_len;
162 u_int32_t dh6opt_ia_iaid;
163 u_int32_t dh6opt_ia_t1;
164 u_int32_t dh6opt_ia_t2;
165 };
166
167 struct dhcp6_ia_prefix {
168 u_int16_t dh6opt_ia_prefix_type;
169 u_int16_t dh6opt_ia_prefix_len;
170 u_int32_t dh6opt_ia_prefix_pltime;
171 u_int32_t dh6opt_ia_prefix_vltime;
172 u_int8_t dh6opt_ia_prefix_plen;
173 struct in6_addr dh6opt_ia_prefix_addr;
174 } __attribute__ ((__packed__));
175
176 static const char *
177 dhcp6opt_name(int type)
178 {
179 static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
180
181 if (type > 65535)
182 return "INVALID option";
183
184 switch(type) {
185 case DH6OPT_CLIENTID:
186 return "client ID";
187 case DH6OPT_SERVERID:
188 return "server ID";
189 case DH6OPT_IA_NA:
190 return "IA_NA";
191 case DH6OPT_ORO:
192 return "option request";
193 case DH6OPT_PREFERENCE:
194 return "preference";
195 case DH6OPT_ELAPSED_TIME:
196 return "elapsed time";
197 case DH6OPT_RELAY_MSG:
198 return "relay message";
199 case DH6OPT_STATUS_CODE:
200 return "status code";
201 case DH6OPT_RAPID_COMMIT:
202 return "rapid commit";
203 case DH6OPT_INTERFACE_ID:
204 return "interface ID";
205 case DH6OPT_RECONF_MSG:
206 return "reconfigure message";
207 case DH6OPT_RECONF_ACCEPT:
208 return "reconfigure accept";
209 case DH6OPT_SIP_SERVER_D:
210 return "SIP Servers Domain";
211 case DH6OPT_SIP_SERVER_A:
212 return "SIP Servers Address";
213 case DH6OPT_DNS:
214 return "DNS";
215 case DH6OPT_PREFIX_DELEGATION:
216 return "prefix delegation";
217 case DH6OPT_PREFIX_INFORMATION:
218 return "prefix information";
219 case DH6OPT_IA_PD:
220 return "IA_PD";
221 case DH6OPT_IA_PD_PREFIX:
222 return "IA_PD prefix";
223 case DH6OPT_NTP_SERVERS:
224 return "NTP Server";
225 default:
226 snprintf(genstr, sizeof(genstr), "opt_%d", type);
227 return(genstr);
228 }
229 }
230
231 static const char *
232 dhcp6stcode(int code)
233 {
234 static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
235
236 if (code > 255)
237 return "INVALID code";
238
239 switch(code) {
240 case DH6OPT_STCODE_SUCCESS:
241 return "success";
242 case DH6OPT_STCODE_UNSPECFAIL:
243 return "unspec failure";
244 case DH6OPT_STCODE_NOADDRAVAIL:
245 return "no addresses";
246 case DH6OPT_STCODE_NOBINDING:
247 return "no binding";
248 case DH6OPT_STCODE_NOTONLINK:
249 return "not on-link";
250 case DH6OPT_STCODE_USEMULTICAST:
251 return "use multicast";
252 case DH6OPT_STCODE_NOPREFIXAVAIL:
253 return "no prefixes";
254 default:
255 snprintf(genstr, sizeof(genstr), "code%d", code);
256 return(genstr);
257 }
258 }
259
260 static void
261 dhcp6opt_print(const u_char *cp, const u_char *ep)
262 {
263 struct dhcp6opt *dh6o;
264 u_char *tp;
265 size_t i;
266 u_int16_t opttype;
267 size_t optlen;
268 u_int16_t val16;
269 u_int32_t val32;
270 struct in6_addr addr6;
271 struct dhcp6_ia ia;
272 struct dhcp6_ia_prefix ia_prefix;
273
274 if (cp == ep)
275 return;
276 while (cp < ep) {
277 if (ep < cp + sizeof(*dh6o))
278 goto trunc;
279 dh6o = (struct dhcp6opt *)cp;
280 optlen = EXTRACT_16BITS(&dh6o->dh6opt_len);
281 if (ep < cp + sizeof(*dh6o) + optlen)
282 goto trunc;
283 opttype = EXTRACT_16BITS(&dh6o->dh6opt_type);
284 printf(" (%s", dhcp6opt_name(opttype));
285 switch (opttype) {
286 case DH6OPT_CLIENTID:
287 case DH6OPT_SERVERID:
288 if (optlen < 2) {
289 /*(*/
290 printf(" ?)");
291 break;
292 }
293 tp = (u_char *)(dh6o + 1);
294 switch (EXTRACT_16BITS(tp)) {
295 case 1:
296 if (optlen >= 2 + 6) {
297 printf(" hwaddr/time type %u time %u ",
298 EXTRACT_16BITS(&tp[2]),
299 EXTRACT_32BITS(&tp[4]));
300 for (i = 8; i < optlen; i++)
301 printf("%02x", tp[i]);
302 /*(*/
303 printf(")");
304 } else {
305 /*(*/
306 printf(" ?)");
307 }
308 break;
309 case 2:
310 if (optlen >= 2 + 8) {
311 printf(" vid ");
312 for (i = 2; i < 2 + 8; i++)
313 printf("%02x", tp[i]);
314 /*(*/
315 printf(")");
316 } else {
317 /*(*/
318 printf(" ?)");
319 }
320 break;
321 case 3:
322 if (optlen >= 2 + 2) {
323 printf(" hwaddr type %u ",
324 EXTRACT_16BITS(&tp[2]));
325 for (i = 4; i < optlen; i++)
326 printf("%02x", tp[i]);
327 /*(*/
328 printf(")");
329 } else {
330 /*(*/
331 printf(" ?)");
332 }
333 break;
334 default:
335 printf(" type %d)", EXTRACT_16BITS(tp));
336 break;
337 }
338 break;
339 case DH6OPT_ORO:
340 if (optlen % 2) {
341 printf(" ?)");
342 break;
343 }
344 tp = (u_char *)(dh6o + 1);
345 for (i = 0; i < optlen; i += 2) {
346 u_int16_t opt;
347
348 memcpy(&opt, &tp[i], sizeof(opt));
349 printf(" %s", dhcp6opt_name(ntohs(opt)));
350 }
351 printf(")");
352 break;
353 case DH6OPT_PREFERENCE:
354 if (optlen != 1) {
355 printf(" ?)");
356 break;
357 }
358 printf(" %d)", *((u_char *)(dh6o + 1) + 1));
359 break;
360 case DH6OPT_ELAPSED_TIME:
361 if (optlen != 2) {
362 printf(" ?)");
363 break;
364 }
365 memcpy(&val16, dh6o + 1, sizeof(val16));
366 val16 = ntohs(val16);
367 printf(" %d)", (int)val16);
368 break;
369 case DH6OPT_RELAY_MSG:
370 printf(" (");
371 dhcp6_print((const u_char *)(dh6o + 1), optlen);
372 printf(")");
373 break;
374 case DH6OPT_RAPID_COMMIT: /* nothing todo */
375 printf(")");
376 break;
377 case DH6OPT_INTERFACE_ID:
378 /*
379 * Since we cannot predict the encoding, print hex dump
380 * at most 10 characters.
381 */
382 for (i = 0; i < optlen && i < 10; i++)
383 printf("%02x", ((u_char *)(dh6o + 1))[i]);
384 break;
385 case DH6OPT_RECONF_MSG:
386 tp = (u_char *)(dh6o + 1);
387 switch (*tp) {
388 case DH6_RENEW:
389 printf(" for renew)");
390 break;
391 case DH6_INFORM_REQ:
392 printf(" for inf-req)");
393 break;
394 default:
395 printf(" for ?\?\?(%02x))", *tp);
396 break;
397 }
398 break;
399 case DH6OPT_RECONF_ACCEPT: /* nothing todo */
400 printf(")");
401 break;
402 case DH6OPT_SIP_SERVER_A:
403 case DH6OPT_DNS:
404 case DH6OPT_NTP_SERVERS:
405 if (optlen % 16) {
406 printf(" ?)");
407 break;
408 }
409 tp = (u_char *)(dh6o + 1);
410 for (i = 0; i < optlen; i += 16)
411 printf(" %s", ip6addr_string(&tp[i]));
412 printf(")");
413 break;
414 case DH6OPT_PREFIX_DELEGATION:
415 dhcp6opt_print((u_char *)(dh6o + 1),
416 (u_char *)(dh6o + 1) + optlen);
417 printf(")");
418 break;
419 case DH6OPT_PREFIX_INFORMATION:
420 if (optlen % 21)
421 printf(" ?)");
422 memcpy(&addr6, (u_char *)(dh6o + 1) + 5,
423 sizeof(addr6));
424 printf(" %s/%d", ip6addr_string(&addr6),
425 (int)*((u_char *)(dh6o + 1) + 4));
426 memcpy(&val32, dh6o + 1, sizeof(val32));
427 val32 = ntohl(val32);
428 if (val32 == DHCP6_DURATITION_INFINITE)
429 printf(" lease-duration: infinite)");
430 else
431 printf(" lease-duration: %u)", val32);
432 break;
433 case DH6OPT_STATUS_CODE:
434 if (optlen < 2) {
435 printf(" ?)");
436 break;
437 }
438 memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16));
439 val16 = ntohs(val16);
440 printf(" %s)", dhcp6stcode(val16));
441 break;
442 case DH6OPT_IA_NA:
443 case DH6OPT_IA_PD:
444 if (optlen < sizeof(ia) - 4) {
445 printf(" ?)");
446 break;
447 }
448 memcpy(&ia, (u_char *)dh6o, sizeof(ia));
449 ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid);
450 ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1);
451 ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2);
452 printf(" IAID:%lu T1:%lu T2:%lu",
453 (unsigned long)ia.dh6opt_ia_iaid,
454 (unsigned long)ia.dh6opt_ia_t1,
455 (unsigned long)ia.dh6opt_ia_t2);
456 if (optlen > sizeof(ia) - 4) {
457 /* there are sub-options */
458 dhcp6opt_print((u_char *)dh6o + sizeof(ia),
459 (u_char *)(dh6o + 1) + optlen);
460 }
461 printf(")");
462 break;
463 case DH6OPT_IA_PD_PREFIX:
464 if (optlen < sizeof(ia_prefix) - 4) {
465 printf(" ?)");
466 break;
467 }
468 memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix));
469 printf(" %s/%d",
470 ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr),
471 ia_prefix.dh6opt_ia_prefix_plen);
472 ia_prefix.dh6opt_ia_prefix_pltime =
473 ntohl(ia_prefix.dh6opt_ia_prefix_pltime);
474 ia_prefix.dh6opt_ia_prefix_vltime =
475 ntohl(ia_prefix.dh6opt_ia_prefix_vltime);
476 printf(" pltime:%lu vltime:%lu",
477 (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime,
478 (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime);
479 if (optlen > sizeof(ia_prefix) - 4) {
480 /* there are sub-options */
481 dhcp6opt_print((u_char *)dh6o +
482 sizeof(ia_prefix),
483 (u_char *)(dh6o + 1) + optlen);
484 }
485 printf(")");
486 break;
487 default:
488 printf(")");
489 break;
490 }
491
492 cp += sizeof(*dh6o) + optlen;
493 }
494 return;
495
496 trunc:
497 printf("[|dhcp6ext]");
498 }
499
500 /*
501 * Print dhcp6 packets
502 */
503 void
504 dhcp6_print(const u_char *cp, u_int length)
505 {
506 struct dhcp6 *dh6;
507 struct dhcp6_relay *dh6relay;
508 const u_char *ep;
509 u_char *extp;
510 const char *name;
511
512 printf("dhcp6");
513
514 ep = (u_char *)snapend;
515 if (cp + length < ep)
516 ep = cp + length;
517
518 dh6 = (struct dhcp6 *)cp;
519 dh6relay = (struct dhcp6_relay *)cp;
520 TCHECK(dh6->dh6_xid);
521 switch (dh6->dh6_msgtype) {
522 case DH6_SOLICIT:
523 name = "solicit";
524 break;
525 case DH6_ADVERTISE:
526 name = "advertise";
527 break;
528 case DH6_REQUEST:
529 name = "request";
530 break;
531 case DH6_CONFIRM:
532 name = "confirm";
533 break;
534 case DH6_RENEW:
535 name = "renew";
536 break;
537 case DH6_REBIND:
538 name = "rebind";
539 break;
540 case DH6_REPLY:
541 name = "reply";
542 break;
543 case DH6_RELEASE:
544 name = "release";
545 break;
546 case DH6_DECLINE:
547 name = "decline";
548 break;
549 case DH6_RECONFIGURE:
550 name = "reconfigure";
551 break;
552 case DH6_INFORM_REQ:
553 name= "inf-req";
554 break;
555 case DH6_RELAY_FORW:
556 name= "relay-fwd";
557 break;
558 case DH6_RELAY_REPLY:
559 name= "relay-reply";
560 break;
561 default:
562 name = NULL;
563 break;
564 }
565
566 if (!vflag) {
567 if (name)
568 printf(" %s", name);
569 else if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
570 dh6->dh6_msgtype != DH6_RELAY_REPLY) {
571 printf(" msgtype-%u", dh6->dh6_msgtype);
572 }
573 return;
574 }
575
576 /* XXX relay agent messages have to be handled differently */
577
578 if (name)
579 printf(" %s (", name); /*)*/
580 else
581 printf(" msgtype-%u (", dh6->dh6_msgtype); /*)*/
582 if (dh6->dh6_msgtype != DH6_RELAY_FORW &&
583 dh6->dh6_msgtype != DH6_RELAY_REPLY) {
584 printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK);
585 extp = (u_char *)(dh6 + 1);
586 dhcp6opt_print(extp, ep);
587 } else { /* relay messages */
588 struct in6_addr addr6;
589
590 TCHECK(dh6relay->dh6relay_peeraddr);
591
592 memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6));
593 printf("linkaddr=%s", ip6addr_string(&addr6));
594
595 memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6));
596 printf(" peeraddr=%s", ip6addr_string(&addr6));
597
598 dhcp6opt_print((u_char *)(dh6relay + 1), ep);
599 }
600 /*(*/
601 printf(")");
602 return;
603
604 trunc:
605 printf("[|dhcp6]");
606 }