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 */
48typedef uint32_t lwres_uint32_t;
49typedef uint16_t lwres_uint16_t;
50typedef uint8_t lwres_uint8_t;
51
52struct 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
76typedef struct {
77	/* public */
78	lwres_uint16_t			datalength;
79	/* data follows */
80} lwres_nooprequest_t;
81
82typedef 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
93typedef struct lwres_addr lwres_addr_t;
94
95struct lwres_addr {
96	lwres_uint32_t			family;
97	lwres_uint16_t			length;
98	/* address folows */
99};
100
101typedef 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
109typedef 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
124typedef struct {
125	/* public */
126	lwres_uint32_t			flags;
127	lwres_addr_t			addr;
128	/* addr body follows */
129} lwres_gnbarequest_t;
130
131typedef 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
145typedef 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
154typedef 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
175static 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 */
184extern const struct tok ns_type2str[];
185extern const struct tok ns_class2str[];
186
187static int
188lwres_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
210static int
211lwres_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
229static int
230lwres_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
252static int
253lwres_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
291void
292lwres_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