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