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