1*e6e30c83Schristos /*	$NetBSD: ns_print.c,v 1.1.1.2 2012/09/09 16:08:03 christos Exp $	*/
2b5677b36Schristos 
3b5677b36Schristos /*
4b5677b36Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos  * Copyright (c) 1996-1999 by Internet Software Consortium.
6b5677b36Schristos  *
7b5677b36Schristos  * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos  * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos  * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos  *
11b5677b36Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos  */
19b5677b36Schristos 
20b5677b36Schristos #ifndef lint
21b5677b36Schristos static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp ";
22b5677b36Schristos #endif
23b5677b36Schristos 
24b5677b36Schristos /* Import. */
25b5677b36Schristos 
26b5677b36Schristos #include "port_before.h"
27b5677b36Schristos 
28b5677b36Schristos #include <sys/types.h>
29b5677b36Schristos #include <sys/socket.h>
30b5677b36Schristos 
31b5677b36Schristos #include <netinet/in.h>
32b5677b36Schristos #include <arpa/nameser.h>
33b5677b36Schristos #include <arpa/inet.h>
34b5677b36Schristos 
35b5677b36Schristos #include <isc/assertions.h>
36b5677b36Schristos #include <isc/dst.h>
37b5677b36Schristos #include <errno.h>
38b5677b36Schristos #include <resolv.h>
39b5677b36Schristos #include <string.h>
40b5677b36Schristos #include <ctype.h>
41b5677b36Schristos 
42b5677b36Schristos #include "port_after.h"
43b5677b36Schristos 
44b5677b36Schristos #ifdef SPRINTF_CHAR
45b5677b36Schristos # define SPRINTF(x) strlen(sprintf/**/x)
46b5677b36Schristos #else
47b5677b36Schristos # define SPRINTF(x) ((size_t)sprintf x)
48b5677b36Schristos #endif
49b5677b36Schristos 
50b5677b36Schristos /* Forward. */
51b5677b36Schristos 
52b5677b36Schristos static size_t	prune_origin(const char *name, const char *origin);
53b5677b36Schristos static int	charstr(const u_char *rdata, const u_char *edata,
54b5677b36Schristos 			char **buf, size_t *buflen);
55b5677b36Schristos static int	addname(const u_char *msg, size_t msglen,
56b5677b36Schristos 			const u_char **p, const char *origin,
57b5677b36Schristos 			char **buf, size_t *buflen);
58b5677b36Schristos static void	addlen(size_t len, char **buf, size_t *buflen);
59b5677b36Schristos static int	addstr(const char *src, size_t len,
60b5677b36Schristos 		       char **buf, size_t *buflen);
61b5677b36Schristos static int	addtab(size_t len, size_t target, int spaced,
62b5677b36Schristos 		       char **buf, size_t *buflen);
63b5677b36Schristos 
64b5677b36Schristos /* Macros. */
65b5677b36Schristos 
66b5677b36Schristos #define	T(x) \
67b5677b36Schristos 	do { \
68b5677b36Schristos 		if ((x) < 0) \
69b5677b36Schristos 			return (-1); \
70b5677b36Schristos 	} while (0)
71b5677b36Schristos 
72b5677b36Schristos static const char base32hex[] =
73b5677b36Schristos         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
74b5677b36Schristos 
75b5677b36Schristos /* Public. */
76b5677b36Schristos 
77b5677b36Schristos /*%
78b5677b36Schristos  *	Convert an RR to presentation format.
79b5677b36Schristos  *
80b5677b36Schristos  * return:
81b5677b36Schristos  *\li	Number of characters written to buf, or -1 (check errno).
82b5677b36Schristos  */
83b5677b36Schristos int
ns_sprintrr(const ns_msg * handle,const ns_rr * rr,const char * name_ctx,const char * origin,char * buf,size_t buflen)84b5677b36Schristos ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
85b5677b36Schristos 	    const char *name_ctx, const char *origin,
86b5677b36Schristos 	    char *buf, size_t buflen)
87b5677b36Schristos {
88b5677b36Schristos 	int n;
89b5677b36Schristos 
90b5677b36Schristos 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
91b5677b36Schristos 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
92b5677b36Schristos 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
93b5677b36Schristos 			 name_ctx, origin, buf, buflen);
94b5677b36Schristos 	return (n);
95b5677b36Schristos }
96b5677b36Schristos 
97b5677b36Schristos /*%
98b5677b36Schristos  *	Convert the fields of an RR into presentation format.
99b5677b36Schristos  *
100b5677b36Schristos  * return:
101b5677b36Schristos  *\li	Number of characters written to buf, or -1 (check errno).
102b5677b36Schristos  */
103b5677b36Schristos int
ns_sprintrrf(const u_char * msg,size_t msglen,const char * name,ns_class class,ns_type type,u_long ttl,const u_char * rdata,size_t rdlen,const char * name_ctx,const char * origin,char * buf,size_t buflen)104b5677b36Schristos ns_sprintrrf(const u_char *msg, size_t msglen,
105b5677b36Schristos 	    const char *name, ns_class class, ns_type type,
106b5677b36Schristos 	    u_long ttl, const u_char *rdata, size_t rdlen,
107b5677b36Schristos 	    const char *name_ctx, const char *origin,
108b5677b36Schristos 	    char *buf, size_t buflen)
109b5677b36Schristos {
110b5677b36Schristos 	const char *obuf = buf;
111b5677b36Schristos 	const u_char *edata = rdata + rdlen;
112b5677b36Schristos 	int spaced = 0;
113b5677b36Schristos 
114b5677b36Schristos 	const char *comment;
115b5677b36Schristos 	char tmp[100];
116b5677b36Schristos 	int len, x;
117b5677b36Schristos 
118b5677b36Schristos 	/*
119b5677b36Schristos 	 * Owner.
120b5677b36Schristos 	 */
121b5677b36Schristos 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
122b5677b36Schristos 		T(addstr("\t\t\t", 3, &buf, &buflen));
123b5677b36Schristos 	} else {
124b5677b36Schristos 		len = prune_origin(name, origin);
125b5677b36Schristos 		if (*name == '\0') {
126b5677b36Schristos 			goto root;
127b5677b36Schristos 		} else if (len == 0) {
128b5677b36Schristos 			T(addstr("@\t\t\t", 4, &buf, &buflen));
129b5677b36Schristos 		} else {
130b5677b36Schristos 			T(addstr(name, len, &buf, &buflen));
131b5677b36Schristos 			/* Origin not used or not root, and no trailing dot? */
132b5677b36Schristos 			if (((origin == NULL || origin[0] == '\0') ||
133b5677b36Schristos 			    (origin[0] != '.' && origin[1] != '\0' &&
134b5677b36Schristos 			    name[len] == '\0')) && name[len - 1] != '.') {
135b5677b36Schristos  root:
136b5677b36Schristos 				T(addstr(".", 1, &buf, &buflen));
137b5677b36Schristos 				len++;
138b5677b36Schristos 			}
139b5677b36Schristos 			T(spaced = addtab(len, 24, spaced, &buf, &buflen));
140b5677b36Schristos 		}
141b5677b36Schristos 	}
142b5677b36Schristos 
143b5677b36Schristos 	/*
144b5677b36Schristos 	 * TTL, Class, Type.
145b5677b36Schristos 	 */
146b5677b36Schristos 	T(x = ns_format_ttl(ttl, buf, buflen));
147b5677b36Schristos 	addlen(x, &buf, &buflen);
148b5677b36Schristos 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
149b5677b36Schristos 	T(addstr(tmp, len, &buf, &buflen));
150b5677b36Schristos 	T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
151b5677b36Schristos 
152b5677b36Schristos 	/*
153b5677b36Schristos 	 * RData.
154b5677b36Schristos 	 */
155b5677b36Schristos 	switch (type) {
156b5677b36Schristos 	case ns_t_a:
157b5677b36Schristos 		if (rdlen != (size_t)NS_INADDRSZ)
158b5677b36Schristos 			goto formerr;
159b5677b36Schristos 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
160b5677b36Schristos 		addlen(strlen(buf), &buf, &buflen);
161b5677b36Schristos 		break;
162b5677b36Schristos 
163b5677b36Schristos 	case ns_t_cname:
164b5677b36Schristos 	case ns_t_mb:
165b5677b36Schristos 	case ns_t_mg:
166b5677b36Schristos 	case ns_t_mr:
167b5677b36Schristos 	case ns_t_ns:
168b5677b36Schristos 	case ns_t_ptr:
169b5677b36Schristos 	case ns_t_dname:
170b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
171b5677b36Schristos 		break;
172b5677b36Schristos 
173b5677b36Schristos 	case ns_t_hinfo:
174b5677b36Schristos 	case ns_t_isdn:
175b5677b36Schristos 		/* First word. */
176b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
177b5677b36Schristos 		if (len == 0)
178b5677b36Schristos 			goto formerr;
179b5677b36Schristos 		rdata += len;
180b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
181b5677b36Schristos 
182b5677b36Schristos 
183b5677b36Schristos 		/* Second word, optional in ISDN records. */
184b5677b36Schristos 		if (type == ns_t_isdn && rdata == edata)
185b5677b36Schristos 			break;
186b5677b36Schristos 
187b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
188b5677b36Schristos 		if (len == 0)
189b5677b36Schristos 			goto formerr;
190b5677b36Schristos 		rdata += len;
191b5677b36Schristos 		break;
192b5677b36Schristos 
193b5677b36Schristos 	case ns_t_soa: {
194b5677b36Schristos 		u_long t;
195b5677b36Schristos 
196b5677b36Schristos 		/* Server name. */
197b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
198b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
199b5677b36Schristos 
200b5677b36Schristos 		/* Administrator name. */
201b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
202b5677b36Schristos 		T(addstr(" (\n", 3, &buf, &buflen));
203b5677b36Schristos 		spaced = 0;
204b5677b36Schristos 
205b5677b36Schristos 		if ((edata - rdata) != 5*NS_INT32SZ)
206b5677b36Schristos 			goto formerr;
207b5677b36Schristos 
208b5677b36Schristos 		/* Serial number. */
209b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
210b5677b36Schristos 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
211b5677b36Schristos 		len = SPRINTF((tmp, "%lu", t));
212b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
213b5677b36Schristos 		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
214b5677b36Schristos 		T(addstr("; serial\n", 9, &buf, &buflen));
215b5677b36Schristos 		spaced = 0;
216b5677b36Schristos 
217b5677b36Schristos 		/* Refresh interval. */
218b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
219b5677b36Schristos 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
220b5677b36Schristos 		T(len = ns_format_ttl(t, buf, buflen));
221b5677b36Schristos 		addlen(len, &buf, &buflen);
222b5677b36Schristos 		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
223b5677b36Schristos 		T(addstr("; refresh\n", 10, &buf, &buflen));
224b5677b36Schristos 		spaced = 0;
225b5677b36Schristos 
226b5677b36Schristos 		/* Retry interval. */
227b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
228b5677b36Schristos 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
229b5677b36Schristos 		T(len = ns_format_ttl(t, buf, buflen));
230b5677b36Schristos 		addlen(len, &buf, &buflen);
231b5677b36Schristos 		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
232b5677b36Schristos 		T(addstr("; retry\n", 8, &buf, &buflen));
233b5677b36Schristos 		spaced = 0;
234b5677b36Schristos 
235b5677b36Schristos 		/* Expiry. */
236b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
237b5677b36Schristos 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
238b5677b36Schristos 		T(len = ns_format_ttl(t, buf, buflen));
239b5677b36Schristos 		addlen(len, &buf, &buflen);
240b5677b36Schristos 		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
241b5677b36Schristos 		T(addstr("; expiry\n", 9, &buf, &buflen));
242b5677b36Schristos 		spaced = 0;
243b5677b36Schristos 
244b5677b36Schristos 		/* Minimum TTL. */
245b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
246b5677b36Schristos 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
247b5677b36Schristos 		T(len = ns_format_ttl(t, buf, buflen));
248b5677b36Schristos 		addlen(len, &buf, &buflen);
249b5677b36Schristos 		T(addstr(" )", 2, &buf, &buflen));
250b5677b36Schristos 		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
251b5677b36Schristos 		T(addstr("; minimum\n", 10, &buf, &buflen));
252b5677b36Schristos 
253b5677b36Schristos 		break;
254b5677b36Schristos 	    }
255b5677b36Schristos 
256b5677b36Schristos 	case ns_t_mx:
257b5677b36Schristos 	case ns_t_afsdb:
258b5677b36Schristos 	case ns_t_rt:
259b5677b36Schristos 	case ns_t_kx: {
260b5677b36Schristos 		u_int t;
261b5677b36Schristos 
262b5677b36Schristos 		if (rdlen < (size_t)NS_INT16SZ)
263b5677b36Schristos 			goto formerr;
264b5677b36Schristos 
265b5677b36Schristos 		/* Priority. */
266b5677b36Schristos 		t = ns_get16(rdata);
267b5677b36Schristos 		rdata += NS_INT16SZ;
268b5677b36Schristos 		len = SPRINTF((tmp, "%u ", t));
269b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
270b5677b36Schristos 
271b5677b36Schristos 		/* Target. */
272b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
273b5677b36Schristos 
274b5677b36Schristos 		break;
275b5677b36Schristos 	    }
276b5677b36Schristos 
277b5677b36Schristos 	case ns_t_px: {
278b5677b36Schristos 		u_int t;
279b5677b36Schristos 
280b5677b36Schristos 		if (rdlen < (size_t)NS_INT16SZ)
281b5677b36Schristos 			goto formerr;
282b5677b36Schristos 
283b5677b36Schristos 		/* Priority. */
284b5677b36Schristos 		t = ns_get16(rdata);
285b5677b36Schristos 		rdata += NS_INT16SZ;
286b5677b36Schristos 		len = SPRINTF((tmp, "%u ", t));
287b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
288b5677b36Schristos 
289b5677b36Schristos 		/* Name1. */
290b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
291b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
292b5677b36Schristos 
293b5677b36Schristos 		/* Name2. */
294b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
295b5677b36Schristos 
296b5677b36Schristos 		break;
297b5677b36Schristos 	    }
298b5677b36Schristos 
299b5677b36Schristos 	case ns_t_x25:
300b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
301b5677b36Schristos 		if (len == 0)
302b5677b36Schristos 			goto formerr;
303b5677b36Schristos 		rdata += len;
304b5677b36Schristos 		break;
305b5677b36Schristos 
306b5677b36Schristos 	case ns_t_txt:
307b5677b36Schristos 	case ns_t_spf:
308b5677b36Schristos 		while (rdata < edata) {
309b5677b36Schristos 			T(len = charstr(rdata, edata, &buf, &buflen));
310b5677b36Schristos 			if (len == 0)
311b5677b36Schristos 				goto formerr;
312b5677b36Schristos 			rdata += len;
313b5677b36Schristos 			if (rdata < edata)
314b5677b36Schristos 				T(addstr(" ", 1, &buf, &buflen));
315b5677b36Schristos 		}
316b5677b36Schristos 		break;
317b5677b36Schristos 
318b5677b36Schristos 	case ns_t_nsap: {
319b5677b36Schristos 		char t[2+255*3];
320b5677b36Schristos 
321b5677b36Schristos 		(void) inet_nsap_ntoa(rdlen, rdata, t);
322b5677b36Schristos 		T(addstr(t, strlen(t), &buf, &buflen));
323b5677b36Schristos 		break;
324b5677b36Schristos 	    }
325b5677b36Schristos 
326b5677b36Schristos 	case ns_t_aaaa:
327b5677b36Schristos 		if (rdlen != (size_t)NS_IN6ADDRSZ)
328b5677b36Schristos 			goto formerr;
329b5677b36Schristos 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
330b5677b36Schristos 		addlen(strlen(buf), &buf, &buflen);
331b5677b36Schristos 		break;
332b5677b36Schristos 
333b5677b36Schristos 	case ns_t_loc: {
334b5677b36Schristos 		char t[255];
335b5677b36Schristos 
336b5677b36Schristos 		/* XXX protocol format checking? */
337b5677b36Schristos 		(void) loc_ntoa(rdata, t);
338b5677b36Schristos 		T(addstr(t, strlen(t), &buf, &buflen));
339b5677b36Schristos 		break;
340b5677b36Schristos 	    }
341b5677b36Schristos 
342b5677b36Schristos 	case ns_t_naptr: {
343b5677b36Schristos 		u_int order, preference;
344b5677b36Schristos 		char t[50];
345b5677b36Schristos 
346b5677b36Schristos 		if (rdlen < 2U*NS_INT16SZ)
347b5677b36Schristos 			goto formerr;
348b5677b36Schristos 
349b5677b36Schristos 		/* Order, Precedence. */
350b5677b36Schristos 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
351b5677b36Schristos 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
352b5677b36Schristos 		len = SPRINTF((t, "%u %u ", order, preference));
353b5677b36Schristos 		T(addstr(t, len, &buf, &buflen));
354b5677b36Schristos 
355b5677b36Schristos 		/* Flags. */
356b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
357b5677b36Schristos 		if (len == 0)
358b5677b36Schristos 			goto formerr;
359b5677b36Schristos 		rdata += len;
360b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
361b5677b36Schristos 
362b5677b36Schristos 		/* Service. */
363b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
364b5677b36Schristos 		if (len == 0)
365b5677b36Schristos 			goto formerr;
366b5677b36Schristos 		rdata += len;
367b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
368b5677b36Schristos 
369b5677b36Schristos 		/* Regexp. */
370b5677b36Schristos 		T(len = charstr(rdata, edata, &buf, &buflen));
371b5677b36Schristos 		if (len < 0)
372b5677b36Schristos 			return (-1);
373b5677b36Schristos 		if (len == 0)
374b5677b36Schristos 			goto formerr;
375b5677b36Schristos 		rdata += len;
376b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
377b5677b36Schristos 
378b5677b36Schristos 		/* Server. */
379b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
380b5677b36Schristos 		break;
381b5677b36Schristos 	    }
382b5677b36Schristos 
383b5677b36Schristos 	case ns_t_srv: {
384b5677b36Schristos 		u_int priority, weight, port;
385b5677b36Schristos 		char t[50];
386b5677b36Schristos 
387b5677b36Schristos 		if (rdlen < 3U*NS_INT16SZ)
388b5677b36Schristos 			goto formerr;
389b5677b36Schristos 
390b5677b36Schristos 		/* Priority, Weight, Port. */
391b5677b36Schristos 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
392b5677b36Schristos 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
393b5677b36Schristos 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
394b5677b36Schristos 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
395b5677b36Schristos 		T(addstr(t, len, &buf, &buflen));
396b5677b36Schristos 
397b5677b36Schristos 		/* Server. */
398b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
399b5677b36Schristos 		break;
400b5677b36Schristos 	    }
401b5677b36Schristos 
402b5677b36Schristos 	case ns_t_minfo:
403b5677b36Schristos 	case ns_t_rp:
404b5677b36Schristos 		/* Name1. */
405b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
406b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
407b5677b36Schristos 
408b5677b36Schristos 		/* Name2. */
409b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
410b5677b36Schristos 
411b5677b36Schristos 		break;
412b5677b36Schristos 
413b5677b36Schristos 	case ns_t_wks: {
414b5677b36Schristos 		int n, lcnt;
415b5677b36Schristos 
416b5677b36Schristos 		if (rdlen < 1U + NS_INT32SZ)
417b5677b36Schristos 			goto formerr;
418b5677b36Schristos 
419b5677b36Schristos 		/* Address. */
420b5677b36Schristos 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
421b5677b36Schristos 		addlen(strlen(buf), &buf, &buflen);
422b5677b36Schristos 		rdata += NS_INADDRSZ;
423b5677b36Schristos 
424b5677b36Schristos 		/* Protocol. */
425b5677b36Schristos 		len = SPRINTF((tmp, " %u ( ", *rdata));
426b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
427b5677b36Schristos 		rdata += NS_INT8SZ;
428b5677b36Schristos 
429b5677b36Schristos 		/* Bit map. */
430b5677b36Schristos 		n = 0;
431b5677b36Schristos 		lcnt = 0;
432b5677b36Schristos 		while (rdata < edata) {
433b5677b36Schristos 			u_int c = *rdata++;
434b5677b36Schristos 			do {
435b5677b36Schristos 				if (c & 0200) {
436b5677b36Schristos 					if (lcnt == 0) {
437b5677b36Schristos 						T(addstr("\n\t\t\t\t", 5,
438b5677b36Schristos 							 &buf, &buflen));
439b5677b36Schristos 						lcnt = 10;
440b5677b36Schristos 						spaced = 0;
441b5677b36Schristos 					}
442b5677b36Schristos 					len = SPRINTF((tmp, "%d ", n));
443b5677b36Schristos 					T(addstr(tmp, len, &buf, &buflen));
444b5677b36Schristos 					lcnt--;
445b5677b36Schristos 				}
446b5677b36Schristos 				c <<= 1;
447b5677b36Schristos 			} while (++n & 07);
448b5677b36Schristos 		}
449b5677b36Schristos 		T(addstr(")", 1, &buf, &buflen));
450b5677b36Schristos 
451b5677b36Schristos 		break;
452b5677b36Schristos 	    }
453b5677b36Schristos 
454b5677b36Schristos 	case ns_t_key:
455b5677b36Schristos 	case ns_t_dnskey: {
456b5677b36Schristos 		char base64_key[NS_MD5RSA_MAX_BASE64];
457b5677b36Schristos 		u_int keyflags, protocol, algorithm, key_id;
458b5677b36Schristos 		const char *leader;
459b5677b36Schristos 		int n;
460b5677b36Schristos 
461b5677b36Schristos 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
462b5677b36Schristos 			goto formerr;
463b5677b36Schristos 
464b5677b36Schristos 		/* Key flags, Protocol, Algorithm. */
465b5677b36Schristos 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
466b5677b36Schristos 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
467b5677b36Schristos 		protocol = *rdata++;
468b5677b36Schristos 		algorithm = *rdata++;
469b5677b36Schristos 		len = SPRINTF((tmp, "0x%04x %u %u",
470b5677b36Schristos 			       keyflags, protocol, algorithm));
471b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
472b5677b36Schristos 
473b5677b36Schristos 		/* Public key data. */
474b5677b36Schristos 		len = b64_ntop(rdata, edata - rdata,
475b5677b36Schristos 			       base64_key, sizeof base64_key);
476b5677b36Schristos 		if (len < 0)
477b5677b36Schristos 			goto formerr;
478b5677b36Schristos 		if (len > 15) {
479b5677b36Schristos 			T(addstr(" (", 2, &buf, &buflen));
480b5677b36Schristos 			leader = "\n\t\t";
481b5677b36Schristos 			spaced = 0;
482b5677b36Schristos 		} else
483b5677b36Schristos 			leader = " ";
484b5677b36Schristos 		for (n = 0; n < len; n += 48) {
485b5677b36Schristos 			T(addstr(leader, strlen(leader), &buf, &buflen));
486b5677b36Schristos 			T(addstr(base64_key + n, MIN(len - n, 48),
487b5677b36Schristos 				 &buf, &buflen));
488b5677b36Schristos 		}
489b5677b36Schristos 		if (len > 15)
490b5677b36Schristos 			T(addstr(" )", 2, &buf, &buflen));
491b5677b36Schristos 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
492b5677b36Schristos 		T(addstr(tmp, n, &buf, &buflen));
493b5677b36Schristos 
494b5677b36Schristos 		break;
495b5677b36Schristos 	    }
496b5677b36Schristos 
497b5677b36Schristos 	case ns_t_sig:
498b5677b36Schristos 	case ns_t_rrsig: {
499b5677b36Schristos 		char base64_key[NS_MD5RSA_MAX_BASE64];
500b5677b36Schristos 		u_int type, algorithm, labels, footprint;
501b5677b36Schristos 		const char *leader;
502b5677b36Schristos 		u_long t;
503b5677b36Schristos 		int n;
504b5677b36Schristos 
505b5677b36Schristos 		if (rdlen < 22U)
506b5677b36Schristos 			goto formerr;
507b5677b36Schristos 
508b5677b36Schristos 		/* Type covered, Algorithm, Label count, Original TTL. */
509b5677b36Schristos 		type = ns_get16(rdata);  rdata += NS_INT16SZ;
510b5677b36Schristos 		algorithm = *rdata++;
511b5677b36Schristos 		labels = *rdata++;
512b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
513b5677b36Schristos 		len = SPRINTF((tmp, "%s %d %d %lu ",
514b5677b36Schristos 			       p_type(type), algorithm, labels, t));
515b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
516b5677b36Schristos 		if (labels > (u_int)dn_count_labels(name))
517b5677b36Schristos 			goto formerr;
518b5677b36Schristos 
519b5677b36Schristos 		/* Signature expiry. */
520b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
521b5677b36Schristos 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
522b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
523b5677b36Schristos 
524b5677b36Schristos 		/* Time signed. */
525b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
526b5677b36Schristos 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
527b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
528b5677b36Schristos 
529b5677b36Schristos 		/* Signature Footprint. */
530b5677b36Schristos 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
531b5677b36Schristos 		len = SPRINTF((tmp, "%u ", footprint));
532b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
533b5677b36Schristos 
534b5677b36Schristos 		/* Signer's name. */
535b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
536b5677b36Schristos 
537b5677b36Schristos 		/* Signature. */
538b5677b36Schristos 		len = b64_ntop(rdata, edata - rdata,
539b5677b36Schristos 			       base64_key, sizeof base64_key);
540b5677b36Schristos 		if (len > 15) {
541b5677b36Schristos 			T(addstr(" (", 2, &buf, &buflen));
542b5677b36Schristos 			leader = "\n\t\t";
543b5677b36Schristos 			spaced = 0;
544b5677b36Schristos 		} else
545b5677b36Schristos 			leader = " ";
546b5677b36Schristos 		if (len < 0)
547b5677b36Schristos 			goto formerr;
548b5677b36Schristos 		for (n = 0; n < len; n += 48) {
549b5677b36Schristos 			T(addstr(leader, strlen(leader), &buf, &buflen));
550b5677b36Schristos 			T(addstr(base64_key + n, MIN(len - n, 48),
551b5677b36Schristos 				 &buf, &buflen));
552b5677b36Schristos 		}
553b5677b36Schristos 		if (len > 15)
554b5677b36Schristos 			T(addstr(" )", 2, &buf, &buflen));
555b5677b36Schristos 		break;
556b5677b36Schristos 	    }
557b5677b36Schristos 
558b5677b36Schristos 	case ns_t_nxt: {
559b5677b36Schristos 		int n, c;
560b5677b36Schristos 
561b5677b36Schristos 		/* Next domain name. */
562b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
563b5677b36Schristos 
564b5677b36Schristos 		/* Type bit map. */
565b5677b36Schristos 		n = edata - rdata;
566b5677b36Schristos 		for (c = 0; c < n*8; c++)
567b5677b36Schristos 			if (NS_NXT_BIT_ISSET(c, rdata)) {
568b5677b36Schristos 				len = SPRINTF((tmp, " %s", p_type(c)));
569b5677b36Schristos 				T(addstr(tmp, len, &buf, &buflen));
570b5677b36Schristos 			}
571b5677b36Schristos 		break;
572b5677b36Schristos 	    }
573b5677b36Schristos 
574b5677b36Schristos 	case ns_t_cert: {
575b5677b36Schristos 		u_int c_type, key_tag, alg;
576b5677b36Schristos 		int n;
577b5677b36Schristos 		unsigned int siz;
578b5677b36Schristos 		char base64_cert[8192], tmp[40];
579b5677b36Schristos 		const char *leader;
580b5677b36Schristos 
581b5677b36Schristos 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
582b5677b36Schristos 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
583b5677b36Schristos 		alg = (u_int) *rdata++;
584b5677b36Schristos 
585b5677b36Schristos 		len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
586b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
587b5677b36Schristos 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
588b5677b36Schristos 		if (siz > sizeof(base64_cert) * 3/4) {
589b5677b36Schristos 			const char *str = "record too long to print";
590b5677b36Schristos 			T(addstr(str, strlen(str), &buf, &buflen));
591b5677b36Schristos 		}
592b5677b36Schristos 		else {
593b5677b36Schristos 			len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
594b5677b36Schristos 
595b5677b36Schristos 			if (len < 0)
596b5677b36Schristos 				goto formerr;
597b5677b36Schristos 			else if (len > 15) {
598b5677b36Schristos 				T(addstr(" (", 2, &buf, &buflen));
599b5677b36Schristos 				leader = "\n\t\t";
600b5677b36Schristos 				spaced = 0;
601b5677b36Schristos 			}
602b5677b36Schristos 			else
603b5677b36Schristos 				leader = " ";
604b5677b36Schristos 
605b5677b36Schristos 			for (n = 0; n < len; n += 48) {
606b5677b36Schristos 				T(addstr(leader, strlen(leader),
607b5677b36Schristos 					 &buf, &buflen));
608b5677b36Schristos 				T(addstr(base64_cert + n, MIN(len - n, 48),
609b5677b36Schristos 					 &buf, &buflen));
610b5677b36Schristos 			}
611b5677b36Schristos 			if (len > 15)
612b5677b36Schristos 				T(addstr(" )", 2, &buf, &buflen));
613b5677b36Schristos 		}
614b5677b36Schristos 		break;
615b5677b36Schristos 	    }
616b5677b36Schristos 
617b5677b36Schristos 	case ns_t_tkey: {
618b5677b36Schristos 		/* KJD - need to complete this */
619b5677b36Schristos 		u_long t;
620b5677b36Schristos 		int mode, err, keysize;
621b5677b36Schristos 
622b5677b36Schristos 		/* Algorithm name. */
623b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
624b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
625b5677b36Schristos 
626b5677b36Schristos 		/* Inception. */
627b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
628b5677b36Schristos 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
629b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
630b5677b36Schristos 
631b5677b36Schristos 		/* Experation. */
632b5677b36Schristos 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
633b5677b36Schristos 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
634b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
635b5677b36Schristos 
636b5677b36Schristos 		/* Mode , Error, Key Size. */
637b5677b36Schristos 		/* Priority, Weight, Port. */
638b5677b36Schristos 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
639b5677b36Schristos 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
640b5677b36Schristos 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
641b5677b36Schristos 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
642b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
643b5677b36Schristos 
644b5677b36Schristos 		/* XXX need to dump key, print otherdata length & other data */
645b5677b36Schristos 		break;
646b5677b36Schristos 	    }
647b5677b36Schristos 
648b5677b36Schristos 	case ns_t_tsig: {
649b5677b36Schristos 		/* BEW - need to complete this */
650b5677b36Schristos 		int n;
651b5677b36Schristos 
652b5677b36Schristos 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
653b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
654b5677b36Schristos 		rdata += 8; /*%< time */
655b5677b36Schristos 		n = ns_get16(rdata); rdata += INT16SZ;
656b5677b36Schristos 		rdata += n; /*%< sig */
657b5677b36Schristos 		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
658b5677b36Schristos 		sprintf(buf, "%d", ns_get16(rdata));
659b5677b36Schristos 		rdata += INT16SZ;
660b5677b36Schristos 		addlen(strlen(buf), &buf, &buflen);
661b5677b36Schristos 		break;
662b5677b36Schristos 	    }
663b5677b36Schristos 
664b5677b36Schristos 	case ns_t_a6: {
665b5677b36Schristos 		struct in6_addr a;
666b5677b36Schristos 		int pbyte, pbit;
667b5677b36Schristos 
668b5677b36Schristos 		/* prefix length */
669b5677b36Schristos 		if (rdlen == 0U) goto formerr;
670b5677b36Schristos 		len = SPRINTF((tmp, "%d ", *rdata));
671b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
672b5677b36Schristos 		pbit = *rdata;
673b5677b36Schristos 		if (pbit > 128) goto formerr;
674b5677b36Schristos 		pbyte = (pbit & ~7) / 8;
675b5677b36Schristos 		rdata++;
676b5677b36Schristos 
677b5677b36Schristos 		/* address suffix: provided only when prefix len != 128 */
678b5677b36Schristos 		if (pbit < 128) {
679b5677b36Schristos 			if (rdata + pbyte >= edata) goto formerr;
680b5677b36Schristos 			memset(&a, 0, sizeof(a));
681b5677b36Schristos 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
682b5677b36Schristos 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
683b5677b36Schristos 			addlen(strlen(buf), &buf, &buflen);
684b5677b36Schristos 			rdata += sizeof(a) - pbyte;
685b5677b36Schristos 		}
686b5677b36Schristos 
687b5677b36Schristos 		/* prefix name: provided only when prefix len > 0 */
688b5677b36Schristos 		if (pbit == 0)
689b5677b36Schristos 			break;
690b5677b36Schristos 		if (rdata >= edata) goto formerr;
691b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
692b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
693b5677b36Schristos 
694b5677b36Schristos 		break;
695b5677b36Schristos 	    }
696b5677b36Schristos 
697b5677b36Schristos 	case ns_t_opt: {
698b5677b36Schristos 		len = SPRINTF((tmp, "%u bytes", class));
699b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
700b5677b36Schristos 		break;
701b5677b36Schristos 	    }
702b5677b36Schristos 
703b5677b36Schristos 	case ns_t_ds:
704b5677b36Schristos 	case ns_t_dlv:
705b5677b36Schristos 	case ns_t_sshfp: {
706b5677b36Schristos 		u_int t;
707b5677b36Schristos 
708b5677b36Schristos 		if (type == ns_t_ds || type == ns_t_dlv) {
709b5677b36Schristos 			if (rdlen < 4U) goto formerr;
710b5677b36Schristos 			t = ns_get16(rdata);
711b5677b36Schristos 			rdata += NS_INT16SZ;
712b5677b36Schristos 			len = SPRINTF((tmp, "%u ", t));
713b5677b36Schristos 			T(addstr(tmp, len, &buf, &buflen));
714b5677b36Schristos 		} else
715b5677b36Schristos 			if (rdlen < 2U) goto formerr;
716b5677b36Schristos 
717b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
718b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
719b5677b36Schristos 		rdata++;
720b5677b36Schristos 
721b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
722b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
723b5677b36Schristos 		rdata++;
724b5677b36Schristos 
725b5677b36Schristos 		while (rdata < edata) {
726b5677b36Schristos 			len = SPRINTF((tmp, "%02X", *rdata));
727b5677b36Schristos 			T(addstr(tmp, len, &buf, &buflen));
728b5677b36Schristos 			rdata++;
729b5677b36Schristos 		}
730b5677b36Schristos 		break;
731b5677b36Schristos 	    }
732b5677b36Schristos 
733b5677b36Schristos 	case ns_t_nsec3:
734b5677b36Schristos 	case ns_t_nsec3param: {
735b5677b36Schristos 		u_int t, w, l, j, k, c;
736b5677b36Schristos 
737b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
738b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
739b5677b36Schristos 		rdata++;
740b5677b36Schristos 
741b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
742b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
743b5677b36Schristos 		rdata++;
744b5677b36Schristos 
745b5677b36Schristos 		t = ns_get16(rdata);
746b5677b36Schristos 		rdata += NS_INT16SZ;
747b5677b36Schristos 		len = SPRINTF((tmp, "%u ", t));
748b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
749b5677b36Schristos 
750b5677b36Schristos 		t = *rdata++;
751b5677b36Schristos 		if (t == 0) {
752b5677b36Schristos 			T(addstr("-", 1, &buf, &buflen));
753b5677b36Schristos 		} else {
754b5677b36Schristos 			while (t-- > 0) {
755b5677b36Schristos 				len = SPRINTF((tmp, "%02X", *rdata));
756b5677b36Schristos 				T(addstr(tmp, len, &buf, &buflen));
757b5677b36Schristos 				rdata++;
758b5677b36Schristos 			}
759b5677b36Schristos 		}
760b5677b36Schristos 		if (type == ns_t_nsec3param)
761b5677b36Schristos 			break;
762b5677b36Schristos 		T(addstr(" ", 1, &buf, &buflen));
763b5677b36Schristos 
764b5677b36Schristos 		t = *rdata++;
765b5677b36Schristos 		while (t > 0) {
766b5677b36Schristos 			switch (t) {
767b5677b36Schristos 			case 1:
768b5677b36Schristos 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
769b5677b36Schristos 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
770b5677b36Schristos 				tmp[2] = tmp[3] = tmp[4] = '=';
771b5677b36Schristos 				tmp[5] = tmp[6] = tmp[7] = '=';
772b5677b36Schristos 				break;
773b5677b36Schristos 			case 2:
774b5677b36Schristos 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
775b5677b36Schristos 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
776b5677b36Schristos 						   ((rdata[1]>>6)&0x03)];
777b5677b36Schristos 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
778b5677b36Schristos 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
779b5677b36Schristos 				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
780b5677b36Schristos 				break;
781b5677b36Schristos 			case 3:
782b5677b36Schristos 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
783b5677b36Schristos 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
784b5677b36Schristos 						   ((rdata[1]>>6)&0x03)];
785b5677b36Schristos 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
786b5677b36Schristos 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
787b5677b36Schristos 						   ((rdata[2]>>4)&0x0f)];
788b5677b36Schristos 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
789b5677b36Schristos 				tmp[5] = tmp[6] = tmp[7] = '=';
790b5677b36Schristos 				break;
791b5677b36Schristos 			case 4:
792b5677b36Schristos 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
793b5677b36Schristos 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
794b5677b36Schristos 						   ((rdata[1]>>6)&0x03)];
795b5677b36Schristos 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
796b5677b36Schristos 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
797b5677b36Schristos 						   ((rdata[2]>>4)&0x0f)];
798b5677b36Schristos 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
799b5677b36Schristos 						   ((rdata[3]>>7)&0x01)];
800b5677b36Schristos 				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
801b5677b36Schristos 				tmp[6] = base32hex[(rdata[3]<<3)&0x18];
802b5677b36Schristos 				tmp[7] = '=';
803b5677b36Schristos 				break;
804b5677b36Schristos 			default:
805b5677b36Schristos 				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
806b5677b36Schristos 				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
807b5677b36Schristos 						   ((rdata[1]>>6)&0x03)];
808b5677b36Schristos 				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
809b5677b36Schristos 				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
810b5677b36Schristos 						   ((rdata[2]>>4)&0x0f)];
811b5677b36Schristos 				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
812b5677b36Schristos 						   ((rdata[3]>>7)&0x01)];
813b5677b36Schristos 				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
814b5677b36Schristos 				tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
815b5677b36Schristos 						   ((rdata[4]>>5)&0x07)];
816b5677b36Schristos 				tmp[7] = base32hex[(rdata[4]&0x1f)];
817b5677b36Schristos 				break;
818b5677b36Schristos 			}
819b5677b36Schristos 			T(addstr(tmp, 8, &buf, &buflen));
820b5677b36Schristos 			if (t >= 5) {
821b5677b36Schristos 				rdata += 5;
822b5677b36Schristos 				t -= 5;
823b5677b36Schristos 			} else {
824b5677b36Schristos 				rdata += t;
825b5677b36Schristos 				t -= t;
826b5677b36Schristos 			}
827b5677b36Schristos 		}
828b5677b36Schristos 
829b5677b36Schristos 		while (rdata < edata) {
830b5677b36Schristos 			w = *rdata++;
831b5677b36Schristos 			l = *rdata++;
832b5677b36Schristos 			for (j = 0; j < l; j++) {
833b5677b36Schristos 				if (rdata[j] == 0)
834b5677b36Schristos 					continue;
835b5677b36Schristos 				for (k = 0; k < 8; k++) {
836b5677b36Schristos 					if ((rdata[j] & (0x80 >> k)) == 0)
837b5677b36Schristos 						continue;
838b5677b36Schristos 					c = w * 256 + j * 8 + k;
839b5677b36Schristos 					len = SPRINTF((tmp, " %s", p_type(c)));
840b5677b36Schristos 					T(addstr(tmp, len, &buf, &buflen));
841b5677b36Schristos 				}
842b5677b36Schristos 			}
843b5677b36Schristos 			rdata += l;
844b5677b36Schristos 		}
845b5677b36Schristos 		break;
846b5677b36Schristos 	    }
847b5677b36Schristos 
848b5677b36Schristos 	case ns_t_nsec: {
849b5677b36Schristos 		u_int w, l, j, k, c;
850b5677b36Schristos 
851b5677b36Schristos 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
852b5677b36Schristos 
853b5677b36Schristos 		while (rdata < edata) {
854b5677b36Schristos 			w = *rdata++;
855b5677b36Schristos 			l = *rdata++;
856b5677b36Schristos 			for (j = 0; j < l; j++) {
857b5677b36Schristos 				if (rdata[j] == 0)
858b5677b36Schristos 					continue;
859b5677b36Schristos 				for (k = 0; k < 8; k++) {
860b5677b36Schristos 					if ((rdata[j] & (0x80 >> k)) == 0)
861b5677b36Schristos 						continue;
862b5677b36Schristos 					c = w * 256 + j * 8 + k;
863b5677b36Schristos 					len = SPRINTF((tmp, " %s", p_type(c)));
864b5677b36Schristos 					T(addstr(tmp, len, &buf, &buflen));
865b5677b36Schristos 				}
866b5677b36Schristos 			}
867b5677b36Schristos 			rdata += l;
868b5677b36Schristos 		}
869b5677b36Schristos 		break;
870b5677b36Schristos 	    }
871b5677b36Schristos 
872b5677b36Schristos 	case ns_t_dhcid: {
873b5677b36Schristos 		int n;
874b5677b36Schristos 		unsigned int siz;
875b5677b36Schristos 		char base64_dhcid[8192];
876b5677b36Schristos 		const char *leader;
877b5677b36Schristos 
878b5677b36Schristos 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
879b5677b36Schristos 		if (siz > sizeof(base64_dhcid) * 3/4) {
880b5677b36Schristos 			const char *str = "record too long to print";
881b5677b36Schristos 			T(addstr(str, strlen(str), &buf, &buflen));
882b5677b36Schristos 		} else {
883b5677b36Schristos 			len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
884b5677b36Schristos 
885b5677b36Schristos 			if (len < 0)
886b5677b36Schristos 				goto formerr;
887b5677b36Schristos 
888b5677b36Schristos 			else if (len > 15) {
889b5677b36Schristos 				T(addstr(" (", 2, &buf, &buflen));
890b5677b36Schristos 				leader = "\n\t\t";
891b5677b36Schristos 				spaced = 0;
892b5677b36Schristos 			}
893b5677b36Schristos 			else
894b5677b36Schristos 				leader = " ";
895b5677b36Schristos 
896b5677b36Schristos 			for (n = 0; n < len; n += 48) {
897b5677b36Schristos 				T(addstr(leader, strlen(leader),
898b5677b36Schristos 					 &buf, &buflen));
899b5677b36Schristos 				T(addstr(base64_dhcid + n, MIN(len - n, 48),
900b5677b36Schristos 					 &buf, &buflen));
901b5677b36Schristos 			}
902b5677b36Schristos 			if (len > 15)
903b5677b36Schristos 				T(addstr(" )", 2, &buf, &buflen));
904b5677b36Schristos 		}
905b5677b36Schristos 	}
906b5677b36Schristos 
907b5677b36Schristos 	case ns_t_ipseckey: {
908b5677b36Schristos 		int n;
909b5677b36Schristos 		unsigned int siz;
910b5677b36Schristos 		char base64_key[8192];
911b5677b36Schristos 		const char *leader;
912b5677b36Schristos 
913b5677b36Schristos 		if (rdlen < 2)
914b5677b36Schristos 			goto formerr;
915b5677b36Schristos 
916b5677b36Schristos 		switch (rdata[1]) {
917b5677b36Schristos 		case 0:
918b5677b36Schristos 		case 3:
919b5677b36Schristos 			if (rdlen < 3)
920b5677b36Schristos 				goto formerr;
921b5677b36Schristos 			break;
922b5677b36Schristos 		case 1:
923b5677b36Schristos 			if (rdlen < 7)
924b5677b36Schristos 				goto formerr;
925b5677b36Schristos 			break;
926b5677b36Schristos 		case 2:
927b5677b36Schristos 			if (rdlen < 19)
928b5677b36Schristos 				goto formerr;
929b5677b36Schristos 			break;
930b5677b36Schristos 		default:
931b5677b36Schristos 			comment = "unknown IPSECKEY gateway type";
932b5677b36Schristos 			goto hexify;
933b5677b36Schristos 		}
934b5677b36Schristos 
935b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
936b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
937b5677b36Schristos 		rdata++;
938b5677b36Schristos 
939b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
940b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
941b5677b36Schristos 		rdata++;
942b5677b36Schristos 
943b5677b36Schristos 		len = SPRINTF((tmp, "%u ", *rdata));
944b5677b36Schristos 		T(addstr(tmp, len, &buf, &buflen));
945b5677b36Schristos 		rdata++;
946b5677b36Schristos 
947b5677b36Schristos 		switch (rdata[-2]) {
948b5677b36Schristos 		case 0:
949b5677b36Schristos 			T(addstr(".", 1, &buf, &buflen));
950b5677b36Schristos 			break;
951b5677b36Schristos 		case 1:
952b5677b36Schristos 			(void) inet_ntop(AF_INET, rdata, buf, buflen);
953b5677b36Schristos 			addlen(strlen(buf), &buf, &buflen);
954b5677b36Schristos 			rdata += 4;
955b5677b36Schristos 			break;
956b5677b36Schristos 		case 2:
957b5677b36Schristos 			(void) inet_ntop(AF_INET6, rdata, buf, buflen);
958b5677b36Schristos 			addlen(strlen(buf), &buf, &buflen);
959b5677b36Schristos 			rdata += 16;
960b5677b36Schristos 			break;
961b5677b36Schristos 		case 3:
962b5677b36Schristos 			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
963b5677b36Schristos 			break;
964b5677b36Schristos 		}
965b5677b36Schristos 
966b5677b36Schristos 		if (rdata >= edata)
967b5677b36Schristos 			break;
968b5677b36Schristos 
969b5677b36Schristos 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
970b5677b36Schristos 		if (siz > sizeof(base64_key) * 3/4) {
971b5677b36Schristos 			const char *str = "record too long to print";
972b5677b36Schristos 			T(addstr(str, strlen(str), &buf, &buflen));
973b5677b36Schristos 		} else {
974b5677b36Schristos 			len = b64_ntop(rdata, edata-rdata, base64_key, siz);
975b5677b36Schristos 
976b5677b36Schristos 			if (len < 0)
977b5677b36Schristos 				goto formerr;
978b5677b36Schristos 
979b5677b36Schristos 			else if (len > 15) {
980b5677b36Schristos 				T(addstr(" (", 2, &buf, &buflen));
981b5677b36Schristos 				leader = "\n\t\t";
982b5677b36Schristos 				spaced = 0;
983b5677b36Schristos 			}
984b5677b36Schristos 			else
985b5677b36Schristos 				leader = " ";
986b5677b36Schristos 
987b5677b36Schristos 			for (n = 0; n < len; n += 48) {
988b5677b36Schristos 				T(addstr(leader, strlen(leader),
989b5677b36Schristos 					 &buf, &buflen));
990b5677b36Schristos 				T(addstr(base64_key + n, MIN(len - n, 48),
991b5677b36Schristos 					 &buf, &buflen));
992b5677b36Schristos 			}
993b5677b36Schristos 			if (len > 15)
994b5677b36Schristos 				T(addstr(" )", 2, &buf, &buflen));
995b5677b36Schristos 		}
996b5677b36Schristos 	}
997b5677b36Schristos 
998b5677b36Schristos 	case ns_t_hip: {
999b5677b36Schristos 		unsigned int i, hip_len, algorithm, key_len;
1000b5677b36Schristos 		char base64_key[NS_MD5RSA_MAX_BASE64];
1001b5677b36Schristos 		unsigned int siz;
1002b5677b36Schristos 		const char *leader = "\n\t\t\t\t\t";
1003b5677b36Schristos 
1004b5677b36Schristos 		hip_len = *rdata++;
1005b5677b36Schristos 		algorithm = *rdata++;
1006b5677b36Schristos 		key_len = ns_get16(rdata);
1007b5677b36Schristos 		rdata += NS_INT16SZ;
1008b5677b36Schristos 
1009b5677b36Schristos 		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
1010b5677b36Schristos 		if (siz > sizeof(base64_key) * 3/4) {
1011b5677b36Schristos 			const char *str = "record too long to print";
1012b5677b36Schristos 			T(addstr(str, strlen(str), &buf, &buflen));
1013b5677b36Schristos 		} else {
1014b5677b36Schristos 			len = sprintf(tmp, "( %u ", algorithm);
1015b5677b36Schristos 			T(addstr(tmp, len, &buf, &buflen));
1016b5677b36Schristos 
1017b5677b36Schristos 			for (i = 0; i < hip_len; i++) {
1018b5677b36Schristos 				len = sprintf(tmp, "%02X", *rdata);
1019b5677b36Schristos 				T(addstr(tmp, len, &buf, &buflen));
1020b5677b36Schristos 				rdata++;
1021b5677b36Schristos 			}
1022b5677b36Schristos 			T(addstr(leader, strlen(leader), &buf, &buflen));
1023b5677b36Schristos 
1024b5677b36Schristos 			len = b64_ntop(rdata, key_len, base64_key, siz);
1025b5677b36Schristos 			if (len < 0)
1026b5677b36Schristos 				goto formerr;
1027b5677b36Schristos 
1028b5677b36Schristos 			T(addstr(base64_key, len, &buf, &buflen));
1029b5677b36Schristos 
1030b5677b36Schristos 			rdata += key_len;
1031b5677b36Schristos 			while (rdata < edata) {
1032b5677b36Schristos 				T(addstr(leader, strlen(leader), &buf, &buflen));
1033b5677b36Schristos 				T(addname(msg, msglen, &rdata, origin,
1034b5677b36Schristos 					  &buf, &buflen));
1035b5677b36Schristos 			}
1036b5677b36Schristos 			T(addstr(" )", 2, &buf, &buflen));
1037b5677b36Schristos 		}
1038b5677b36Schristos 		break;
1039b5677b36Schristos 	}
1040b5677b36Schristos 
1041b5677b36Schristos 	default:
1042b5677b36Schristos 		comment = "unknown RR type";
1043b5677b36Schristos 		goto hexify;
1044b5677b36Schristos 	}
1045b5677b36Schristos 	return (buf - obuf);
1046b5677b36Schristos  formerr:
1047b5677b36Schristos 	comment = "RR format error";
1048b5677b36Schristos  hexify: {
1049b5677b36Schristos 	int n, m;
1050b5677b36Schristos 	char *p;
1051b5677b36Schristos 
1052b5677b36Schristos 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
1053b5677b36Schristos 		       rdlen != 0U ? " (" : "", comment));
1054b5677b36Schristos 	T(addstr(tmp, len, &buf, &buflen));
1055b5677b36Schristos 	while (rdata < edata) {
1056b5677b36Schristos 		p = tmp;
1057b5677b36Schristos 		p += SPRINTF((p, "\n\t"));
1058b5677b36Schristos 		spaced = 0;
1059b5677b36Schristos 		n = MIN(16, edata - rdata);
1060b5677b36Schristos 		for (m = 0; m < n; m++)
1061b5677b36Schristos 			p += SPRINTF((p, "%02x ", rdata[m]));
1062b5677b36Schristos 		T(addstr(tmp, p - tmp, &buf, &buflen));
1063b5677b36Schristos 		if (n < 16) {
1064b5677b36Schristos 			T(addstr(")", 1, &buf, &buflen));
1065b5677b36Schristos 			T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
1066b5677b36Schristos 		}
1067b5677b36Schristos 		p = tmp;
1068b5677b36Schristos 		p += SPRINTF((p, "; "));
1069b5677b36Schristos 		for (m = 0; m < n; m++)
1070b5677b36Schristos 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
1071b5677b36Schristos 				? rdata[m]
1072b5677b36Schristos 				: '.';
1073b5677b36Schristos 		T(addstr(tmp, p - tmp, &buf, &buflen));
1074b5677b36Schristos 		rdata += n;
1075b5677b36Schristos 	}
1076b5677b36Schristos 	return (buf - obuf);
1077b5677b36Schristos     }
1078b5677b36Schristos }
1079b5677b36Schristos 
1080b5677b36Schristos /* Private. */
1081b5677b36Schristos 
1082b5677b36Schristos /*%
1083b5677b36Schristos  * size_t
1084b5677b36Schristos  * prune_origin(name, origin)
1085b5677b36Schristos  *	Find out if the name is at or under the current origin.
1086b5677b36Schristos  * return:
1087b5677b36Schristos  *	Number of characters in name before start of origin,
1088b5677b36Schristos  *	or length of name if origin does not match.
1089b5677b36Schristos  * notes:
1090b5677b36Schristos  *	This function should share code with samedomain().
1091b5677b36Schristos  */
1092b5677b36Schristos static size_t
prune_origin(const char * name,const char * origin)1093b5677b36Schristos prune_origin(const char *name, const char *origin) {
1094b5677b36Schristos 	const char *oname = name;
1095b5677b36Schristos 
1096b5677b36Schristos 	while (*name != '\0') {
1097b5677b36Schristos 		if (origin != NULL && ns_samename(name, origin) == 1)
1098b5677b36Schristos 			return (name - oname - (name > oname));
1099b5677b36Schristos 		while (*name != '\0') {
1100b5677b36Schristos 			if (*name == '\\') {
1101b5677b36Schristos 				name++;
1102b5677b36Schristos 				/* XXX need to handle \nnn form. */
1103b5677b36Schristos 				if (*name == '\0')
1104b5677b36Schristos 					break;
1105b5677b36Schristos 			} else if (*name == '.') {
1106b5677b36Schristos 				name++;
1107b5677b36Schristos 				break;
1108b5677b36Schristos 			}
1109b5677b36Schristos 			name++;
1110b5677b36Schristos 		}
1111b5677b36Schristos 	}
1112b5677b36Schristos 	return (name - oname);
1113b5677b36Schristos }
1114b5677b36Schristos 
1115b5677b36Schristos /*%
1116b5677b36Schristos  * int
1117b5677b36Schristos  * charstr(rdata, edata, buf, buflen)
1118b5677b36Schristos  *	Format a <character-string> into the presentation buffer.
1119b5677b36Schristos  * return:
1120b5677b36Schristos  *	Number of rdata octets consumed
1121b5677b36Schristos  *	0 for protocol format error
1122b5677b36Schristos  *	-1 for output buffer error
1123b5677b36Schristos  * side effects:
1124b5677b36Schristos  *	buffer is advanced on success.
1125b5677b36Schristos  */
1126b5677b36Schristos static int
charstr(const u_char * rdata,const u_char * edata,char ** buf,size_t * buflen)1127b5677b36Schristos charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
1128b5677b36Schristos 	const u_char *odata = rdata;
1129b5677b36Schristos 	size_t save_buflen = *buflen;
1130b5677b36Schristos 	char *save_buf = *buf;
1131b5677b36Schristos 
1132b5677b36Schristos 	if (addstr("\"", 1, buf, buflen) < 0)
1133b5677b36Schristos 		goto enospc;
1134b5677b36Schristos 	if (rdata < edata) {
1135b5677b36Schristos 		int n = *rdata;
1136b5677b36Schristos 
1137b5677b36Schristos 		if (rdata + 1 + n <= edata) {
1138b5677b36Schristos 			rdata++;
1139b5677b36Schristos 			while (n-- > 0) {
1140b5677b36Schristos 				if (strchr("\n\"\\", *rdata) != NULL)
1141b5677b36Schristos 					if (addstr("\\", 1, buf, buflen) < 0)
1142b5677b36Schristos 						goto enospc;
1143b5677b36Schristos 				if (addstr((const char *)rdata, 1,
1144b5677b36Schristos 					   buf, buflen) < 0)
1145b5677b36Schristos 					goto enospc;
1146b5677b36Schristos 				rdata++;
1147b5677b36Schristos 			}
1148b5677b36Schristos 		}
1149b5677b36Schristos 	}
1150b5677b36Schristos 	if (addstr("\"", 1, buf, buflen) < 0)
1151b5677b36Schristos 		goto enospc;
1152b5677b36Schristos 	return (rdata - odata);
1153b5677b36Schristos  enospc:
1154b5677b36Schristos 	errno = ENOSPC;
1155b5677b36Schristos 	*buf = save_buf;
1156b5677b36Schristos 	*buflen = save_buflen;
1157b5677b36Schristos 	return (-1);
1158b5677b36Schristos }
1159b5677b36Schristos 
1160b5677b36Schristos static int
addname(const u_char * msg,size_t msglen,const u_char ** pp,const char * origin,char ** buf,size_t * buflen)1161b5677b36Schristos addname(const u_char *msg, size_t msglen,
1162b5677b36Schristos 	const u_char **pp, const char *origin,
1163b5677b36Schristos 	char **buf, size_t *buflen)
1164b5677b36Schristos {
1165b5677b36Schristos 	size_t newlen, save_buflen = *buflen;
1166b5677b36Schristos 	char *save_buf = *buf;
1167b5677b36Schristos 	int n;
1168b5677b36Schristos 
1169b5677b36Schristos 	n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
1170b5677b36Schristos 	if (n < 0)
1171b5677b36Schristos 		goto enospc;	/*%< Guess. */
1172b5677b36Schristos 	newlen = prune_origin(*buf, origin);
1173b5677b36Schristos 	if (**buf == '\0') {
1174b5677b36Schristos 		goto root;
1175b5677b36Schristos 	} else if (newlen == 0U) {
1176b5677b36Schristos 		/* Use "@" instead of name. */
1177b5677b36Schristos 		if (newlen + 2 > *buflen)
1178b5677b36Schristos 			goto enospc;        /* No room for "@\0". */
1179b5677b36Schristos 		(*buf)[newlen++] = '@';
1180b5677b36Schristos 		(*buf)[newlen] = '\0';
1181b5677b36Schristos 	} else {
1182b5677b36Schristos 		if (((origin == NULL || origin[0] == '\0') ||
1183b5677b36Schristos 		    (origin[0] != '.' && origin[1] != '\0' &&
1184b5677b36Schristos 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
1185b5677b36Schristos 			/* No trailing dot. */
1186b5677b36Schristos  root:
1187b5677b36Schristos 			if (newlen + 2 > *buflen)
1188b5677b36Schristos 				goto enospc;	/* No room for ".\0". */
1189b5677b36Schristos 			(*buf)[newlen++] = '.';
1190b5677b36Schristos 			(*buf)[newlen] = '\0';
1191b5677b36Schristos 		}
1192b5677b36Schristos 	}
1193b5677b36Schristos 	*pp += n;
1194b5677b36Schristos 	addlen(newlen, buf, buflen);
1195b5677b36Schristos 	**buf = '\0';
1196b5677b36Schristos 	return (newlen);
1197b5677b36Schristos  enospc:
1198b5677b36Schristos 	errno = ENOSPC;
1199b5677b36Schristos 	*buf = save_buf;
1200b5677b36Schristos 	*buflen = save_buflen;
1201b5677b36Schristos 	return (-1);
1202b5677b36Schristos }
1203b5677b36Schristos 
1204b5677b36Schristos static void
addlen(size_t len,char ** buf,size_t * buflen)1205b5677b36Schristos addlen(size_t len, char **buf, size_t *buflen) {
1206b5677b36Schristos 	INSIST(len <= *buflen);
1207b5677b36Schristos 	*buf += len;
1208b5677b36Schristos 	*buflen -= len;
1209b5677b36Schristos }
1210b5677b36Schristos 
1211b5677b36Schristos static int
addstr(const char * src,size_t len,char ** buf,size_t * buflen)1212b5677b36Schristos addstr(const char *src, size_t len, char **buf, size_t *buflen) {
1213b5677b36Schristos 	if (len >= *buflen) {
1214b5677b36Schristos 		errno = ENOSPC;
1215b5677b36Schristos 		return (-1);
1216b5677b36Schristos 	}
1217b5677b36Schristos 	memcpy(*buf, src, len);
1218b5677b36Schristos 	addlen(len, buf, buflen);
1219b5677b36Schristos 	**buf = '\0';
1220b5677b36Schristos 	return (0);
1221b5677b36Schristos }
1222b5677b36Schristos 
1223b5677b36Schristos static int
addtab(size_t len,size_t target,int spaced,char ** buf,size_t * buflen)1224b5677b36Schristos addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
1225b5677b36Schristos 	size_t save_buflen = *buflen;
1226b5677b36Schristos 	char *save_buf = *buf;
1227b5677b36Schristos 	int t;
1228b5677b36Schristos 
1229b5677b36Schristos 	if (spaced || len >= target - 1) {
1230b5677b36Schristos 		T(addstr("  ", 2, buf, buflen));
1231b5677b36Schristos 		spaced = 1;
1232b5677b36Schristos 	} else {
1233b5677b36Schristos 		for (t = (target - len - 1) / 8; t >= 0; t--)
1234b5677b36Schristos 			if (addstr("\t", 1, buf, buflen) < 0) {
1235b5677b36Schristos 				*buflen = save_buflen;
1236b5677b36Schristos 				*buf = save_buf;
1237b5677b36Schristos 				return (-1);
1238b5677b36Schristos 			}
1239b5677b36Schristos 		spaced = 0;
1240b5677b36Schristos 	}
1241b5677b36Schristos 	return (spaced);
1242b5677b36Schristos }
1243b5677b36Schristos 
1244b5677b36Schristos /*! \file */
1245