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