xref: /netbsd-src/external/bsd/tcpdump/dist/print-lwres.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (C) 2001 WIDE Project.
30f74e101Schristos  * All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that the following conditions
70f74e101Schristos  * are met:
80f74e101Schristos  * 1. Redistributions of source code must retain the above copyright
90f74e101Schristos  *    notice, this list of conditions and the following disclaimer.
100f74e101Schristos  * 2. Redistributions in binary form must reproduce the above copyright
110f74e101Schristos  *    notice, this list of conditions and the following disclaimer in the
120f74e101Schristos  *    documentation and/or other materials provided with the distribution.
130f74e101Schristos  * 3. Neither the name of the project nor the names of its contributors
140f74e101Schristos  *    may be used to endorse or promote products derived from this software
150f74e101Schristos  *    without specific prior written permission.
160f74e101Schristos  *
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
180f74e101Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190f74e101Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200f74e101Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
210f74e101Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220f74e101Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230f74e101Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240f74e101Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250f74e101Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260f74e101Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270f74e101Schristos  * SUCH DAMAGE.
280f74e101Schristos  */
290f74e101Schristos 
3011b3aaa1Schristos #include <sys/cdefs.h>
310f74e101Schristos #ifndef lint
32*26ba0b50Schristos __RCSID("$NetBSD: print-lwres.c,v 1.9 2024/09/02 16:15:32 christos Exp $");
330f74e101Schristos #endif
340f74e101Schristos 
35dc860a36Sspz /* \summary: BIND9 Lightweight Resolver protocol printer */
36dc860a36Sspz 
37c74ad251Schristos #include <config.h>
380f74e101Schristos 
39c74ad251Schristos #include "netdissect-stdinc.h"
400f74e101Schristos 
41c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK
42fdccd7e4Schristos #include "netdissect.h"
430f74e101Schristos #include "addrtoname.h"
44fdccd7e4Schristos #include "extract.h"
450f74e101Schristos 
46c74ad251Schristos #include "nameser.h"
47c74ad251Schristos 
480f74e101Schristos /* BIND9 lib/lwres/include/lwres */
49c74ad251Schristos /*
50c74ad251Schristos  * Use nd_uint16_t for lwres_uint16_t
51c74ad251Schristos  * Use nd_uint32_t for lwres_uint32_t
52c74ad251Schristos */
530f74e101Schristos 
540f74e101Schristos struct lwres_lwpacket {
55c74ad251Schristos 	nd_uint32_t		length;
56c74ad251Schristos 	nd_uint16_t		version;
57c74ad251Schristos 	nd_uint16_t		pktflags;
58c74ad251Schristos 	nd_uint32_t		serial;
59c74ad251Schristos 	nd_uint32_t		opcode;
60c74ad251Schristos 	nd_uint32_t		result;
61c74ad251Schristos 	nd_uint32_t		recvlength;
62c74ad251Schristos 	nd_uint16_t		authtype;
63c74ad251Schristos 	nd_uint16_t		authlength;
640f74e101Schristos };
650f74e101Schristos 
660f74e101Schristos #define LWRES_LWPACKETFLAG_RESPONSE	0x0001U	/* if set, pkt is a response */
670f74e101Schristos 
680f74e101Schristos #define LWRES_LWPACKETVERSION_0		0
690f74e101Schristos 
700f74e101Schristos #define LWRES_FLAG_TRUSTNOTREQUIRED	0x00000001U
710f74e101Schristos #define LWRES_FLAG_SECUREDATA		0x00000002U
720f74e101Schristos 
730f74e101Schristos /*
740f74e101Schristos  * no-op
750f74e101Schristos  */
760f74e101Schristos #define LWRES_OPCODE_NOOP		0x00000000U
770f74e101Schristos 
780f74e101Schristos typedef struct {
790f74e101Schristos 	/* public */
80c74ad251Schristos 	nd_uint16_t			datalength;
810f74e101Schristos 	/* data follows */
820f74e101Schristos } lwres_nooprequest_t;
830f74e101Schristos 
840f74e101Schristos typedef struct {
850f74e101Schristos 	/* public */
86c74ad251Schristos 	nd_uint16_t			datalength;
870f74e101Schristos 	/* data follows */
880f74e101Schristos } lwres_noopresponse_t;
890f74e101Schristos 
900f74e101Schristos /*
910f74e101Schristos  * get addresses by name
920f74e101Schristos  */
930f74e101Schristos #define LWRES_OPCODE_GETADDRSBYNAME	0x00010001U
940f74e101Schristos 
950f74e101Schristos typedef struct lwres_addr lwres_addr_t;
960f74e101Schristos 
970f74e101Schristos struct lwres_addr {
98c74ad251Schristos 	nd_uint32_t			family;
99c74ad251Schristos 	nd_uint16_t			length;
100c74ad251Schristos 	/* address follows */
1010f74e101Schristos };
102c74ad251Schristos #define LWRES_ADDR_LEN			6
1030f74e101Schristos 
1040f74e101Schristos typedef struct {
1050f74e101Schristos 	/* public */
106c74ad251Schristos 	nd_uint32_t			flags;
107c74ad251Schristos 	nd_uint32_t			addrtypes;
108c74ad251Schristos 	nd_uint16_t			namelen;
1090f74e101Schristos 	/* name follows */
1100f74e101Schristos } lwres_gabnrequest_t;
111c74ad251Schristos #define LWRES_GABNREQUEST_LEN		10
1120f74e101Schristos 
1130f74e101Schristos typedef struct {
1140f74e101Schristos 	/* public */
115c74ad251Schristos 	nd_uint32_t			flags;
116c74ad251Schristos 	nd_uint16_t			naliases;
117c74ad251Schristos 	nd_uint16_t			naddrs;
118c74ad251Schristos 	nd_uint16_t			realnamelen;
1190f74e101Schristos 	/* aliases follows */
1200f74e101Schristos 	/* addrs follows */
1210f74e101Schristos 	/* realname follows */
1220f74e101Schristos } lwres_gabnresponse_t;
123c74ad251Schristos #define LWRES_GABNRESPONSE_LEN		10
1240f74e101Schristos 
1250f74e101Schristos /*
1260f74e101Schristos  * get name by address
1270f74e101Schristos  */
1280f74e101Schristos #define LWRES_OPCODE_GETNAMEBYADDR	0x00010002U
1290f74e101Schristos typedef struct {
1300f74e101Schristos 	/* public */
131c74ad251Schristos 	nd_uint32_t			flags;
132c74ad251Schristos 	/* addr follows */
1330f74e101Schristos } lwres_gnbarequest_t;
134c74ad251Schristos #define LWRES_GNBAREQUEST_LEN		4
1350f74e101Schristos 
1360f74e101Schristos typedef struct {
1370f74e101Schristos 	/* public */
138c74ad251Schristos 	nd_uint32_t			flags;
139c74ad251Schristos 	nd_uint16_t			naliases;
140c74ad251Schristos 	nd_uint16_t			realnamelen;
1410f74e101Schristos 	/* aliases follows */
1420f74e101Schristos 	/* realname follows */
1430f74e101Schristos } lwres_gnbaresponse_t;
144c74ad251Schristos #define LWRES_GNBARESPONSE_LEN		8
1450f74e101Schristos 
1460f74e101Schristos /*
1470f74e101Schristos  * get rdata by name
1480f74e101Schristos  */
1490f74e101Schristos #define LWRES_OPCODE_GETRDATABYNAME	0x00010003U
1500f74e101Schristos 
1510f74e101Schristos typedef struct {
1520f74e101Schristos 	/* public */
153c74ad251Schristos 	nd_uint32_t			flags;
154c74ad251Schristos 	nd_uint16_t			rdclass;
155c74ad251Schristos 	nd_uint16_t			rdtype;
156c74ad251Schristos 	nd_uint16_t			namelen;
1570f74e101Schristos 	/* name follows */
1580f74e101Schristos } lwres_grbnrequest_t;
159c74ad251Schristos #define LWRES_GRBNREQUEST_LEN		10
1600f74e101Schristos 
1610f74e101Schristos typedef struct {
1620f74e101Schristos 	/* public */
163c74ad251Schristos 	nd_uint32_t			flags;
164c74ad251Schristos 	nd_uint16_t			rdclass;
165c74ad251Schristos 	nd_uint16_t			rdtype;
166c74ad251Schristos 	nd_uint32_t			ttl;
167c74ad251Schristos 	nd_uint16_t			nrdatas;
168c74ad251Schristos 	nd_uint16_t			nsigs;
1690f74e101Schristos 	/* realname here (len + name) */
1700f74e101Schristos 	/* rdata here (len + name) */
1710f74e101Schristos 	/* signatures here (len + name) */
1720f74e101Schristos } lwres_grbnresponse_t;
173c74ad251Schristos #define LWRES_GRBNRESPONSE_LEN		16
1740f74e101Schristos 
1750f74e101Schristos #define LWRDATA_VALIDATED	0x00000001
1760f74e101Schristos 
1770f74e101Schristos #define LWRES_ADDRTYPE_V4		0x00000001U	/* ipv4 */
1780f74e101Schristos #define LWRES_ADDRTYPE_V6		0x00000002U	/* ipv6 */
1790f74e101Schristos 
1800f74e101Schristos #define LWRES_MAX_ALIASES		16		/* max # of aliases */
1810f74e101Schristos #define LWRES_MAX_ADDRS			64		/* max # of addrs */
1820f74e101Schristos 
183870189d2Schristos static const struct tok opcode[] = {
1840f74e101Schristos 	{ LWRES_OPCODE_NOOP,		"noop", },
1850f74e101Schristos 	{ LWRES_OPCODE_GETADDRSBYNAME,	"getaddrsbyname", },
1860f74e101Schristos 	{ LWRES_OPCODE_GETNAMEBYADDR,	"getnamebyaddr", },
1870f74e101Schristos 	{ LWRES_OPCODE_GETRDATABYNAME,	"getrdatabyname", },
1880f74e101Schristos 	{ 0,				NULL, },
1890f74e101Schristos };
1900f74e101Schristos 
1910f74e101Schristos /* print-domain.c */
192870189d2Schristos extern const struct tok ns_type2str[];
193870189d2Schristos extern const struct tok ns_class2str[];
1940f74e101Schristos 
195c74ad251Schristos static unsigned
196b3a00663Schristos lwres_printname(netdissect_options *ndo,
197c74ad251Schristos                 u_int l, const u_char *p0)
1980f74e101Schristos {
199c74ad251Schristos 	ND_PRINT(" ");
200c74ad251Schristos 	(void)nd_printn(ndo, p0, l, NULL);
201c74ad251Schristos 	p0 += l;
202c74ad251Schristos 	if (GET_U_1(p0))
203c74ad251Schristos 		ND_PRINT(" (not NUL-terminated!)");
204c74ad251Schristos 	return l + 1;
2050f74e101Schristos }
2060f74e101Schristos 
207c74ad251Schristos static unsigned
208b3a00663Schristos lwres_printnamelen(netdissect_options *ndo,
209c74ad251Schristos                    const u_char *p)
2100f74e101Schristos {
211b3a00663Schristos 	uint16_t l;
2120f74e101Schristos 	int advance;
2130f74e101Schristos 
214c74ad251Schristos 	l = GET_BE_U_2(p);
215b3a00663Schristos 	advance = lwres_printname(ndo, l, p + 2);
2160f74e101Schristos 	return 2 + advance;
2170f74e101Schristos }
2180f74e101Schristos 
219c74ad251Schristos static unsigned
220b3a00663Schristos lwres_printbinlen(netdissect_options *ndo,
221c74ad251Schristos                   const u_char *p0)
2220f74e101Schristos {
223c74ad251Schristos 	const u_char *p;
224b3a00663Schristos 	uint16_t l;
2250f74e101Schristos 	int i;
2260f74e101Schristos 
2270f74e101Schristos 	p = p0;
228c74ad251Schristos 	l = GET_BE_U_2(p);
2290f74e101Schristos 	p += 2;
230c74ad251Schristos 	for (i = 0; i < l; i++) {
231c74ad251Schristos 		ND_PRINT("%02x", GET_U_1(p));
232c74ad251Schristos 		p++;
233c74ad251Schristos 	}
234c74ad251Schristos 	return 2 + l;
2350f74e101Schristos }
2360f74e101Schristos 
2370f74e101Schristos static int
238b3a00663Schristos lwres_printaddr(netdissect_options *ndo,
239c74ad251Schristos                 const u_char *p0)
2400f74e101Schristos {
241c74ad251Schristos 	const u_char *p;
242c74ad251Schristos 	const lwres_addr_t *ap;
243b3a00663Schristos 	uint16_t l;
2440f74e101Schristos 	int i;
2450f74e101Schristos 
246c74ad251Schristos 	p = p0;
247c74ad251Schristos 	ap = (const lwres_addr_t *)p;
248c74ad251Schristos 	l = GET_BE_U_2(ap->length);
249c74ad251Schristos 	p += LWRES_ADDR_LEN;
250c74ad251Schristos 	ND_TCHECK_LEN(p, l);
2510f74e101Schristos 
252c74ad251Schristos 	switch (GET_BE_U_4(ap->family)) {
2530f74e101Schristos 	case 1:	/* IPv4 */
2540f74e101Schristos 		if (l < 4)
2550f74e101Schristos 			return -1;
256c74ad251Schristos 		ND_PRINT(" %s", GET_IPADDR_STRING(p));
257c74ad251Schristos 		p += sizeof(nd_ipv4);
2580f74e101Schristos 		break;
2590f74e101Schristos 	case 2:	/* IPv6 */
2600f74e101Schristos 		if (l < 16)
2610f74e101Schristos 			return -1;
262c74ad251Schristos 		ND_PRINT(" %s", GET_IP6ADDR_STRING(p));
263c74ad251Schristos 		p += sizeof(nd_ipv6);
2640f74e101Schristos 		break;
2650f74e101Schristos 	default:
266c74ad251Schristos 		ND_PRINT(" %u/", GET_BE_U_4(ap->family));
267c74ad251Schristos 		for (i = 0; i < l; i++) {
268c74ad251Schristos 			ND_PRINT("%02x", GET_U_1(p));
269c74ad251Schristos 			p++;
270c74ad251Schristos 		}
2710f74e101Schristos 	}
2720f74e101Schristos 
273*26ba0b50Schristos 	return ND_BYTES_BETWEEN(p0, p);
2740f74e101Schristos }
2750f74e101Schristos 
2760f74e101Schristos void
277b3a00663Schristos lwres_print(netdissect_options *ndo,
278c74ad251Schristos             const u_char *bp, u_int length)
2790f74e101Schristos {
280c74ad251Schristos 	const u_char *p;
2810f74e101Schristos 	const struct lwres_lwpacket *np;
282b3a00663Schristos 	uint32_t v;
283c74ad251Schristos 	const u_char *s;
2840f74e101Schristos 	int response;
2850f74e101Schristos 	int advance;
2860f74e101Schristos 	int unsupported = 0;
2870f74e101Schristos 
288c74ad251Schristos 	ndo->ndo_protocol = "lwres";
2890f74e101Schristos 	np = (const struct lwres_lwpacket *)bp;
290c74ad251Schristos 	ND_TCHECK_2(np->authlength);
2910f74e101Schristos 
292c74ad251Schristos 	ND_PRINT(" lwres");
293c74ad251Schristos 	v = GET_BE_U_2(np->version);
294b3a00663Schristos 	if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0)
295c74ad251Schristos 		ND_PRINT(" v%u", v);
2960f74e101Schristos 	if (v != LWRES_LWPACKETVERSION_0) {
297*26ba0b50Schristos 		uint32_t pkt_len = GET_BE_U_4(np->length);
298*26ba0b50Schristos 		ND_TCHECK_LEN(bp, pkt_len);
299*26ba0b50Schristos 		s = bp + pkt_len;
3000f74e101Schristos 		goto tail;
3010f74e101Schristos 	}
3020f74e101Schristos 
303c74ad251Schristos 	response = GET_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE;
3040f74e101Schristos 
3050f74e101Schristos 	/* opcode and pktflags */
306c74ad251Schristos 	v = GET_BE_U_4(np->opcode);
307c74ad251Schristos 	ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?");
3080f74e101Schristos 
3090f74e101Schristos 	/* pktflags */
310c74ad251Schristos 	v = GET_BE_U_2(np->pktflags);
3110f74e101Schristos 	if (v & ~LWRES_LWPACKETFLAG_RESPONSE)
312c74ad251Schristos 		ND_PRINT("[0x%x]", v);
3130f74e101Schristos 
314b3a00663Schristos 	if (ndo->ndo_vflag > 1) {
315c74ad251Schristos 		ND_PRINT(" (");	/*)*/
316c74ad251Schristos 		ND_PRINT("serial:0x%x", GET_BE_U_4(np->serial));
317c74ad251Schristos 		ND_PRINT(" result:0x%x", GET_BE_U_4(np->result));
318c74ad251Schristos 		ND_PRINT(" recvlen:%u", GET_BE_U_4(np->recvlength));
3190f74e101Schristos 		/* BIND910: not used */
320b3a00663Schristos 		if (ndo->ndo_vflag > 2) {
321c74ad251Schristos 			ND_PRINT(" authtype:0x%x", GET_BE_U_2(np->authtype));
322c74ad251Schristos 			ND_PRINT(" authlen:%u", GET_BE_U_2(np->authlength));
3230f74e101Schristos 		}
3240f74e101Schristos 		/*(*/
325c74ad251Schristos 		ND_PRINT(")");
3260f74e101Schristos 	}
3270f74e101Schristos 
3280f74e101Schristos 	/* per-opcode content */
3290f74e101Schristos 	if (!response) {
3300f74e101Schristos 		/*
3310f74e101Schristos 		 * queries
3320f74e101Schristos 		 */
333fdccd7e4Schristos 		const lwres_gabnrequest_t *gabn;
334fdccd7e4Schristos 		const lwres_gnbarequest_t *gnba;
335fdccd7e4Schristos 		const lwres_grbnrequest_t *grbn;
336b3a00663Schristos 		uint32_t l;
3370f74e101Schristos 
3380f74e101Schristos 		gabn = NULL;
3390f74e101Schristos 		gnba = NULL;
3400f74e101Schristos 		grbn = NULL;
3410f74e101Schristos 
342c74ad251Schristos 		p = (const u_char *)(np + 1);
343c74ad251Schristos 		switch (GET_BE_U_4(np->opcode)) {
3440f74e101Schristos 		case LWRES_OPCODE_NOOP:
345c74ad251Schristos 			s = p;
3460f74e101Schristos 			break;
3470f74e101Schristos 		case LWRES_OPCODE_GETADDRSBYNAME:
348c74ad251Schristos 			gabn = (const lwres_gabnrequest_t *)p;
349c74ad251Schristos 			ND_TCHECK_2(gabn->namelen);
3500f74e101Schristos 
3510f74e101Schristos 			/* BIND910: not used */
352b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
353c74ad251Schristos 				ND_PRINT(" flags:0x%x",
354c74ad251Schristos 				    GET_BE_U_4(gabn->flags));
3550f74e101Schristos 			}
3560f74e101Schristos 
357c74ad251Schristos 			v = GET_BE_U_4(gabn->addrtypes);
3580f74e101Schristos 			switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) {
3590f74e101Schristos 			case LWRES_ADDRTYPE_V4:
360c74ad251Schristos 				ND_PRINT(" IPv4");
3610f74e101Schristos 				break;
3620f74e101Schristos 			case LWRES_ADDRTYPE_V6:
363c74ad251Schristos 				ND_PRINT(" IPv6");
3640f74e101Schristos 				break;
3650f74e101Schristos 			case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6:
366c74ad251Schristos 				ND_PRINT(" IPv4/6");
3670f74e101Schristos 				break;
3680f74e101Schristos 			}
3690f74e101Schristos 			if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6))
370c74ad251Schristos 				ND_PRINT("[0x%x]", v);
3710f74e101Schristos 
372c74ad251Schristos 			s = p + LWRES_GABNREQUEST_LEN;
373c74ad251Schristos 			l = GET_BE_U_2(gabn->namelen);
374b3a00663Schristos 			advance = lwres_printname(ndo, l, s);
3750f74e101Schristos 			s += advance;
3760f74e101Schristos 			break;
3770f74e101Schristos 		case LWRES_OPCODE_GETNAMEBYADDR:
378c74ad251Schristos 			gnba = (const lwres_gnbarequest_t *)p;
379c74ad251Schristos 			ND_TCHECK_4(gnba->flags);
3800f74e101Schristos 
3810f74e101Schristos 			/* BIND910: not used */
382b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
383c74ad251Schristos 				ND_PRINT(" flags:0x%x",
384c74ad251Schristos 				    GET_BE_U_4(gnba->flags));
3850f74e101Schristos 			}
3860f74e101Schristos 
387c74ad251Schristos 			s = p + LWRES_GNBAREQUEST_LEN;
388c74ad251Schristos 			advance = lwres_printaddr(ndo, s);
3890f74e101Schristos 			if (advance < 0)
390c74ad251Schristos 				goto invalid;
3910f74e101Schristos 			s += advance;
3920f74e101Schristos 			break;
3930f74e101Schristos 		case LWRES_OPCODE_GETRDATABYNAME:
3940f74e101Schristos 			/* XXX no trace, not tested */
395c74ad251Schristos 			grbn = (const lwres_grbnrequest_t *)p;
396c74ad251Schristos 			ND_TCHECK_2(grbn->namelen);
3970f74e101Schristos 
3980f74e101Schristos 			/* BIND910: not used */
399b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
400c74ad251Schristos 				ND_PRINT(" flags:0x%x",
401c74ad251Schristos 				    GET_BE_U_4(grbn->flags));
4020f74e101Schristos 			}
4030f74e101Schristos 
404c74ad251Schristos 			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
405c74ad251Schristos 			    GET_BE_U_2(grbn->rdtype)));
406c74ad251Schristos 			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
407c74ad251Schristos 				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
408c74ad251Schristos 				    GET_BE_U_2(grbn->rdclass)));
4090f74e101Schristos 			}
4100f74e101Schristos 
411c74ad251Schristos 			s = p + LWRES_GRBNREQUEST_LEN;
412c74ad251Schristos 			l = GET_BE_U_2(grbn->namelen);
413b3a00663Schristos 			advance = lwres_printname(ndo, l, s);
4140f74e101Schristos 			s += advance;
4150f74e101Schristos 			break;
4160f74e101Schristos 		default:
417c74ad251Schristos 			s = p;
4180f74e101Schristos 			unsupported++;
4190f74e101Schristos 			break;
4200f74e101Schristos 		}
4210f74e101Schristos 	} else {
4220f74e101Schristos 		/*
4230f74e101Schristos 		 * responses
4240f74e101Schristos 		 */
425fdccd7e4Schristos 		const lwres_gabnresponse_t *gabn;
426fdccd7e4Schristos 		const lwres_gnbaresponse_t *gnba;
427fdccd7e4Schristos 		const lwres_grbnresponse_t *grbn;
428b3a00663Schristos 		uint32_t l, na;
429b3a00663Schristos 		uint32_t i;
4300f74e101Schristos 
4310f74e101Schristos 		gabn = NULL;
4320f74e101Schristos 		gnba = NULL;
4330f74e101Schristos 		grbn = NULL;
4340f74e101Schristos 
435c74ad251Schristos 		p = (const u_char *)(np + 1);
436c74ad251Schristos 		switch (GET_BE_U_4(np->opcode)) {
4370f74e101Schristos 		case LWRES_OPCODE_NOOP:
438c74ad251Schristos 			s = p;
4390f74e101Schristos 			break;
4400f74e101Schristos 		case LWRES_OPCODE_GETADDRSBYNAME:
441c74ad251Schristos 			gabn = (const lwres_gabnresponse_t *)p;
442c74ad251Schristos 			ND_TCHECK_2(gabn->realnamelen);
4430f74e101Schristos 
4440f74e101Schristos 			/* BIND910: not used */
445b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
446c74ad251Schristos 				ND_PRINT(" flags:0x%x",
447c74ad251Schristos 				    GET_BE_U_4(gabn->flags));
4480f74e101Schristos 			}
4490f74e101Schristos 
450c74ad251Schristos 			ND_PRINT(" %u/%u", GET_BE_U_2(gabn->naliases),
451c74ad251Schristos 				  GET_BE_U_2(gabn->naddrs));
4520f74e101Schristos 
453c74ad251Schristos 			s = p + LWRES_GABNRESPONSE_LEN;
454c74ad251Schristos 			l = GET_BE_U_2(gabn->realnamelen);
455b3a00663Schristos 			advance = lwres_printname(ndo, l, s);
4560f74e101Schristos 			s += advance;
4570f74e101Schristos 
4580f74e101Schristos 			/* aliases */
459c74ad251Schristos 			na = GET_BE_U_2(gabn->naliases);
4600f74e101Schristos 			for (i = 0; i < na; i++) {
461b3a00663Schristos 				advance = lwres_printnamelen(ndo, s);
4620f74e101Schristos 				s += advance;
4630f74e101Schristos 			}
4640f74e101Schristos 
4650f74e101Schristos 			/* addrs */
466c74ad251Schristos 			na = GET_BE_U_2(gabn->naddrs);
4670f74e101Schristos 			for (i = 0; i < na; i++) {
468c74ad251Schristos 				advance = lwres_printaddr(ndo, s);
4690f74e101Schristos 				if (advance < 0)
470c74ad251Schristos 					goto invalid;
4710f74e101Schristos 				s += advance;
4720f74e101Schristos 			}
4730f74e101Schristos 			break;
4740f74e101Schristos 		case LWRES_OPCODE_GETNAMEBYADDR:
475c74ad251Schristos 			gnba = (const lwres_gnbaresponse_t *)p;
476c74ad251Schristos 			ND_TCHECK_2(gnba->realnamelen);
4770f74e101Schristos 
4780f74e101Schristos 			/* BIND910: not used */
479b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
480c74ad251Schristos 				ND_PRINT(" flags:0x%x",
481c74ad251Schristos 				    GET_BE_U_4(gnba->flags));
4820f74e101Schristos 			}
4830f74e101Schristos 
484c74ad251Schristos 			ND_PRINT(" %u", GET_BE_U_2(gnba->naliases));
4850f74e101Schristos 
486c74ad251Schristos 			s = p + LWRES_GNBARESPONSE_LEN;
487c74ad251Schristos 			l = GET_BE_U_2(gnba->realnamelen);
488b3a00663Schristos 			advance = lwres_printname(ndo, l, s);
4890f74e101Schristos 			s += advance;
4900f74e101Schristos 
4910f74e101Schristos 			/* aliases */
492c74ad251Schristos 			na = GET_BE_U_2(gnba->naliases);
4930f74e101Schristos 			for (i = 0; i < na; i++) {
494b3a00663Schristos 				advance = lwres_printnamelen(ndo, s);
4950f74e101Schristos 				s += advance;
4960f74e101Schristos 			}
4970f74e101Schristos 			break;
4980f74e101Schristos 		case LWRES_OPCODE_GETRDATABYNAME:
4990f74e101Schristos 			/* XXX no trace, not tested */
500c74ad251Schristos 			grbn = (const lwres_grbnresponse_t *)p;
501c74ad251Schristos 			ND_TCHECK_2(grbn->nsigs);
5020f74e101Schristos 
5030f74e101Schristos 			/* BIND910: not used */
504b3a00663Schristos 			if (ndo->ndo_vflag > 2) {
505c74ad251Schristos 				ND_PRINT(" flags:0x%x",
506c74ad251Schristos 				    GET_BE_U_4(grbn->flags));
5070f74e101Schristos 			}
5080f74e101Schristos 
509c74ad251Schristos 			ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
510c74ad251Schristos 			    GET_BE_U_2(grbn->rdtype)));
511c74ad251Schristos 			if (GET_BE_U_2(grbn->rdclass) != C_IN) {
512c74ad251Schristos 				ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
513c74ad251Schristos 				    GET_BE_U_2(grbn->rdclass)));
5140f74e101Schristos 			}
515c74ad251Schristos 			ND_PRINT(" TTL ");
516c74ad251Schristos 			unsigned_relts_print(ndo,
517c74ad251Schristos 					     GET_BE_U_4(grbn->ttl));
518c74ad251Schristos 			ND_PRINT(" %u/%u", GET_BE_U_2(grbn->nrdatas),
519c74ad251Schristos 				  GET_BE_U_2(grbn->nsigs));
5200f74e101Schristos 
521c74ad251Schristos 			s = p + LWRES_GRBNRESPONSE_LEN;
522b3a00663Schristos 			advance = lwres_printnamelen(ndo, s);
5230f74e101Schristos 			s += advance;
5240f74e101Schristos 
5250f74e101Schristos 			/* rdatas */
526c74ad251Schristos 			na = GET_BE_U_2(grbn->nrdatas);
5270f74e101Schristos 			for (i = 0; i < na; i++) {
5280f74e101Schristos 				/* XXX should decode resource data */
529b3a00663Schristos 				advance = lwres_printbinlen(ndo, s);
5300f74e101Schristos 				s += advance;
5310f74e101Schristos 			}
5320f74e101Schristos 
5330f74e101Schristos 			/* sigs */
534c74ad251Schristos 			na = GET_BE_U_2(grbn->nsigs);
5350f74e101Schristos 			for (i = 0; i < na; i++) {
5360f74e101Schristos 				/* XXX how should we print it? */
537b3a00663Schristos 				advance = lwres_printbinlen(ndo, s);
5380f74e101Schristos 				s += advance;
5390f74e101Schristos 			}
5400f74e101Schristos 			break;
5410f74e101Schristos 		default:
542c74ad251Schristos 			s = p;
5430f74e101Schristos 			unsupported++;
5440f74e101Schristos 			break;
5450f74e101Schristos 		}
5460f74e101Schristos 	}
5470f74e101Schristos 
5480f74e101Schristos   tail:
5490f74e101Schristos 	/* length mismatch */
550c74ad251Schristos 	if (GET_BE_U_4(np->length) != length) {
551c74ad251Schristos 		ND_PRINT(" [len: %u != %u]", GET_BE_U_4(np->length),
552c74ad251Schristos 			  length);
5530f74e101Schristos 	}
554*26ba0b50Schristos 	if (!unsupported && ND_BYTES_BETWEEN(bp, s) < GET_BE_U_4(np->length))
555c74ad251Schristos 		ND_PRINT("[extra]");
5560f74e101Schristos 	return;
5570f74e101Schristos 
558c74ad251Schristos   invalid:
559c74ad251Schristos 	nd_print_invalid(ndo);
5600f74e101Schristos }
561