print-lwres.c revision 98524
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[] =
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 */
54typedef u_int32_t lwres_uint32_t;
55typedef u_int16_t lwres_uint16_t;
56typedef u_int8_t lwres_uint8_t;
57
58struct 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
82typedef struct {
83	/* public */
84	lwres_uint16_t			datalength;
85	/* data follows */
86} lwres_nooprequest_t;
87
88typedef 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
99typedef struct lwres_addr lwres_addr_t;
100
101struct lwres_addr {
102	lwres_uint32_t			family;
103	lwres_uint16_t			length;
104	/* address folows */
105};
106
107typedef 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
115typedef 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
130typedef struct {
131	/* public */
132	lwres_uint32_t			flags;
133	lwres_addr_t			addr;
134	/* addr body follows */
135} lwres_gnbarequest_t;
136
137typedef 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
151typedef 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
160typedef 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
181struct 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 */
190extern struct tok ns_type2str[];
191extern struct tok ns_class2str[];
192
193static int lwres_printname(size_t, const char *);
194static int lwres_printnamelen(const char *);
195static int lwres_printbinlen(const char *);
196static int lwres_printaddr(lwres_addr_t *);
197
198static int
199lwres_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
220static int
221lwres_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
238static int
239lwres_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
260static int
261lwres_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
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 = 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