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