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