xref: /openbsd-src/usr.sbin/tcpdump/print-dhcp6.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: print-dhcp6.c,v 1.11 2018/10/22 16:12:45 kn Exp $	*/
2 
3 /*
4  * Copyright (C) 1998 and 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/time.h>
33 #include <sys/socket.h>
34 
35 struct mbuf;
36 struct rtentry;
37 #include <net/if.h>
38 
39 #include <netinet/in.h>
40 
41 #include <ctype.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <arpa/inet.h>
45 
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "dhcp6.h"
49 #include "dhcp6opt.h"
50 
51 #if 0
52 static void dhcp6opttab_init(void);
53 static struct dhcp6_opt *dhcp6opttab_byname(char *);
54 #endif
55 static struct dhcp6_opt *dhcp6opttab_bycode(u_int);
56 
57 static char tstr[] = " [|dhcp6]";
58 
59 static struct dhcp6_opt dh6opttab[] = {
60 	/* IP Address Extension */
61 	{ 1, OL6_N,	"IP Address",			OT6_NONE, },
62 
63 	/* General Extension */
64 	{ 2, 4,		"Time Offset",			OT6_NUM, },
65 	{ 3, OL6_N,	"IEEE 1003.1 POSIX Timezone",	OT6_STR, },
66 	{ 6, OL6_16N,	"Domain Name Server",		OT6_V6, },
67 	{ 10, OL6_N,	"Domain Name",			OT6_STR, },
68 
69 	/* Application and Service Parameters */
70 	{ 16, OL6_N,	"Directory Agent",		OT6_NONE, },
71 	{ 17, OL6_N,	"Service Scope"	,		OT6_NONE, },
72 	{ 18, OL6_16N,	"Network Time Protocol Servers", OT6_V6, },
73 	{ 19, OL6_N,	"NIS Domain",			OT6_STR, },
74 	{ 20, OL6_16N,	"NIS Servers",			OT6_V6, },
75 	{ 21, OL6_N,	"NIS+ Domain",			OT6_STR, },
76 	{ 22, OL6_16N,	"NIS+ Servers",			OT6_V6, },
77 
78 	/* TCP Parameters */
79 	{ 32, 4,	"TCP Keepalive Interval",	OT6_NUM, },
80 
81 	/* DHCPv6 Extensions */
82 	{ 40, 4,	"Maximum DHCPv6 Message Size",	OT6_NUM, },
83 	{ 41, OL6_N,	"DHCP Retransmission and Configuration Parameter",
84 							OT6_NONE, },
85 	{ 48, OL6_N,	"Platform Specific Information", OT6_NONE, },
86 	{ 49, OL6_N,	"Platform Class Identifier",	OT6_STR, },
87 	{ 64, OL6_N,	"Class Identifier",		OT6_STR, },
88 	{ 66, 16,	"Reconfigure Multicast Address", OT6_V6, },
89 	{ 67, 16,	"Renumber DHCPv6 Server Address",
90 							OT6_V6, },
91 	{ 68, OL6_N,	"DHCP Relay ICMP Error Message", OT6_NONE, },
92 	{ 84, OL6_N,	"Client-Server Authentication",	OT6_NONE, },
93 	{ 85, 4,	"Client Key Selection",		OT6_NUM, },
94 
95 	/* End Extension */
96 	{ 65536, OL6_Z,	"End",				OT6_NONE, },
97 
98 	{ 0 },
99 };
100 
101 #if 0
102 static struct dhcp6_opt *dh6o_pad;
103 static struct dhcp6_opt *dh6o_end;
104 
105 static void
106 dhcp6opttab_init()
107 {
108 	dh6o_pad = dhcp6opttab_bycode(0);
109 	dh6o_end = dhcp6opttab_bycode(65536);
110 }
111 #endif
112 
113 #if 0
114 static struct dhcp6_opt *
115 dhcp6opttab_byname(name)
116 	char *name;
117 {
118 	struct dhcp6_opt *p;
119 
120 	for (p = dh6opttab; p->code; p++)
121 		if (strcmp(name, p->name) == 0)
122 			return p;
123 	return NULL;
124 }
125 #endif
126 
127 static struct dhcp6_opt *
128 dhcp6opttab_bycode(code)
129 	u_int code;
130 {
131 	struct dhcp6_opt *p;
132 
133 	for (p = dh6opttab; p->code; p++)
134 		if (p->code == code)
135 			return p;
136 	return NULL;
137 }
138 
139 static void
140 dhcp6ext_print(u_char *cp, u_char *ep)
141 {
142 	u_int16_t code, len;
143 	struct dhcp6_opt *p;
144 	char buf[BUFSIZ];
145 	int i;
146 
147 	if (cp == ep)
148 		return;
149 	printf(" ");
150 	while (cp < ep) {
151 		code = ntohs(*(u_int16_t *)&cp[0]);
152 		if (code != 65535)
153 			len = ntohs(*(u_int16_t *)&cp[2]);
154 		else
155 			len = 0;
156 		p = dhcp6opttab_bycode(code);
157 		if (p == NULL) {
158 			printf("(unknown, len=%d)", len);
159 			cp += len + 4;
160 			continue;
161 		}
162 
163 		/* sanity check on length */
164 		switch (p->len) {
165 		case OL6_N:
166 			break;
167 		case OL6_16N:
168 			if (len % 16 != 0)
169 				goto trunc;
170 			break;
171 		case OL6_Z:
172 			if (len != 0)
173 				goto trunc;
174 			break;
175 		default:
176 			if (len != p->len)
177 				goto trunc;
178 			break;
179 		}
180 		if (cp + 4 + len > ep) {
181 			printf("[|%s]", p->name);
182 			return;
183 		}
184 
185 		printf("(%s, ", p->name);
186 		switch (p->type) {
187 		case OT6_V6:
188 			for (i = 0; i < len; i += 16) {
189 				inet_ntop(AF_INET6, &cp[4 + i], buf,
190 					sizeof(buf));
191 				if (i != 0)
192 					printf(",");
193 				printf("%s", buf);
194 			}
195 			break;
196 		case OT6_STR:
197 			memset(&buf, 0, sizeof(buf));
198 			strlcpy(buf, &cp[4], len);
199 			printf("%s", buf);
200 			break;
201 		case OT6_NUM:
202 			printf("%d", (u_int32_t)ntohl(*(u_int32_t *)&cp[4]));
203 			break;
204 		default:
205 			for (i = 0; i < len; i++)
206 				printf("%02x", cp[4 + i] & 0xff);
207 		}
208 		printf(")");
209 		cp += len + 4;
210 	}
211 	return;
212 
213 trunc:
214 	printf("[|dhcp6ext]");
215 }
216 
217 /*
218  * Print dhcp6 requests
219  */
220 void
221 dhcp6_print(const u_char *cp, u_int length,
222 	    u_short sport, u_short dport)
223 {
224 	union dhcp6 *dh6;
225 	u_char *ep;
226 	u_char *extp;
227 
228 	printf("dhcp6");
229 
230 	ep = (u_char *)snapend;
231 
232 	dh6 = (union dhcp6 *)cp;
233 	TCHECK(dh6->dh6_msgtype);
234 	switch (dh6->dh6_msgtype) {
235 	case DH6_SOLICIT:
236 		if (vflag && TTEST(dh6->dh6_sol.dh6sol_relayaddr)) {
237 			printf(" solicit(");
238 			if ((dh6->dh6_sol.dh6sol_flags & DH6SOL_CLOSE) != 0)
239 				printf("C");
240 			if (dh6->dh6_sol.dh6sol_flags != 0)
241 				printf(" ");
242 			printf("cliaddr=%s",
243 				ip6addr_string(&dh6->dh6_sol.dh6sol_cliaddr));
244 			printf(" relayaddr=%s",
245 				ip6addr_string(&dh6->dh6_sol.dh6sol_relayaddr));
246 			printf(")");
247 		} else
248 			printf(" solicit");
249 		break;
250 	case DH6_ADVERT:
251 		if (!(vflag && TTEST(dh6->dh6_adv.dh6adv_serveraddr))) {
252 			printf(" advert");
253 			break;
254 		}
255 		printf(" advert(");
256 		if ((dh6->dh6_adv.dh6adv_flags & DH6ADV_SERVPRESENT) != 0)
257 			printf("S");
258 		if (dh6->dh6_adv.dh6adv_flags != 0)
259 			printf(" ");
260 		printf("pref=%u", dh6->dh6_adv.dh6adv_pref);
261 		printf(" cliaddr=%s",
262 			ip6addr_string(&dh6->dh6_adv.dh6adv_cliaddr));
263 		printf(" relayaddr=%s",
264 			ip6addr_string(&dh6->dh6_adv.dh6adv_relayaddr));
265 		printf(" servaddr=%s",
266 			ip6addr_string(&dh6->dh6_adv.dh6adv_serveraddr));
267 		extp = (u_char *)((&dh6->dh6_adv) + 1);
268 		dhcp6ext_print(extp, ep);
269 		printf(")");
270 		break;
271 	case DH6_REQUEST:
272 		if (!(vflag && TTEST(dh6->dh6_req.dh6req_relayaddr))) {
273 			printf(" request");
274 			break;
275 		}
276 		printf(" request(");
277 		if ((dh6->dh6_req.dh6req_flags & DH6REQ_CLOSE) != 0)
278 			printf("C");
279 		if ((dh6->dh6_req.dh6req_flags & DH6REQ_SERVPRESENT) != 0)
280 			printf("S");
281 		if ((dh6->dh6_req.dh6req_flags & DH6REQ_REBOOT) != 0)
282 			printf("R");
283 		if (dh6->dh6_req.dh6req_flags != 0)
284 			printf(" ");
285 		printf("xid=0x%04x", dh6->dh6_req.dh6req_xid);
286 		printf(" cliaddr=%s",
287 			ip6addr_string(&dh6->dh6_req.dh6req_cliaddr));
288 		printf(" relayaddr=%s",
289 			ip6addr_string(&dh6->dh6_req.dh6req_relayaddr));
290 		extp = (char *)((&dh6->dh6_req) + 1);
291 		if ((dh6->dh6_req.dh6req_flags & DH6REQ_SERVPRESENT) != 0) {
292 			printf(" servaddr=%s", ip6addr_string(extp));
293 			extp += 16;
294 		}
295 		dhcp6ext_print(extp, ep);
296 		printf(")");
297 		break;
298 	case DH6_REPLY:
299 		if (!(vflag && TTEST(dh6->dh6_rep.dh6rep_xid))) {
300 			printf(" reply");
301 			break;
302 		}
303 		printf(" reply(");
304 		if ((dh6->dh6_rep.dh6rep_flagandstat & DH6REP_CLIPRESENT) != 0)
305 			printf("C");
306 		if (dh6->dh6_rep.dh6rep_flagandstat != 0)
307 			printf(" ");
308 		printf("stat=0x%02x",
309 			dh6->dh6_rep.dh6rep_flagandstat & DH6REP_STATMASK);
310 		extp = (u_char *)((&dh6->dh6_rep) + 1);
311 		if ((dh6->dh6_rep.dh6rep_flagandstat & DH6REP_CLIPRESENT) != 0) {
312 			printf(" cliaddr=%s", ip6addr_string(extp));
313 			extp += 16;
314 		}
315 		dhcp6ext_print(extp, ep);
316 		printf(")");
317 		break;
318 	case DH6_RELEASE:
319 		printf(" release");
320 		break;
321 	case DH6_RECONFIG:
322 		printf(" reconfig");
323 		break;
324 	}
325 	return;
326 
327 trunc:
328 	printf("%s", tstr);
329 }
330