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