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