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