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#define ND_LONGJMP_FROM_TCHECK
39#include "netdissect.h"
40#include "addrtoname.h"
41#include "extract.h"
42
43#include "nameser.h"
44
45/* BIND9 lib/lwres/include/lwres */
46/*
47 * Use nd_uint16_t for lwres_uint16_t
48 * Use nd_uint32_t for lwres_uint32_t
49*/
50
51struct lwres_lwpacket {
52	nd_uint32_t		length;
53	nd_uint16_t		version;
54	nd_uint16_t		pktflags;
55	nd_uint32_t		serial;
56	nd_uint32_t		opcode;
57	nd_uint32_t		result;
58	nd_uint32_t		recvlength;
59	nd_uint16_t		authtype;
60	nd_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
75typedef struct {
76	/* public */
77	nd_uint16_t			datalength;
78	/* data follows */
79} lwres_nooprequest_t;
80
81typedef struct {
82	/* public */
83	nd_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
92typedef struct lwres_addr lwres_addr_t;
93
94struct lwres_addr {
95	nd_uint32_t			family;
96	nd_uint16_t			length;
97	/* address follows */
98};
99#define LWRES_ADDR_LEN			6
100
101typedef struct {
102	/* public */
103	nd_uint32_t			flags;
104	nd_uint32_t			addrtypes;
105	nd_uint16_t			namelen;
106	/* name follows */
107} lwres_gabnrequest_t;
108#define LWRES_GABNREQUEST_LEN		10
109
110typedef struct {
111	/* public */
112	nd_uint32_t			flags;
113	nd_uint16_t			naliases;
114	nd_uint16_t			naddrs;
115	nd_uint16_t			realnamelen;
116	/* aliases follows */
117	/* addrs follows */
118	/* realname follows */
119} lwres_gabnresponse_t;
120#define LWRES_GABNRESPONSE_LEN		10
121
122/*
123 * get name by address
124 */
125#define LWRES_OPCODE_GETNAMEBYADDR	0x00010002U
126typedef struct {
127	/* public */
128	nd_uint32_t			flags;
129	/* addr follows */
130} lwres_gnbarequest_t;
131#define LWRES_GNBAREQUEST_LEN		4
132
133typedef struct {
134	/* public */
135	nd_uint32_t			flags;
136	nd_uint16_t			naliases;
137	nd_uint16_t			realnamelen;
138	/* aliases follows */
139	/* realname follows */
140} lwres_gnbaresponse_t;
141#define LWRES_GNBARESPONSE_LEN		8
142
143/*
144 * get rdata by name
145 */
146#define LWRES_OPCODE_GETRDATABYNAME	0x00010003U
147
148typedef struct {
149	/* public */
150	nd_uint32_t			flags;
151	nd_uint16_t			rdclass;
152	nd_uint16_t			rdtype;
153	nd_uint16_t			namelen;
154	/* name follows */
155} lwres_grbnrequest_t;
156#define LWRES_GRBNREQUEST_LEN		10
157
158typedef struct {
159	/* public */
160	nd_uint32_t			flags;
161	nd_uint16_t			rdclass;
162	nd_uint16_t			rdtype;
163	nd_uint32_t			ttl;
164	nd_uint16_t			nrdatas;
165	nd_uint16_t			nsigs;
166	/* realname here (len + name) */
167	/* rdata here (len + name) */
168	/* signatures here (len + name) */
169} lwres_grbnresponse_t;
170#define LWRES_GRBNRESPONSE_LEN		16
171
172#define LWRDATA_VALIDATED	0x00000001
173
174#define LWRES_ADDRTYPE_V4		0x00000001U	/* ipv4 */
175#define LWRES_ADDRTYPE_V6		0x00000002U	/* ipv6 */
176
177#define LWRES_MAX_ALIASES		16		/* max # of aliases */
178#define LWRES_MAX_ADDRS			64		/* max # of addrs */
179
180static const struct tok opcode[] = {
181	{ LWRES_OPCODE_NOOP,		"noop", },
182	{ LWRES_OPCODE_GETADDRSBYNAME,	"getaddrsbyname", },
183	{ LWRES_OPCODE_GETNAMEBYADDR,	"getnamebyaddr", },
184	{ LWRES_OPCODE_GETRDATABYNAME,	"getrdatabyname", },
185	{ 0,				NULL, },
186};
187
188/* print-domain.c */
189extern const struct tok ns_type2str[];
190extern const struct tok ns_class2str[];
191
192static unsigned
193lwres_printname(netdissect_options *ndo,
194                u_int l, const u_char *p0)
195{
196	ND_PRINT(" ");
197	(void)nd_printn(ndo, p0, l, NULL);
198	p0 += l;
199	if (GET_U_1(p0))
200		ND_PRINT(" (not NUL-terminated!)");
201	return l + 1;
202}
203
204static unsigned
205lwres_printnamelen(netdissect_options *ndo,
206                   const u_char *p)
207{
208	uint16_t l;
209	int advance;
210
211	l = GET_BE_U_2(p);
212	advance = lwres_printname(ndo, l, p + 2);
213	return 2 + advance;
214}
215
216static unsigned
217lwres_printbinlen(netdissect_options *ndo,
218                  const u_char *p0)
219{
220	const u_char *p;
221	uint16_t l;
222	int i;
223
224	p = p0;
225	l = GET_BE_U_2(p);
226	p += 2;
227	for (i = 0; i < l; i++) {
228		ND_PRINT("%02x", GET_U_1(p));
229		p++;
230	}
231	return 2 + l;
232}
233
234static int
235lwres_printaddr(netdissect_options *ndo,
236                const u_char *p0)
237{
238	const u_char *p;
239	const lwres_addr_t *ap;
240	uint16_t l;
241	int i;
242
243	p = p0;
244	ap = (const lwres_addr_t *)p;
245	l = GET_BE_U_2(ap->length);
246	p += LWRES_ADDR_LEN;
247	ND_TCHECK_LEN(p, l);
248
249	switch (GET_BE_U_4(ap->family)) {
250	case 1:	/* IPv4 */
251		if (l < 4)
252			return -1;
253		ND_PRINT(" %s", GET_IPADDR_STRING(p));
254		p += sizeof(nd_ipv4);
255		break;
256	case 2:	/* IPv6 */
257		if (l < 16)
258			return -1;
259		ND_PRINT(" %s", GET_IP6ADDR_STRING(p));
260		p += sizeof(nd_ipv6);
261		break;
262	default:
263		ND_PRINT(" %u/", GET_BE_U_4(ap->family));
264		for (i = 0; i < l; i++) {
265			ND_PRINT("%02x", GET_U_1(p));
266			p++;
267		}
268	}
269
270	return ND_BYTES_BETWEEN(p, p0);
271}
272
273void
274lwres_print(netdissect_options *ndo,
275            const u_char *bp, u_int length)
276{
277	const u_char *p;
278	const struct lwres_lwpacket *np;
279	uint32_t v;
280	const u_char *s;
281	int response;
282	int advance;
283	int unsupported = 0;
284
285	ndo->ndo_protocol = "lwres";
286	np = (const struct lwres_lwpacket *)bp;
287	ND_TCHECK_2(np->authlength);
288
289	ND_PRINT(" lwres");
290	v = GET_BE_U_2(np->version);
291	if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0)
292		ND_PRINT(" v%u", v);
293	if (v != LWRES_LWPACKETVERSION_0) {
294		s = bp + GET_BE_U_4(np->length);
295		goto tail;
296	}
297
298	response = GET_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE;
299
300	/* opcode and pktflags */
301	v = GET_BE_U_4(np->opcode);
302	ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?");
303
304	/* pktflags */
305	v = GET_BE_U_2(np->pktflags);
306	if (v & ~LWRES_LWPACKETFLAG_RESPONSE)
307		ND_PRINT("[0x%x]", v);
308
309	if (ndo->ndo_vflag > 1) {
310		ND_PRINT(" (");	/*)*/
311		ND_PRINT("serial:0x%x", GET_BE_U_4(np->serial));
312		ND_PRINT(" result:0x%x", GET_BE_U_4(np->result));
313		ND_PRINT(" recvlen:%u", GET_BE_U_4(np->recvlength));
314		/* BIND910: not used */
315		if (ndo->ndo_vflag > 2) {
316			ND_PRINT(" authtype:0x%x", GET_BE_U_2(np->authtype));
317			ND_PRINT(" authlen:%u", GET_BE_U_2(np->authlength));
318		}
319		/*(*/
320		ND_PRINT(")");
321	}
322
323	/* per-opcode content */
324	if (!response) {
325		/*
326		 * queries
327		 */
328		const lwres_gabnrequest_t *gabn;
329		const lwres_gnbarequest_t *gnba;
330		const lwres_grbnrequest_t *grbn;
331		uint32_t l;
332
333		gabn = NULL;
334		gnba = NULL;
335		grbn = NULL;
336
337		p = (const u_char *)(np + 1);
338		switch (GET_BE_U_4(np->opcode)) {
339		case LWRES_OPCODE_NOOP:
340			s = p;
341			break;
342		case LWRES_OPCODE_GETADDRSBYNAME:
343			gabn = (const lwres_gabnrequest_t *)p;
344			ND_TCHECK_2(gabn->namelen);
345
346			/* BIND910: not used */
347			if (ndo->ndo_vflag > 2) {
348				ND_PRINT(" flags:0x%x",
349				    GET_BE_U_4(gabn->flags));
350			}
351
352			v = GET_BE_U_4(gabn->addrtypes);
353			switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) {
354			case LWRES_ADDRTYPE_V4:
355				ND_PRINT(" IPv4");
356				break;
357			case LWRES_ADDRTYPE_V6:
358				ND_PRINT(" IPv6");
359				break;
360			case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6:
361				ND_PRINT(" IPv4/6");
362				break;
363			}
364			if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6))
365				ND_PRINT("[0x%x]", v);
366
367			s = p + LWRES_GABNREQUEST_LEN;
368			l = GET_BE_U_2(gabn->namelen);
369			advance = lwres_printname(ndo, l, s);
370			s += advance;
371			break;
372		case LWRES_OPCODE_GETNAMEBYADDR:
373			gnba = (const lwres_gnbarequest_t *)p;
374			ND_TCHECK_4(gnba->flags);
375
376			/* BIND910: not used */
377			if (ndo->ndo_vflag > 2) {
378				ND_PRINT(" flags:0x%x",
379				    GET_BE_U_4(gnba->flags));
380			}
381
382			s = p + LWRES_GNBAREQUEST_LEN;
383			advance = lwres_printaddr(ndo, s);
384			if (advance < 0)
385				goto invalid;
386			s += advance;
387			break;
388		case LWRES_OPCODE_GETRDATABYNAME:
389			/* XXX no trace, not tested */
390			grbn = (const lwres_grbnrequest_t *)p;
391			ND_TCHECK_2(grbn->namelen);
392
393			/* BIND910: not used */
394			if (ndo->ndo_vflag > 2) {
395				ND_PRINT(" flags:0x%x",
396				    GET_BE_U_4(grbn->flags));
397			}
398
399			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
400			    GET_BE_U_2(grbn->rdtype)));
401			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
402				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
403				    GET_BE_U_2(grbn->rdclass)));
404			}
405
406			s = p + LWRES_GRBNREQUEST_LEN;
407			l = GET_BE_U_2(grbn->namelen);
408			advance = lwres_printname(ndo, l, s);
409			s += advance;
410			break;
411		default:
412			s = p;
413			unsupported++;
414			break;
415		}
416	} else {
417		/*
418		 * responses
419		 */
420		const lwres_gabnresponse_t *gabn;
421		const lwres_gnbaresponse_t *gnba;
422		const lwres_grbnresponse_t *grbn;
423		uint32_t l, na;
424		uint32_t i;
425
426		gabn = NULL;
427		gnba = NULL;
428		grbn = NULL;
429
430		p = (const u_char *)(np + 1);
431		switch (GET_BE_U_4(np->opcode)) {
432		case LWRES_OPCODE_NOOP:
433			s = p;
434			break;
435		case LWRES_OPCODE_GETADDRSBYNAME:
436			gabn = (const lwres_gabnresponse_t *)p;
437			ND_TCHECK_2(gabn->realnamelen);
438
439			/* BIND910: not used */
440			if (ndo->ndo_vflag > 2) {
441				ND_PRINT(" flags:0x%x",
442				    GET_BE_U_4(gabn->flags));
443			}
444
445			ND_PRINT(" %u/%u", GET_BE_U_2(gabn->naliases),
446				  GET_BE_U_2(gabn->naddrs));
447
448			s = p + LWRES_GABNRESPONSE_LEN;
449			l = GET_BE_U_2(gabn->realnamelen);
450			advance = lwres_printname(ndo, l, s);
451			s += advance;
452
453			/* aliases */
454			na = GET_BE_U_2(gabn->naliases);
455			for (i = 0; i < na; i++) {
456				advance = lwres_printnamelen(ndo, s);
457				s += advance;
458			}
459
460			/* addrs */
461			na = GET_BE_U_2(gabn->naddrs);
462			for (i = 0; i < na; i++) {
463				advance = lwres_printaddr(ndo, s);
464				if (advance < 0)
465					goto invalid;
466				s += advance;
467			}
468			break;
469		case LWRES_OPCODE_GETNAMEBYADDR:
470			gnba = (const lwres_gnbaresponse_t *)p;
471			ND_TCHECK_2(gnba->realnamelen);
472
473			/* BIND910: not used */
474			if (ndo->ndo_vflag > 2) {
475				ND_PRINT(" flags:0x%x",
476				    GET_BE_U_4(gnba->flags));
477			}
478
479			ND_PRINT(" %u", GET_BE_U_2(gnba->naliases));
480
481			s = p + LWRES_GNBARESPONSE_LEN;
482			l = GET_BE_U_2(gnba->realnamelen);
483			advance = lwres_printname(ndo, l, s);
484			s += advance;
485
486			/* aliases */
487			na = GET_BE_U_2(gnba->naliases);
488			for (i = 0; i < na; i++) {
489				advance = lwres_printnamelen(ndo, s);
490				s += advance;
491			}
492			break;
493		case LWRES_OPCODE_GETRDATABYNAME:
494			/* XXX no trace, not tested */
495			grbn = (const lwres_grbnresponse_t *)p;
496			ND_TCHECK_2(grbn->nsigs);
497
498			/* BIND910: not used */
499			if (ndo->ndo_vflag > 2) {
500				ND_PRINT(" flags:0x%x",
501				    GET_BE_U_4(grbn->flags));
502			}
503
504			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
505			    GET_BE_U_2(grbn->rdtype)));
506			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
507				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
508				    GET_BE_U_2(grbn->rdclass)));
509			}
510			ND_PRINT(" TTL ");
511			unsigned_relts_print(ndo,
512					     GET_BE_U_4(grbn->ttl));
513			ND_PRINT(" %u/%u", GET_BE_U_2(grbn->nrdatas),
514				  GET_BE_U_2(grbn->nsigs));
515
516			s = p + LWRES_GRBNRESPONSE_LEN;
517			advance = lwres_printnamelen(ndo, s);
518			s += advance;
519
520			/* rdatas */
521			na = GET_BE_U_2(grbn->nrdatas);
522			for (i = 0; i < na; i++) {
523				/* XXX should decode resource data */
524				advance = lwres_printbinlen(ndo, s);
525				s += advance;
526			}
527
528			/* sigs */
529			na = GET_BE_U_2(grbn->nsigs);
530			for (i = 0; i < na; i++) {
531				/* XXX how should we print it? */
532				advance = lwres_printbinlen(ndo, s);
533				s += advance;
534			}
535			break;
536		default:
537			s = p;
538			unsupported++;
539			break;
540		}
541	}
542
543  tail:
544	/* length mismatch */
545	if (GET_BE_U_4(np->length) != length) {
546		ND_PRINT(" [len: %u != %u]", GET_BE_U_4(np->length),
547			  length);
548	}
549	if (!unsupported && ND_BYTES_BETWEEN(s, bp) < GET_BE_U_4(np->length))
550		ND_PRINT("[extra]");
551	return;
552
553  invalid:
554	nd_print_invalid(ndo);
555}
556