Home | History | Annotate | Download | only in tcpdump
      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