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