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 #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