xref: /freebsd/contrib/tcpdump/print-lwres.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
1 /*
2  * Copyright (C) 2001 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 /* \summary: BIND9 Lightweight Resolver protocol printer */
31 
32 #include <config.h>
33 
34 #include "netdissect-stdinc.h"
35 
36 #define ND_LONGJMP_FROM_TCHECK
37 #include "netdissect.h"
38 #include "addrtoname.h"
39 #include "extract.h"
40 
41 #include "nameser.h"
42 
43 /* BIND9 lib/lwres/include/lwres */
44 /*
45  * Use nd_uint16_t for lwres_uint16_t
46  * Use nd_uint32_t for lwres_uint32_t
47 */
48 
49 struct lwres_lwpacket {
50 	nd_uint32_t		length;
51 	nd_uint16_t		version;
52 	nd_uint16_t		pktflags;
53 	nd_uint32_t		serial;
54 	nd_uint32_t		opcode;
55 	nd_uint32_t		result;
56 	nd_uint32_t		recvlength;
57 	nd_uint16_t		authtype;
58 	nd_uint16_t		authlength;
59 };
60 
61 #define LWRES_LWPACKETFLAG_RESPONSE	0x0001U	/* if set, pkt is a response */
62 
63 #define LWRES_LWPACKETVERSION_0		0
64 
65 #define LWRES_FLAG_TRUSTNOTREQUIRED	0x00000001U
66 #define LWRES_FLAG_SECUREDATA		0x00000002U
67 
68 /*
69  * no-op
70  */
71 #define LWRES_OPCODE_NOOP		0x00000000U
72 
73 typedef struct {
74 	/* public */
75 	nd_uint16_t			datalength;
76 	/* data follows */
77 } lwres_nooprequest_t;
78 
79 typedef struct {
80 	/* public */
81 	nd_uint16_t			datalength;
82 	/* data follows */
83 } lwres_noopresponse_t;
84 
85 /*
86  * get addresses by name
87  */
88 #define LWRES_OPCODE_GETADDRSBYNAME	0x00010001U
89 
90 typedef struct lwres_addr lwres_addr_t;
91 
92 struct lwres_addr {
93 	nd_uint32_t			family;
94 	nd_uint16_t			length;
95 	/* address follows */
96 };
97 #define LWRES_ADDR_LEN			6
98 
99 typedef struct {
100 	/* public */
101 	nd_uint32_t			flags;
102 	nd_uint32_t			addrtypes;
103 	nd_uint16_t			namelen;
104 	/* name follows */
105 } lwres_gabnrequest_t;
106 #define LWRES_GABNREQUEST_LEN		10
107 
108 typedef struct {
109 	/* public */
110 	nd_uint32_t			flags;
111 	nd_uint16_t			naliases;
112 	nd_uint16_t			naddrs;
113 	nd_uint16_t			realnamelen;
114 	/* aliases follows */
115 	/* addrs follows */
116 	/* realname follows */
117 } lwres_gabnresponse_t;
118 #define LWRES_GABNRESPONSE_LEN		10
119 
120 /*
121  * get name by address
122  */
123 #define LWRES_OPCODE_GETNAMEBYADDR	0x00010002U
124 typedef struct {
125 	/* public */
126 	nd_uint32_t			flags;
127 	/* addr follows */
128 } lwres_gnbarequest_t;
129 #define LWRES_GNBAREQUEST_LEN		4
130 
131 typedef struct {
132 	/* public */
133 	nd_uint32_t			flags;
134 	nd_uint16_t			naliases;
135 	nd_uint16_t			realnamelen;
136 	/* aliases follows */
137 	/* realname follows */
138 } lwres_gnbaresponse_t;
139 #define LWRES_GNBARESPONSE_LEN		8
140 
141 /*
142  * get rdata by name
143  */
144 #define LWRES_OPCODE_GETRDATABYNAME	0x00010003U
145 
146 typedef struct {
147 	/* public */
148 	nd_uint32_t			flags;
149 	nd_uint16_t			rdclass;
150 	nd_uint16_t			rdtype;
151 	nd_uint16_t			namelen;
152 	/* name follows */
153 } lwres_grbnrequest_t;
154 #define LWRES_GRBNREQUEST_LEN		10
155 
156 typedef struct {
157 	/* public */
158 	nd_uint32_t			flags;
159 	nd_uint16_t			rdclass;
160 	nd_uint16_t			rdtype;
161 	nd_uint32_t			ttl;
162 	nd_uint16_t			nrdatas;
163 	nd_uint16_t			nsigs;
164 	/* realname here (len + name) */
165 	/* rdata here (len + name) */
166 	/* signatures here (len + name) */
167 } lwres_grbnresponse_t;
168 #define LWRES_GRBNRESPONSE_LEN		16
169 
170 #define LWRDATA_VALIDATED	0x00000001
171 
172 #define LWRES_ADDRTYPE_V4		0x00000001U	/* ipv4 */
173 #define LWRES_ADDRTYPE_V6		0x00000002U	/* ipv6 */
174 
175 #define LWRES_MAX_ALIASES		16		/* max # of aliases */
176 #define LWRES_MAX_ADDRS			64		/* max # of addrs */
177 
178 static const struct tok opcode[] = {
179 	{ LWRES_OPCODE_NOOP,		"noop", },
180 	{ LWRES_OPCODE_GETADDRSBYNAME,	"getaddrsbyname", },
181 	{ LWRES_OPCODE_GETNAMEBYADDR,	"getnamebyaddr", },
182 	{ LWRES_OPCODE_GETRDATABYNAME,	"getrdatabyname", },
183 	{ 0,				NULL, },
184 };
185 
186 /* print-domain.c */
187 extern const struct tok ns_type2str[];
188 extern const struct tok ns_class2str[];
189 
190 static unsigned
lwres_printname(netdissect_options * ndo,u_int l,const u_char * p0)191 lwres_printname(netdissect_options *ndo,
192                 u_int l, const u_char *p0)
193 {
194 	ND_PRINT(" ");
195 	(void)nd_printn(ndo, p0, l, NULL);
196 	p0 += l;
197 	if (GET_U_1(p0))
198 		ND_PRINT(" (not NUL-terminated!)");
199 	return l + 1;
200 }
201 
202 static unsigned
lwres_printnamelen(netdissect_options * ndo,const u_char * p)203 lwres_printnamelen(netdissect_options *ndo,
204                    const u_char *p)
205 {
206 	uint16_t l;
207 	int advance;
208 
209 	l = GET_BE_U_2(p);
210 	advance = lwres_printname(ndo, l, p + 2);
211 	return 2 + advance;
212 }
213 
214 static unsigned
lwres_printbinlen(netdissect_options * ndo,const u_char * p0)215 lwres_printbinlen(netdissect_options *ndo,
216                   const u_char *p0)
217 {
218 	const u_char *p;
219 	uint16_t l;
220 	int i;
221 
222 	p = p0;
223 	l = GET_BE_U_2(p);
224 	p += 2;
225 	for (i = 0; i < l; i++) {
226 		ND_PRINT("%02x", GET_U_1(p));
227 		p++;
228 	}
229 	return 2 + l;
230 }
231 
232 static int
lwres_printaddr(netdissect_options * ndo,const u_char * p0)233 lwres_printaddr(netdissect_options *ndo,
234                 const u_char *p0)
235 {
236 	const u_char *p;
237 	const lwres_addr_t *ap;
238 	uint16_t l;
239 	int i;
240 
241 	p = p0;
242 	ap = (const lwres_addr_t *)p;
243 	l = GET_BE_U_2(ap->length);
244 	p += LWRES_ADDR_LEN;
245 	ND_TCHECK_LEN(p, l);
246 
247 	switch (GET_BE_U_4(ap->family)) {
248 	case 1:	/* IPv4 */
249 		if (l < 4)
250 			return -1;
251 		ND_PRINT(" %s", GET_IPADDR_STRING(p));
252 		p += sizeof(nd_ipv4);
253 		break;
254 	case 2:	/* IPv6 */
255 		if (l < 16)
256 			return -1;
257 		ND_PRINT(" %s", GET_IP6ADDR_STRING(p));
258 		p += sizeof(nd_ipv6);
259 		break;
260 	default:
261 		ND_PRINT(" %u/", GET_BE_U_4(ap->family));
262 		for (i = 0; i < l; i++) {
263 			ND_PRINT("%02x", GET_U_1(p));
264 			p++;
265 		}
266 	}
267 
268 	return ND_BYTES_BETWEEN(p0, p);
269 }
270 
271 void
lwres_print(netdissect_options * ndo,const u_char * bp,u_int length)272 lwres_print(netdissect_options *ndo,
273             const u_char *bp, u_int length)
274 {
275 	const u_char *p;
276 	const struct lwres_lwpacket *np;
277 	uint32_t v;
278 	const u_char *s;
279 	int response;
280 	int advance;
281 	int unsupported = 0;
282 
283 	ndo->ndo_protocol = "lwres";
284 	np = (const struct lwres_lwpacket *)bp;
285 	ND_TCHECK_2(np->authlength);
286 
287 	ND_PRINT(" lwres");
288 	v = GET_BE_U_2(np->version);
289 	if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0)
290 		ND_PRINT(" v%u", v);
291 	if (v != LWRES_LWPACKETVERSION_0) {
292 		uint32_t pkt_len = GET_BE_U_4(np->length);
293 		ND_TCHECK_LEN(bp, pkt_len);
294 		s = bp + pkt_len;
295 		goto tail;
296 	}
297 
298 	response = GET_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE;
299 
300 	/* opcode and pktflags */
301 	v = GET_BE_U_4(np->opcode);
302 	ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?");
303 
304 	/* pktflags */
305 	v = GET_BE_U_2(np->pktflags);
306 	if (v & ~LWRES_LWPACKETFLAG_RESPONSE)
307 		ND_PRINT("[0x%x]", v);
308 
309 	if (ndo->ndo_vflag > 1) {
310 		ND_PRINT(" (");	/*)*/
311 		ND_PRINT("serial:0x%x", GET_BE_U_4(np->serial));
312 		ND_PRINT(" result:0x%x", GET_BE_U_4(np->result));
313 		ND_PRINT(" recvlen:%u", GET_BE_U_4(np->recvlength));
314 		/* BIND910: not used */
315 		if (ndo->ndo_vflag > 2) {
316 			ND_PRINT(" authtype:0x%x", GET_BE_U_2(np->authtype));
317 			ND_PRINT(" authlen:%u", GET_BE_U_2(np->authlength));
318 		}
319 		/*(*/
320 		ND_PRINT(")");
321 	}
322 
323 	/* per-opcode content */
324 	if (!response) {
325 		/*
326 		 * queries
327 		 */
328 		const lwres_gabnrequest_t *gabn;
329 		const lwres_gnbarequest_t *gnba;
330 		const lwres_grbnrequest_t *grbn;
331 		uint32_t l;
332 
333 		gabn = NULL;
334 		gnba = NULL;
335 		grbn = NULL;
336 
337 		p = (const u_char *)(np + 1);
338 		switch (GET_BE_U_4(np->opcode)) {
339 		case LWRES_OPCODE_NOOP:
340 			s = p;
341 			break;
342 		case LWRES_OPCODE_GETADDRSBYNAME:
343 			gabn = (const lwres_gabnrequest_t *)p;
344 			ND_TCHECK_2(gabn->namelen);
345 
346 			/* BIND910: not used */
347 			if (ndo->ndo_vflag > 2) {
348 				ND_PRINT(" flags:0x%x",
349 				    GET_BE_U_4(gabn->flags));
350 			}
351 
352 			v = GET_BE_U_4(gabn->addrtypes);
353 			switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) {
354 			case LWRES_ADDRTYPE_V4:
355 				ND_PRINT(" IPv4");
356 				break;
357 			case LWRES_ADDRTYPE_V6:
358 				ND_PRINT(" IPv6");
359 				break;
360 			case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6:
361 				ND_PRINT(" IPv4/6");
362 				break;
363 			}
364 			if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6))
365 				ND_PRINT("[0x%x]", v);
366 
367 			s = p + LWRES_GABNREQUEST_LEN;
368 			l = GET_BE_U_2(gabn->namelen);
369 			advance = lwres_printname(ndo, l, s);
370 			s += advance;
371 			break;
372 		case LWRES_OPCODE_GETNAMEBYADDR:
373 			gnba = (const lwres_gnbarequest_t *)p;
374 			ND_TCHECK_4(gnba->flags);
375 
376 			/* BIND910: not used */
377 			if (ndo->ndo_vflag > 2) {
378 				ND_PRINT(" flags:0x%x",
379 				    GET_BE_U_4(gnba->flags));
380 			}
381 
382 			s = p + LWRES_GNBAREQUEST_LEN;
383 			advance = lwres_printaddr(ndo, s);
384 			if (advance < 0)
385 				goto invalid;
386 			s += advance;
387 			break;
388 		case LWRES_OPCODE_GETRDATABYNAME:
389 			/* XXX no trace, not tested */
390 			grbn = (const lwres_grbnrequest_t *)p;
391 			ND_TCHECK_2(grbn->namelen);
392 
393 			/* BIND910: not used */
394 			if (ndo->ndo_vflag > 2) {
395 				ND_PRINT(" flags:0x%x",
396 				    GET_BE_U_4(grbn->flags));
397 			}
398 
399 			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
400 			    GET_BE_U_2(grbn->rdtype)));
401 			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
402 				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
403 				    GET_BE_U_2(grbn->rdclass)));
404 			}
405 
406 			s = p + LWRES_GRBNREQUEST_LEN;
407 			l = GET_BE_U_2(grbn->namelen);
408 			advance = lwres_printname(ndo, l, s);
409 			s += advance;
410 			break;
411 		default:
412 			s = p;
413 			unsupported++;
414 			break;
415 		}
416 	} else {
417 		/*
418 		 * responses
419 		 */
420 		const lwres_gabnresponse_t *gabn;
421 		const lwres_gnbaresponse_t *gnba;
422 		const lwres_grbnresponse_t *grbn;
423 		uint32_t l, na;
424 		uint32_t i;
425 
426 		gabn = NULL;
427 		gnba = NULL;
428 		grbn = NULL;
429 
430 		p = (const u_char *)(np + 1);
431 		switch (GET_BE_U_4(np->opcode)) {
432 		case LWRES_OPCODE_NOOP:
433 			s = p;
434 			break;
435 		case LWRES_OPCODE_GETADDRSBYNAME:
436 			gabn = (const lwres_gabnresponse_t *)p;
437 			ND_TCHECK_2(gabn->realnamelen);
438 
439 			/* BIND910: not used */
440 			if (ndo->ndo_vflag > 2) {
441 				ND_PRINT(" flags:0x%x",
442 				    GET_BE_U_4(gabn->flags));
443 			}
444 
445 			ND_PRINT(" %u/%u", GET_BE_U_2(gabn->naliases),
446 				  GET_BE_U_2(gabn->naddrs));
447 
448 			s = p + LWRES_GABNRESPONSE_LEN;
449 			l = GET_BE_U_2(gabn->realnamelen);
450 			advance = lwres_printname(ndo, l, s);
451 			s += advance;
452 
453 			/* aliases */
454 			na = GET_BE_U_2(gabn->naliases);
455 			for (i = 0; i < na; i++) {
456 				advance = lwres_printnamelen(ndo, s);
457 				s += advance;
458 			}
459 
460 			/* addrs */
461 			na = GET_BE_U_2(gabn->naddrs);
462 			for (i = 0; i < na; i++) {
463 				advance = lwres_printaddr(ndo, s);
464 				if (advance < 0)
465 					goto invalid;
466 				s += advance;
467 			}
468 			break;
469 		case LWRES_OPCODE_GETNAMEBYADDR:
470 			gnba = (const lwres_gnbaresponse_t *)p;
471 			ND_TCHECK_2(gnba->realnamelen);
472 
473 			/* BIND910: not used */
474 			if (ndo->ndo_vflag > 2) {
475 				ND_PRINT(" flags:0x%x",
476 				    GET_BE_U_4(gnba->flags));
477 			}
478 
479 			ND_PRINT(" %u", GET_BE_U_2(gnba->naliases));
480 
481 			s = p + LWRES_GNBARESPONSE_LEN;
482 			l = GET_BE_U_2(gnba->realnamelen);
483 			advance = lwres_printname(ndo, l, s);
484 			s += advance;
485 
486 			/* aliases */
487 			na = GET_BE_U_2(gnba->naliases);
488 			for (i = 0; i < na; i++) {
489 				advance = lwres_printnamelen(ndo, s);
490 				s += advance;
491 			}
492 			break;
493 		case LWRES_OPCODE_GETRDATABYNAME:
494 			/* XXX no trace, not tested */
495 			grbn = (const lwres_grbnresponse_t *)p;
496 			ND_TCHECK_2(grbn->nsigs);
497 
498 			/* BIND910: not used */
499 			if (ndo->ndo_vflag > 2) {
500 				ND_PRINT(" flags:0x%x",
501 				    GET_BE_U_4(grbn->flags));
502 			}
503 
504 			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
505 			    GET_BE_U_2(grbn->rdtype)));
506 			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
507 				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
508 				    GET_BE_U_2(grbn->rdclass)));
509 			}
510 			ND_PRINT(" TTL ");
511 			unsigned_relts_print(ndo,
512 					     GET_BE_U_4(grbn->ttl));
513 			ND_PRINT(" %u/%u", GET_BE_U_2(grbn->nrdatas),
514 				  GET_BE_U_2(grbn->nsigs));
515 
516 			s = p + LWRES_GRBNRESPONSE_LEN;
517 			advance = lwres_printnamelen(ndo, s);
518 			s += advance;
519 
520 			/* rdatas */
521 			na = GET_BE_U_2(grbn->nrdatas);
522 			for (i = 0; i < na; i++) {
523 				/* XXX should decode resource data */
524 				advance = lwres_printbinlen(ndo, s);
525 				s += advance;
526 			}
527 
528 			/* sigs */
529 			na = GET_BE_U_2(grbn->nsigs);
530 			for (i = 0; i < na; i++) {
531 				/* XXX how should we print it? */
532 				advance = lwres_printbinlen(ndo, s);
533 				s += advance;
534 			}
535 			break;
536 		default:
537 			s = p;
538 			unsupported++;
539 			break;
540 		}
541 	}
542 
543   tail:
544 	/* length mismatch */
545 	if (GET_BE_U_4(np->length) != length) {
546 		ND_PRINT(" [len: %u != %u]", GET_BE_U_4(np->length),
547 			  length);
548 	}
549 	if (!unsupported && ND_BYTES_BETWEEN(bp, s) < GET_BE_U_4(np->length))
550 		ND_PRINT("[extra]");
551 	return;
552 
553   invalid:
554 	nd_print_invalid(ndo);
555 }
556