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