1156952Sume/*
2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3156952Sume * Copyright (c) 1996-1999 by Internet Software Consortium.
4156952Sume *
5156952Sume * Permission to use, copy, modify, and distribute this software for any
6156952Sume * purpose with or without fee is hereby granted, provided that the above
7156952Sume * copyright notice and this permission notice appear in all copies.
8156952Sume *
9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16156952Sume */
17156952Sume
18156952Sume#ifndef lint
19269867Sumestatic const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
20156952Sume#endif
21156956Sume#include <sys/cdefs.h>
22156956Sume__FBSDID("$FreeBSD$");
23156952Sume
24156952Sume/* Import. */
25156952Sume
26156952Sume#include "port_before.h"
27156952Sume
28156952Sume#include <sys/types.h>
29156952Sume#include <sys/socket.h>
30156952Sume
31156952Sume#include <netinet/in.h>
32156952Sume#include <arpa/nameser.h>
33156952Sume#include <arpa/inet.h>
34156952Sume
35156956Sume#ifdef _LIBC
36156956Sume#include <assert.h>
37156956Sume#define INSIST(cond)	assert(cond)
38156956Sume#else
39156952Sume#include <isc/assertions.h>
40156952Sume#include <isc/dst.h>
41156956Sume#endif
42156952Sume#include <errno.h>
43156952Sume#include <resolv.h>
44156952Sume#include <string.h>
45156952Sume#include <ctype.h>
46156952Sume
47156952Sume#include "port_after.h"
48156952Sume
49156952Sume#ifdef SPRINTF_CHAR
50156952Sume# define SPRINTF(x) strlen(sprintf/**/x)
51156952Sume#else
52156952Sume# define SPRINTF(x) ((size_t)sprintf x)
53156952Sume#endif
54156952Sume
55156952Sume/* Forward. */
56156952Sume
57156952Sumestatic size_t	prune_origin(const char *name, const char *origin);
58156952Sumestatic int	charstr(const u_char *rdata, const u_char *edata,
59156952Sume			char **buf, size_t *buflen);
60156952Sumestatic int	addname(const u_char *msg, size_t msglen,
61156952Sume			const u_char **p, const char *origin,
62156952Sume			char **buf, size_t *buflen);
63156952Sumestatic void	addlen(size_t len, char **buf, size_t *buflen);
64156952Sumestatic int	addstr(const char *src, size_t len,
65156952Sume		       char **buf, size_t *buflen);
66156952Sumestatic int	addtab(size_t len, size_t target, int spaced,
67156952Sume		       char **buf, size_t *buflen);
68156952Sume
69156952Sume/* Macros. */
70156952Sume
71156952Sume#define	T(x) \
72156952Sume	do { \
73156952Sume		if ((x) < 0) \
74156952Sume			return (-1); \
75156952Sume	} while (0)
76156952Sume
77269867Sumestatic const char base32hex[] =
78269867Sume        "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
79269867Sume
80156952Sume/* Public. */
81156952Sume
82170244Sume/*%
83156952Sume *	Convert an RR to presentation format.
84170244Sume *
85156952Sume * return:
86170244Sume *\li	Number of characters written to buf, or -1 (check errno).
87156952Sume */
88156952Sumeint
89156952Sumens_sprintrr(const ns_msg *handle, const ns_rr *rr,
90156952Sume	    const char *name_ctx, const char *origin,
91156952Sume	    char *buf, size_t buflen)
92156952Sume{
93156952Sume	int n;
94156952Sume
95156952Sume	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
96156952Sume			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
97156952Sume			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
98156952Sume			 name_ctx, origin, buf, buflen);
99156952Sume	return (n);
100156952Sume}
101156952Sume
102170244Sume/*%
103156952Sume *	Convert the fields of an RR into presentation format.
104170244Sume *
105156952Sume * return:
106170244Sume *\li	Number of characters written to buf, or -1 (check errno).
107156952Sume */
108156952Sumeint
109156952Sumens_sprintrrf(const u_char *msg, size_t msglen,
110156952Sume	    const char *name, ns_class class, ns_type type,
111156952Sume	    u_long ttl, const u_char *rdata, size_t rdlen,
112156952Sume	    const char *name_ctx, const char *origin,
113156952Sume	    char *buf, size_t buflen)
114156952Sume{
115156952Sume	const char *obuf = buf;
116156952Sume	const u_char *edata = rdata + rdlen;
117156952Sume	int spaced = 0;
118156952Sume
119156952Sume	const char *comment;
120156952Sume	char tmp[100];
121156952Sume	int len, x;
122156952Sume
123156952Sume	/*
124156952Sume	 * Owner.
125156952Sume	 */
126156952Sume	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
127156952Sume		T(addstr("\t\t\t", 3, &buf, &buflen));
128156952Sume	} else {
129156952Sume		len = prune_origin(name, origin);
130156952Sume		if (*name == '\0') {
131156952Sume			goto root;
132156952Sume		} else if (len == 0) {
133156952Sume			T(addstr("@\t\t\t", 4, &buf, &buflen));
134156952Sume		} else {
135156952Sume			T(addstr(name, len, &buf, &buflen));
136156952Sume			/* Origin not used or not root, and no trailing dot? */
137156952Sume			if (((origin == NULL || origin[0] == '\0') ||
138156952Sume			    (origin[0] != '.' && origin[1] != '\0' &&
139156952Sume			    name[len] == '\0')) && name[len - 1] != '.') {
140156952Sume root:
141156952Sume				T(addstr(".", 1, &buf, &buflen));
142156952Sume				len++;
143156952Sume			}
144156952Sume			T(spaced = addtab(len, 24, spaced, &buf, &buflen));
145156952Sume		}
146156952Sume	}
147156952Sume
148156952Sume	/*
149156952Sume	 * TTL, Class, Type.
150156952Sume	 */
151156952Sume	T(x = ns_format_ttl(ttl, buf, buflen));
152156952Sume	addlen(x, &buf, &buflen);
153156952Sume	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
154156952Sume	T(addstr(tmp, len, &buf, &buflen));
155156952Sume	T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
156156952Sume
157156952Sume	/*
158156952Sume	 * RData.
159156952Sume	 */
160156952Sume	switch (type) {
161156952Sume	case ns_t_a:
162156952Sume		if (rdlen != (size_t)NS_INADDRSZ)
163156952Sume			goto formerr;
164156952Sume		(void) inet_ntop(AF_INET, rdata, buf, buflen);
165156952Sume		addlen(strlen(buf), &buf, &buflen);
166156952Sume		break;
167156952Sume
168156952Sume	case ns_t_cname:
169156952Sume	case ns_t_mb:
170156952Sume	case ns_t_mg:
171156952Sume	case ns_t_mr:
172156952Sume	case ns_t_ns:
173156952Sume	case ns_t_ptr:
174156952Sume	case ns_t_dname:
175156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
176156952Sume		break;
177156952Sume
178156952Sume	case ns_t_hinfo:
179156952Sume	case ns_t_isdn:
180156952Sume		/* First word. */
181156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
182156952Sume		if (len == 0)
183156952Sume			goto formerr;
184156952Sume		rdata += len;
185156952Sume		T(addstr(" ", 1, &buf, &buflen));
186156952Sume
187156952Sume
188156952Sume		/* Second word, optional in ISDN records. */
189156952Sume		if (type == ns_t_isdn && rdata == edata)
190156952Sume			break;
191156952Sume
192156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
193156952Sume		if (len == 0)
194156952Sume			goto formerr;
195156952Sume		rdata += len;
196156952Sume		break;
197156952Sume
198156952Sume	case ns_t_soa: {
199156952Sume		u_long t;
200156952Sume
201156952Sume		/* Server name. */
202156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
203156952Sume		T(addstr(" ", 1, &buf, &buflen));
204156952Sume
205156952Sume		/* Administrator name. */
206156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
207156952Sume		T(addstr(" (\n", 3, &buf, &buflen));
208156952Sume		spaced = 0;
209156952Sume
210156952Sume		if ((edata - rdata) != 5*NS_INT32SZ)
211156952Sume			goto formerr;
212156952Sume
213156952Sume		/* Serial number. */
214156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
215156952Sume		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
216156952Sume		len = SPRINTF((tmp, "%lu", t));
217156952Sume		T(addstr(tmp, len, &buf, &buflen));
218156952Sume		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
219156952Sume		T(addstr("; serial\n", 9, &buf, &buflen));
220156952Sume		spaced = 0;
221156952Sume
222156952Sume		/* Refresh interval. */
223156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
224156952Sume		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
225156952Sume		T(len = ns_format_ttl(t, buf, buflen));
226156952Sume		addlen(len, &buf, &buflen);
227156952Sume		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
228156952Sume		T(addstr("; refresh\n", 10, &buf, &buflen));
229156952Sume		spaced = 0;
230156952Sume
231156952Sume		/* Retry interval. */
232156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
233156952Sume		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
234156952Sume		T(len = ns_format_ttl(t, buf, buflen));
235156952Sume		addlen(len, &buf, &buflen);
236156952Sume		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
237156952Sume		T(addstr("; retry\n", 8, &buf, &buflen));
238156952Sume		spaced = 0;
239156952Sume
240156952Sume		/* Expiry. */
241156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
242156952Sume		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
243156952Sume		T(len = ns_format_ttl(t, buf, buflen));
244156952Sume		addlen(len, &buf, &buflen);
245156952Sume		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
246156952Sume		T(addstr("; expiry\n", 9, &buf, &buflen));
247156952Sume		spaced = 0;
248156952Sume
249156952Sume		/* Minimum TTL. */
250156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
251156952Sume		T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
252156952Sume		T(len = ns_format_ttl(t, buf, buflen));
253156952Sume		addlen(len, &buf, &buflen);
254156952Sume		T(addstr(" )", 2, &buf, &buflen));
255156952Sume		T(spaced = addtab(len, 16, spaced, &buf, &buflen));
256156952Sume		T(addstr("; minimum\n", 10, &buf, &buflen));
257156952Sume
258156952Sume		break;
259156952Sume	    }
260156952Sume
261156952Sume	case ns_t_mx:
262156952Sume	case ns_t_afsdb:
263269867Sume	case ns_t_rt:
264269867Sume	case ns_t_kx: {
265156952Sume		u_int t;
266156952Sume
267156952Sume		if (rdlen < (size_t)NS_INT16SZ)
268156952Sume			goto formerr;
269156952Sume
270156952Sume		/* Priority. */
271156952Sume		t = ns_get16(rdata);
272156952Sume		rdata += NS_INT16SZ;
273156952Sume		len = SPRINTF((tmp, "%u ", t));
274156952Sume		T(addstr(tmp, len, &buf, &buflen));
275156952Sume
276156952Sume		/* Target. */
277156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
278156952Sume
279156952Sume		break;
280156952Sume	    }
281156952Sume
282156952Sume	case ns_t_px: {
283156952Sume		u_int t;
284156952Sume
285156952Sume		if (rdlen < (size_t)NS_INT16SZ)
286156952Sume			goto formerr;
287156952Sume
288156952Sume		/* Priority. */
289156952Sume		t = ns_get16(rdata);
290156952Sume		rdata += NS_INT16SZ;
291156952Sume		len = SPRINTF((tmp, "%u ", t));
292156952Sume		T(addstr(tmp, len, &buf, &buflen));
293156952Sume
294156952Sume		/* Name1. */
295156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
296156952Sume		T(addstr(" ", 1, &buf, &buflen));
297156952Sume
298156952Sume		/* Name2. */
299156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
300156952Sume
301156952Sume		break;
302156952Sume	    }
303156952Sume
304156952Sume	case ns_t_x25:
305156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
306156952Sume		if (len == 0)
307156952Sume			goto formerr;
308156952Sume		rdata += len;
309156952Sume		break;
310156952Sume
311156952Sume	case ns_t_txt:
312269867Sume	case ns_t_spf:
313156952Sume		while (rdata < edata) {
314156952Sume			T(len = charstr(rdata, edata, &buf, &buflen));
315156952Sume			if (len == 0)
316156952Sume				goto formerr;
317156952Sume			rdata += len;
318156952Sume			if (rdata < edata)
319156952Sume				T(addstr(" ", 1, &buf, &buflen));
320156952Sume		}
321156952Sume		break;
322156952Sume
323156952Sume	case ns_t_nsap: {
324156952Sume		char t[2+255*3];
325156952Sume
326156952Sume		(void) inet_nsap_ntoa(rdlen, rdata, t);
327156952Sume		T(addstr(t, strlen(t), &buf, &buflen));
328156952Sume		break;
329156952Sume	    }
330156952Sume
331156952Sume	case ns_t_aaaa:
332156952Sume		if (rdlen != (size_t)NS_IN6ADDRSZ)
333156952Sume			goto formerr;
334156952Sume		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
335156952Sume		addlen(strlen(buf), &buf, &buflen);
336156952Sume		break;
337156952Sume
338156952Sume	case ns_t_loc: {
339156952Sume		char t[255];
340156952Sume
341156952Sume		/* XXX protocol format checking? */
342156952Sume		(void) loc_ntoa(rdata, t);
343156952Sume		T(addstr(t, strlen(t), &buf, &buflen));
344156952Sume		break;
345156952Sume	    }
346156952Sume
347156952Sume	case ns_t_naptr: {
348156952Sume		u_int order, preference;
349156952Sume		char t[50];
350156952Sume
351156952Sume		if (rdlen < 2U*NS_INT16SZ)
352156952Sume			goto formerr;
353156952Sume
354156952Sume		/* Order, Precedence. */
355156952Sume		order = ns_get16(rdata);	rdata += NS_INT16SZ;
356156952Sume		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
357156952Sume		len = SPRINTF((t, "%u %u ", order, preference));
358156952Sume		T(addstr(t, len, &buf, &buflen));
359156952Sume
360156952Sume		/* Flags. */
361156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
362156952Sume		if (len == 0)
363156952Sume			goto formerr;
364156952Sume		rdata += len;
365156952Sume		T(addstr(" ", 1, &buf, &buflen));
366156952Sume
367156952Sume		/* Service. */
368156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
369156952Sume		if (len == 0)
370156952Sume			goto formerr;
371156952Sume		rdata += len;
372156952Sume		T(addstr(" ", 1, &buf, &buflen));
373156952Sume
374156952Sume		/* Regexp. */
375156952Sume		T(len = charstr(rdata, edata, &buf, &buflen));
376156952Sume		if (len < 0)
377156952Sume			return (-1);
378156952Sume		if (len == 0)
379156952Sume			goto formerr;
380156952Sume		rdata += len;
381156952Sume		T(addstr(" ", 1, &buf, &buflen));
382156952Sume
383156952Sume		/* Server. */
384156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
385156952Sume		break;
386156952Sume	    }
387156952Sume
388156952Sume	case ns_t_srv: {
389156952Sume		u_int priority, weight, port;
390156952Sume		char t[50];
391156952Sume
392156952Sume		if (rdlen < 3U*NS_INT16SZ)
393156952Sume			goto formerr;
394156952Sume
395156952Sume		/* Priority, Weight, Port. */
396156952Sume		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
397156952Sume		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
398156952Sume		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
399156952Sume		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
400156952Sume		T(addstr(t, len, &buf, &buflen));
401156952Sume
402156952Sume		/* Server. */
403156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
404156952Sume		break;
405156952Sume	    }
406156952Sume
407156952Sume	case ns_t_minfo:
408156952Sume	case ns_t_rp:
409156952Sume		/* Name1. */
410156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
411156952Sume		T(addstr(" ", 1, &buf, &buflen));
412156952Sume
413156952Sume		/* Name2. */
414156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
415156952Sume
416156952Sume		break;
417156952Sume
418156952Sume	case ns_t_wks: {
419156952Sume		int n, lcnt;
420156952Sume
421156952Sume		if (rdlen < 1U + NS_INT32SZ)
422156952Sume			goto formerr;
423156952Sume
424156952Sume		/* Address. */
425156952Sume		(void) inet_ntop(AF_INET, rdata, buf, buflen);
426156952Sume		addlen(strlen(buf), &buf, &buflen);
427156952Sume		rdata += NS_INADDRSZ;
428156952Sume
429156952Sume		/* Protocol. */
430156952Sume		len = SPRINTF((tmp, " %u ( ", *rdata));
431156952Sume		T(addstr(tmp, len, &buf, &buflen));
432156952Sume		rdata += NS_INT8SZ;
433156952Sume
434156952Sume		/* Bit map. */
435156952Sume		n = 0;
436156952Sume		lcnt = 0;
437156952Sume		while (rdata < edata) {
438156952Sume			u_int c = *rdata++;
439156952Sume			do {
440156952Sume				if (c & 0200) {
441156952Sume					if (lcnt == 0) {
442156952Sume						T(addstr("\n\t\t\t\t", 5,
443156952Sume							 &buf, &buflen));
444156952Sume						lcnt = 10;
445156952Sume						spaced = 0;
446156952Sume					}
447156952Sume					len = SPRINTF((tmp, "%d ", n));
448156952Sume					T(addstr(tmp, len, &buf, &buflen));
449156952Sume					lcnt--;
450156952Sume				}
451156952Sume				c <<= 1;
452156952Sume			} while (++n & 07);
453156952Sume		}
454156952Sume		T(addstr(")", 1, &buf, &buflen));
455156952Sume
456156952Sume		break;
457156952Sume	    }
458156952Sume
459269867Sume	case ns_t_key:
460269867Sume	case ns_t_dnskey: {
461156952Sume		char base64_key[NS_MD5RSA_MAX_BASE64];
462156952Sume		u_int keyflags, protocol, algorithm, key_id;
463156952Sume		const char *leader;
464156952Sume		int n;
465156952Sume
466156952Sume		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
467156952Sume			goto formerr;
468156952Sume
469156952Sume		/* Key flags, Protocol, Algorithm. */
470156956Sume#ifndef _LIBC
471156952Sume		key_id = dst_s_dns_key_id(rdata, edata-rdata);
472156956Sume#else
473156956Sume		key_id = 0;
474156956Sume#endif
475156952Sume		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
476156952Sume		protocol = *rdata++;
477156952Sume		algorithm = *rdata++;
478156952Sume		len = SPRINTF((tmp, "0x%04x %u %u",
479156952Sume			       keyflags, protocol, algorithm));
480156952Sume		T(addstr(tmp, len, &buf, &buflen));
481156952Sume
482156952Sume		/* Public key data. */
483156952Sume		len = b64_ntop(rdata, edata - rdata,
484156952Sume			       base64_key, sizeof base64_key);
485156952Sume		if (len < 0)
486156952Sume			goto formerr;
487156952Sume		if (len > 15) {
488156952Sume			T(addstr(" (", 2, &buf, &buflen));
489156952Sume			leader = "\n\t\t";
490156952Sume			spaced = 0;
491156952Sume		} else
492156952Sume			leader = " ";
493156952Sume		for (n = 0; n < len; n += 48) {
494156952Sume			T(addstr(leader, strlen(leader), &buf, &buflen));
495156952Sume			T(addstr(base64_key + n, MIN(len - n, 48),
496156952Sume				 &buf, &buflen));
497156952Sume		}
498156952Sume		if (len > 15)
499156952Sume			T(addstr(" )", 2, &buf, &buflen));
500156952Sume		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
501156952Sume		T(addstr(tmp, n, &buf, &buflen));
502156952Sume
503156952Sume		break;
504156952Sume	    }
505156952Sume
506269867Sume	case ns_t_sig:
507269867Sume	case ns_t_rrsig: {
508156952Sume		char base64_key[NS_MD5RSA_MAX_BASE64];
509156952Sume		u_int type, algorithm, labels, footprint;
510156952Sume		const char *leader;
511156952Sume		u_long t;
512156952Sume		int n;
513156952Sume
514156952Sume		if (rdlen < 22U)
515156952Sume			goto formerr;
516156952Sume
517156952Sume		/* Type covered, Algorithm, Label count, Original TTL. */
518269867Sume		type = ns_get16(rdata);  rdata += NS_INT16SZ;
519156952Sume		algorithm = *rdata++;
520156952Sume		labels = *rdata++;
521156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
522156952Sume		len = SPRINTF((tmp, "%s %d %d %lu ",
523156952Sume			       p_type(type), algorithm, labels, t));
524156952Sume		T(addstr(tmp, len, &buf, &buflen));
525156952Sume		if (labels > (u_int)dn_count_labels(name))
526156952Sume			goto formerr;
527156952Sume
528156952Sume		/* Signature expiry. */
529156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
530156952Sume		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
531156952Sume		T(addstr(tmp, len, &buf, &buflen));
532156952Sume
533156952Sume		/* Time signed. */
534156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
535156952Sume		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
536156952Sume		T(addstr(tmp, len, &buf, &buflen));
537156952Sume
538156952Sume		/* Signature Footprint. */
539156952Sume		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
540156952Sume		len = SPRINTF((tmp, "%u ", footprint));
541156952Sume		T(addstr(tmp, len, &buf, &buflen));
542156952Sume
543156952Sume		/* Signer's name. */
544156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
545156952Sume
546156952Sume		/* Signature. */
547156952Sume		len = b64_ntop(rdata, edata - rdata,
548156952Sume			       base64_key, sizeof base64_key);
549156952Sume		if (len > 15) {
550156952Sume			T(addstr(" (", 2, &buf, &buflen));
551156952Sume			leader = "\n\t\t";
552156952Sume			spaced = 0;
553156952Sume		} else
554156952Sume			leader = " ";
555156952Sume		if (len < 0)
556156952Sume			goto formerr;
557156952Sume		for (n = 0; n < len; n += 48) {
558156952Sume			T(addstr(leader, strlen(leader), &buf, &buflen));
559156952Sume			T(addstr(base64_key + n, MIN(len - n, 48),
560156952Sume				 &buf, &buflen));
561156952Sume		}
562156952Sume		if (len > 15)
563156952Sume			T(addstr(" )", 2, &buf, &buflen));
564156952Sume		break;
565156952Sume	    }
566156952Sume
567156952Sume	case ns_t_nxt: {
568156952Sume		int n, c;
569156952Sume
570156952Sume		/* Next domain name. */
571156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
572156952Sume
573156952Sume		/* Type bit map. */
574156952Sume		n = edata - rdata;
575156952Sume		for (c = 0; c < n*8; c++)
576156952Sume			if (NS_NXT_BIT_ISSET(c, rdata)) {
577156952Sume				len = SPRINTF((tmp, " %s", p_type(c)));
578156952Sume				T(addstr(tmp, len, &buf, &buflen));
579156952Sume			}
580156952Sume		break;
581156952Sume	    }
582156952Sume
583156952Sume	case ns_t_cert: {
584156952Sume		u_int c_type, key_tag, alg;
585156952Sume		int n;
586156952Sume		unsigned int siz;
587156952Sume		char base64_cert[8192], tmp[40];
588156952Sume		const char *leader;
589156952Sume
590156952Sume		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
591156952Sume		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
592156952Sume		alg = (u_int) *rdata++;
593156952Sume
594156952Sume		len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
595156952Sume		T(addstr(tmp, len, &buf, &buflen));
596156952Sume		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
597156952Sume		if (siz > sizeof(base64_cert) * 3/4) {
598156952Sume			const char *str = "record too long to print";
599156952Sume			T(addstr(str, strlen(str), &buf, &buflen));
600156952Sume		}
601156952Sume		else {
602156952Sume			len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
603156952Sume
604156952Sume			if (len < 0)
605156952Sume				goto formerr;
606156952Sume			else if (len > 15) {
607156952Sume				T(addstr(" (", 2, &buf, &buflen));
608156952Sume				leader = "\n\t\t";
609156952Sume				spaced = 0;
610156952Sume			}
611156952Sume			else
612156952Sume				leader = " ";
613156952Sume
614156952Sume			for (n = 0; n < len; n += 48) {
615156952Sume				T(addstr(leader, strlen(leader),
616156952Sume					 &buf, &buflen));
617156952Sume				T(addstr(base64_cert + n, MIN(len - n, 48),
618156952Sume					 &buf, &buflen));
619156952Sume			}
620156952Sume			if (len > 15)
621156952Sume				T(addstr(" )", 2, &buf, &buflen));
622156952Sume		}
623156952Sume		break;
624156952Sume	    }
625156952Sume
626156952Sume	case ns_t_tkey: {
627156952Sume		/* KJD - need to complete this */
628156952Sume		u_long t;
629156952Sume		int mode, err, keysize;
630156952Sume
631156952Sume		/* Algorithm name. */
632156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
633156952Sume		T(addstr(" ", 1, &buf, &buflen));
634156952Sume
635156952Sume		/* Inception. */
636156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
637156952Sume		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
638156952Sume		T(addstr(tmp, len, &buf, &buflen));
639156952Sume
640156952Sume		/* Experation. */
641156952Sume		t = ns_get32(rdata);  rdata += NS_INT32SZ;
642156952Sume		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
643156952Sume		T(addstr(tmp, len, &buf, &buflen));
644156952Sume
645156952Sume		/* Mode , Error, Key Size. */
646156952Sume		/* Priority, Weight, Port. */
647156952Sume		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
648156952Sume		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
649156952Sume		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
650156952Sume		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
651156952Sume		T(addstr(tmp, len, &buf, &buflen));
652156952Sume
653156952Sume		/* XXX need to dump key, print otherdata length & other data */
654156952Sume		break;
655156952Sume	    }
656156952Sume
657156952Sume	case ns_t_tsig: {
658156952Sume		/* BEW - need to complete this */
659156952Sume		int n;
660156952Sume
661156952Sume		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
662156952Sume		T(addstr(" ", 1, &buf, &buflen));
663170244Sume		rdata += 8; /*%< time */
664156952Sume		n = ns_get16(rdata); rdata += INT16SZ;
665170244Sume		rdata += n; /*%< sig */
666170244Sume		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
667156952Sume		sprintf(buf, "%d", ns_get16(rdata));
668156952Sume		rdata += INT16SZ;
669156952Sume		addlen(strlen(buf), &buf, &buflen);
670156952Sume		break;
671156952Sume	    }
672156952Sume
673156952Sume	case ns_t_a6: {
674156952Sume		struct in6_addr a;
675156952Sume		int pbyte, pbit;
676156952Sume
677156952Sume		/* prefix length */
678156952Sume		if (rdlen == 0U) goto formerr;
679156952Sume		len = SPRINTF((tmp, "%d ", *rdata));
680156952Sume		T(addstr(tmp, len, &buf, &buflen));
681156952Sume		pbit = *rdata;
682156952Sume		if (pbit > 128) goto formerr;
683156952Sume		pbyte = (pbit & ~7) / 8;
684156952Sume		rdata++;
685156952Sume
686156952Sume		/* address suffix: provided only when prefix len != 128 */
687156952Sume		if (pbit < 128) {
688156952Sume			if (rdata + pbyte >= edata) goto formerr;
689156952Sume			memset(&a, 0, sizeof(a));
690156952Sume			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
691156952Sume			(void) inet_ntop(AF_INET6, &a, buf, buflen);
692156952Sume			addlen(strlen(buf), &buf, &buflen);
693156952Sume			rdata += sizeof(a) - pbyte;
694156952Sume		}
695156952Sume
696156952Sume		/* prefix name: provided only when prefix len > 0 */
697156952Sume		if (pbit == 0)
698156952Sume			break;
699156952Sume		if (rdata >= edata) goto formerr;
700156952Sume		T(addstr(" ", 1, &buf, &buflen));
701156952Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
702156952Sume
703156952Sume		break;
704156952Sume	    }
705156952Sume
706156952Sume	case ns_t_opt: {
707156952Sume		len = SPRINTF((tmp, "%u bytes", class));
708156952Sume		T(addstr(tmp, len, &buf, &buflen));
709156952Sume		break;
710156952Sume	    }
711156952Sume
712269867Sume	case ns_t_ds:
713269867Sume	case ns_t_dlv:
714269867Sume	case ns_t_sshfp: {
715269867Sume		u_int t;
716269867Sume
717269867Sume		if (type == ns_t_ds || type == ns_t_dlv) {
718269867Sume			if (rdlen < 4U) goto formerr;
719269867Sume			t = ns_get16(rdata);
720269867Sume			rdata += NS_INT16SZ;
721269867Sume			len = SPRINTF((tmp, "%u ", t));
722269867Sume			T(addstr(tmp, len, &buf, &buflen));
723269867Sume		} else
724269867Sume			if (rdlen < 2U) goto formerr;
725269867Sume
726269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
727269867Sume		T(addstr(tmp, len, &buf, &buflen));
728269867Sume		rdata++;
729269867Sume
730269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
731269867Sume		T(addstr(tmp, len, &buf, &buflen));
732269867Sume		rdata++;
733269867Sume
734269867Sume		while (rdata < edata) {
735269867Sume			len = SPRINTF((tmp, "%02X", *rdata));
736269867Sume			T(addstr(tmp, len, &buf, &buflen));
737269867Sume			rdata++;
738269867Sume		}
739269867Sume		break;
740269867Sume	    }
741269867Sume
742269867Sume	case ns_t_nsec3:
743269867Sume	case ns_t_nsec3param: {
744269867Sume		u_int t, w, l, j, k, c;
745269867Sume
746269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
747269867Sume		T(addstr(tmp, len, &buf, &buflen));
748269867Sume		rdata++;
749269867Sume
750269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
751269867Sume		T(addstr(tmp, len, &buf, &buflen));
752269867Sume		rdata++;
753269867Sume
754269867Sume		t = ns_get16(rdata);
755269867Sume		rdata += NS_INT16SZ;
756269867Sume		len = SPRINTF((tmp, "%u ", t));
757269867Sume		T(addstr(tmp, len, &buf, &buflen));
758269867Sume
759269867Sume		t = *rdata++;
760269867Sume		if (t == 0) {
761269867Sume			T(addstr("-", 1, &buf, &buflen));
762269867Sume		} else {
763269867Sume			while (t-- > 0) {
764269867Sume				len = SPRINTF((tmp, "%02X", *rdata));
765269867Sume				T(addstr(tmp, len, &buf, &buflen));
766269867Sume				rdata++;
767269867Sume			}
768269867Sume		}
769269867Sume		if (type == ns_t_nsec3param)
770269867Sume			break;
771269867Sume		T(addstr(" ", 1, &buf, &buflen));
772269867Sume
773269867Sume		t = *rdata++;
774269867Sume		while (t > 0) {
775269867Sume			switch (t) {
776269867Sume			case 1:
777269867Sume				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
778269867Sume				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
779269867Sume				tmp[2] = tmp[3] = tmp[4] = '=';
780269867Sume				tmp[5] = tmp[6] = tmp[7] = '=';
781269867Sume				break;
782269867Sume			case 2:
783269867Sume				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
784269867Sume				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
785269867Sume						   ((rdata[1]>>6)&0x03)];
786269867Sume				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
787269867Sume				tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
788269867Sume				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
789269867Sume				break;
790269867Sume			case 3:
791269867Sume				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
792269867Sume				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
793269867Sume						   ((rdata[1]>>6)&0x03)];
794269867Sume				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
795269867Sume				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
796269867Sume						   ((rdata[2]>>4)&0x0f)];
797269867Sume				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
798269867Sume				tmp[5] = tmp[6] = tmp[7] = '=';
799269867Sume				break;
800269867Sume			case 4:
801269867Sume				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
802269867Sume				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
803269867Sume						   ((rdata[1]>>6)&0x03)];
804269867Sume				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
805269867Sume				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
806269867Sume						   ((rdata[2]>>4)&0x0f)];
807269867Sume				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
808269867Sume						   ((rdata[3]>>7)&0x01)];
809269867Sume				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
810269867Sume				tmp[6] = base32hex[(rdata[3]<<3)&0x18];
811269867Sume				tmp[7] = '=';
812269867Sume				break;
813269867Sume			default:
814269867Sume				tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
815269867Sume				tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
816269867Sume						   ((rdata[1]>>6)&0x03)];
817269867Sume				tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
818269867Sume				tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
819269867Sume						   ((rdata[2]>>4)&0x0f)];
820269867Sume				tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
821269867Sume						   ((rdata[3]>>7)&0x01)];
822269867Sume				tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
823269867Sume				tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
824269867Sume						   ((rdata[4]>>5)&0x07)];
825269867Sume				tmp[7] = base32hex[(rdata[4]&0x1f)];
826269867Sume				break;
827269867Sume			}
828269867Sume			T(addstr(tmp, 8, &buf, &buflen));
829269867Sume			if (t >= 5) {
830269867Sume				rdata += 5;
831269867Sume				t -= 5;
832269867Sume			} else {
833269867Sume				rdata += t;
834269867Sume				t -= t;
835269867Sume			}
836269867Sume		}
837269867Sume
838269867Sume		while (rdata < edata) {
839269867Sume			w = *rdata++;
840269867Sume			l = *rdata++;
841269867Sume			for (j = 0; j < l; j++) {
842269867Sume				if (rdata[j] == 0)
843269867Sume					continue;
844269867Sume				for (k = 0; k < 8; k++) {
845269867Sume					if ((rdata[j] & (0x80 >> k)) == 0)
846269867Sume						continue;
847269867Sume					c = w * 256 + j * 8 + k;
848269867Sume					len = SPRINTF((tmp, " %s", p_type(c)));
849269867Sume					T(addstr(tmp, len, &buf, &buflen));
850269867Sume				}
851269867Sume			}
852269867Sume			rdata += l;
853269867Sume		}
854269867Sume		break;
855269867Sume	    }
856269867Sume
857269867Sume	case ns_t_nsec: {
858269867Sume		u_int w, l, j, k, c;
859269867Sume
860269867Sume		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
861269867Sume
862269867Sume		while (rdata < edata) {
863269867Sume			w = *rdata++;
864269867Sume			l = *rdata++;
865269867Sume			for (j = 0; j < l; j++) {
866269867Sume				if (rdata[j] == 0)
867269867Sume					continue;
868269867Sume				for (k = 0; k < 8; k++) {
869269867Sume					if ((rdata[j] & (0x80 >> k)) == 0)
870269867Sume						continue;
871269867Sume					c = w * 256 + j * 8 + k;
872269867Sume					len = SPRINTF((tmp, " %s", p_type(c)));
873269867Sume					T(addstr(tmp, len, &buf, &buflen));
874269867Sume				}
875269867Sume			}
876269867Sume			rdata += l;
877269867Sume		}
878269867Sume		break;
879269867Sume	    }
880269867Sume
881269867Sume	case ns_t_dhcid: {
882269867Sume		int n;
883269867Sume		unsigned int siz;
884269867Sume		char base64_dhcid[8192];
885269867Sume		const char *leader;
886269867Sume
887269867Sume		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
888269867Sume		if (siz > sizeof(base64_dhcid) * 3/4) {
889269867Sume			const char *str = "record too long to print";
890269867Sume			T(addstr(str, strlen(str), &buf, &buflen));
891269867Sume		} else {
892269867Sume			len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
893269867Sume
894269867Sume			if (len < 0)
895269867Sume				goto formerr;
896269867Sume
897269867Sume			else if (len > 15) {
898269867Sume				T(addstr(" (", 2, &buf, &buflen));
899269867Sume				leader = "\n\t\t";
900269867Sume				spaced = 0;
901269867Sume			}
902269867Sume			else
903269867Sume				leader = " ";
904269867Sume
905269867Sume			for (n = 0; n < len; n += 48) {
906269867Sume				T(addstr(leader, strlen(leader),
907269867Sume					 &buf, &buflen));
908269867Sume				T(addstr(base64_dhcid + n, MIN(len - n, 48),
909269867Sume					 &buf, &buflen));
910269867Sume			}
911269867Sume			if (len > 15)
912269867Sume				T(addstr(" )", 2, &buf, &buflen));
913269867Sume		}
914270215Spfg		break;
915269867Sume	}
916269867Sume
917269867Sume	case ns_t_ipseckey: {
918269867Sume		int n;
919269867Sume		unsigned int siz;
920269867Sume		char base64_key[8192];
921269867Sume		const char *leader;
922269867Sume
923269867Sume		if (rdlen < 2)
924269867Sume			goto formerr;
925269867Sume
926269867Sume		switch (rdata[1]) {
927269867Sume		case 0:
928269867Sume		case 3:
929269867Sume			if (rdlen < 3)
930269867Sume				goto formerr;
931269867Sume			break;
932269867Sume		case 1:
933269867Sume			if (rdlen < 7)
934269867Sume				goto formerr;
935269867Sume			break;
936269867Sume		case 2:
937269867Sume			if (rdlen < 19)
938269867Sume				goto formerr;
939269867Sume			break;
940269867Sume		default:
941269867Sume			comment = "unknown IPSECKEY gateway type";
942269867Sume			goto hexify;
943269867Sume		}
944269867Sume
945269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
946269867Sume		T(addstr(tmp, len, &buf, &buflen));
947269867Sume		rdata++;
948269867Sume
949269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
950269867Sume		T(addstr(tmp, len, &buf, &buflen));
951269867Sume		rdata++;
952269867Sume
953269867Sume		len = SPRINTF((tmp, "%u ", *rdata));
954269867Sume		T(addstr(tmp, len, &buf, &buflen));
955269867Sume		rdata++;
956269867Sume
957269867Sume		switch (rdata[-2]) {
958269867Sume		case 0:
959269867Sume			T(addstr(".", 1, &buf, &buflen));
960269867Sume			break;
961269867Sume		case 1:
962269867Sume			(void) inet_ntop(AF_INET, rdata, buf, buflen);
963269867Sume			addlen(strlen(buf), &buf, &buflen);
964269867Sume			rdata += 4;
965269867Sume			break;
966269867Sume		case 2:
967269867Sume			(void) inet_ntop(AF_INET6, rdata, buf, buflen);
968269867Sume			addlen(strlen(buf), &buf, &buflen);
969269867Sume			rdata += 16;
970269867Sume			break;
971269867Sume		case 3:
972269867Sume			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
973269867Sume			break;
974269867Sume		}
975269867Sume
976269867Sume		if (rdata >= edata)
977269867Sume			break;
978269867Sume
979269867Sume		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
980269867Sume		if (siz > sizeof(base64_key) * 3/4) {
981269867Sume			const char *str = "record too long to print";
982269867Sume			T(addstr(str, strlen(str), &buf, &buflen));
983269867Sume		} else {
984269867Sume			len = b64_ntop(rdata, edata-rdata, base64_key, siz);
985269867Sume
986269867Sume			if (len < 0)
987269867Sume				goto formerr;
988269867Sume
989269867Sume			else if (len > 15) {
990269867Sume				T(addstr(" (", 2, &buf, &buflen));
991269867Sume				leader = "\n\t\t";
992269867Sume				spaced = 0;
993269867Sume			}
994269867Sume			else
995269867Sume				leader = " ";
996269867Sume
997269867Sume			for (n = 0; n < len; n += 48) {
998269867Sume				T(addstr(leader, strlen(leader),
999269867Sume					 &buf, &buflen));
1000269867Sume				T(addstr(base64_key + n, MIN(len - n, 48),
1001269867Sume					 &buf, &buflen));
1002269867Sume			}
1003269867Sume			if (len > 15)
1004269867Sume				T(addstr(" )", 2, &buf, &buflen));
1005269867Sume		}
1006269867Sume	}
1007269867Sume
1008269867Sume	case ns_t_hip: {
1009269867Sume		unsigned int i, hip_len, algorithm, key_len;
1010269867Sume		char base64_key[NS_MD5RSA_MAX_BASE64];
1011269867Sume		unsigned int siz;
1012269867Sume		const char *leader = "\n\t\t\t\t\t";
1013269867Sume
1014269867Sume		hip_len = *rdata++;
1015269867Sume		algorithm = *rdata++;
1016269867Sume		key_len = ns_get16(rdata);
1017269867Sume		rdata += NS_INT16SZ;
1018269867Sume
1019269867Sume		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
1020269867Sume		if (siz > sizeof(base64_key) * 3/4) {
1021269867Sume			const char *str = "record too long to print";
1022269867Sume			T(addstr(str, strlen(str), &buf, &buflen));
1023269867Sume		} else {
1024269867Sume			len = sprintf(tmp, "( %u ", algorithm);
1025269867Sume			T(addstr(tmp, len, &buf, &buflen));
1026269867Sume
1027269867Sume			for (i = 0; i < hip_len; i++) {
1028269867Sume				len = sprintf(tmp, "%02X", *rdata);
1029269867Sume				T(addstr(tmp, len, &buf, &buflen));
1030269867Sume				rdata++;
1031269867Sume			}
1032269867Sume			T(addstr(leader, strlen(leader), &buf, &buflen));
1033269867Sume
1034269867Sume			len = b64_ntop(rdata, key_len, base64_key, siz);
1035269867Sume			if (len < 0)
1036269867Sume				goto formerr;
1037269867Sume
1038269867Sume			T(addstr(base64_key, len, &buf, &buflen));
1039269867Sume
1040269867Sume			rdata += key_len;
1041269867Sume			while (rdata < edata) {
1042269867Sume				T(addstr(leader, strlen(leader), &buf, &buflen));
1043269867Sume				T(addname(msg, msglen, &rdata, origin,
1044269867Sume					  &buf, &buflen));
1045269867Sume			}
1046269867Sume			T(addstr(" )", 2, &buf, &buflen));
1047269867Sume		}
1048269867Sume		break;
1049269867Sume	}
1050269867Sume
1051156952Sume	default:
1052156952Sume		comment = "unknown RR type";
1053156952Sume		goto hexify;
1054156952Sume	}
1055156952Sume	return (buf - obuf);
1056156952Sume formerr:
1057156952Sume	comment = "RR format error";
1058156952Sume hexify: {
1059156952Sume	int n, m;
1060156952Sume	char *p;
1061156952Sume
1062156952Sume	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
1063156952Sume		       rdlen != 0U ? " (" : "", comment));
1064156952Sume	T(addstr(tmp, len, &buf, &buflen));
1065156952Sume	while (rdata < edata) {
1066156952Sume		p = tmp;
1067156952Sume		p += SPRINTF((p, "\n\t"));
1068156952Sume		spaced = 0;
1069156952Sume		n = MIN(16, edata - rdata);
1070156952Sume		for (m = 0; m < n; m++)
1071156952Sume			p += SPRINTF((p, "%02x ", rdata[m]));
1072156952Sume		T(addstr(tmp, p - tmp, &buf, &buflen));
1073156952Sume		if (n < 16) {
1074156952Sume			T(addstr(")", 1, &buf, &buflen));
1075156952Sume			T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
1076156952Sume		}
1077156952Sume		p = tmp;
1078156952Sume		p += SPRINTF((p, "; "));
1079156952Sume		for (m = 0; m < n; m++)
1080156952Sume			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
1081156952Sume				? rdata[m]
1082156952Sume				: '.';
1083156952Sume		T(addstr(tmp, p - tmp, &buf, &buflen));
1084156952Sume		rdata += n;
1085156952Sume	}
1086156952Sume	return (buf - obuf);
1087156952Sume    }
1088156952Sume}
1089156952Sume
1090156952Sume/* Private. */
1091156952Sume
1092170244Sume/*%
1093156952Sume * size_t
1094156952Sume * prune_origin(name, origin)
1095156952Sume *	Find out if the name is at or under the current origin.
1096156952Sume * return:
1097156952Sume *	Number of characters in name before start of origin,
1098156952Sume *	or length of name if origin does not match.
1099156952Sume * notes:
1100156952Sume *	This function should share code with samedomain().
1101156952Sume */
1102156952Sumestatic size_t
1103156952Sumeprune_origin(const char *name, const char *origin) {
1104156952Sume	const char *oname = name;
1105156952Sume
1106156952Sume	while (*name != '\0') {
1107156952Sume		if (origin != NULL && ns_samename(name, origin) == 1)
1108156952Sume			return (name - oname - (name > oname));
1109156952Sume		while (*name != '\0') {
1110156952Sume			if (*name == '\\') {
1111156952Sume				name++;
1112156952Sume				/* XXX need to handle \nnn form. */
1113156952Sume				if (*name == '\0')
1114156952Sume					break;
1115156952Sume			} else if (*name == '.') {
1116156952Sume				name++;
1117156952Sume				break;
1118156952Sume			}
1119156952Sume			name++;
1120156952Sume		}
1121156952Sume	}
1122156952Sume	return (name - oname);
1123156952Sume}
1124156952Sume
1125170244Sume/*%
1126156952Sume * int
1127156952Sume * charstr(rdata, edata, buf, buflen)
1128156952Sume *	Format a <character-string> into the presentation buffer.
1129156952Sume * return:
1130156952Sume *	Number of rdata octets consumed
1131156952Sume *	0 for protocol format error
1132156952Sume *	-1 for output buffer error
1133156952Sume * side effects:
1134156952Sume *	buffer is advanced on success.
1135156952Sume */
1136156952Sumestatic int
1137156952Sumecharstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
1138156952Sume	const u_char *odata = rdata;
1139156952Sume	size_t save_buflen = *buflen;
1140156952Sume	char *save_buf = *buf;
1141156952Sume
1142156952Sume	if (addstr("\"", 1, buf, buflen) < 0)
1143156952Sume		goto enospc;
1144156952Sume	if (rdata < edata) {
1145156952Sume		int n = *rdata;
1146156952Sume
1147156952Sume		if (rdata + 1 + n <= edata) {
1148156952Sume			rdata++;
1149156952Sume			while (n-- > 0) {
1150156952Sume				if (strchr("\n\"\\", *rdata) != NULL)
1151156952Sume					if (addstr("\\", 1, buf, buflen) < 0)
1152156952Sume						goto enospc;
1153156952Sume				if (addstr((const char *)rdata, 1,
1154156952Sume					   buf, buflen) < 0)
1155156952Sume					goto enospc;
1156156952Sume				rdata++;
1157156952Sume			}
1158156952Sume		}
1159156952Sume	}
1160156952Sume	if (addstr("\"", 1, buf, buflen) < 0)
1161156952Sume		goto enospc;
1162156952Sume	return (rdata - odata);
1163156952Sume enospc:
1164156952Sume	errno = ENOSPC;
1165156952Sume	*buf = save_buf;
1166156952Sume	*buflen = save_buflen;
1167156952Sume	return (-1);
1168156952Sume}
1169156952Sume
1170156952Sumestatic int
1171156952Sumeaddname(const u_char *msg, size_t msglen,
1172156952Sume	const u_char **pp, const char *origin,
1173156952Sume	char **buf, size_t *buflen)
1174156952Sume{
1175156952Sume	size_t newlen, save_buflen = *buflen;
1176156952Sume	char *save_buf = *buf;
1177156952Sume	int n;
1178156952Sume
1179156952Sume	n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
1180156952Sume	if (n < 0)
1181170244Sume		goto enospc;	/*%< Guess. */
1182156952Sume	newlen = prune_origin(*buf, origin);
1183156952Sume	if (**buf == '\0') {
1184156952Sume		goto root;
1185156952Sume	} else if (newlen == 0U) {
1186156952Sume		/* Use "@" instead of name. */
1187156952Sume		if (newlen + 2 > *buflen)
1188156952Sume			goto enospc;        /* No room for "@\0". */
1189156952Sume		(*buf)[newlen++] = '@';
1190156952Sume		(*buf)[newlen] = '\0';
1191156952Sume	} else {
1192156952Sume		if (((origin == NULL || origin[0] == '\0') ||
1193156952Sume		    (origin[0] != '.' && origin[1] != '\0' &&
1194156952Sume		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
1195156952Sume			/* No trailing dot. */
1196156952Sume root:
1197156952Sume			if (newlen + 2 > *buflen)
1198156952Sume				goto enospc;	/* No room for ".\0". */
1199156952Sume			(*buf)[newlen++] = '.';
1200156952Sume			(*buf)[newlen] = '\0';
1201156952Sume		}
1202156952Sume	}
1203156952Sume	*pp += n;
1204156952Sume	addlen(newlen, buf, buflen);
1205156952Sume	**buf = '\0';
1206156952Sume	return (newlen);
1207156952Sume enospc:
1208156952Sume	errno = ENOSPC;
1209156952Sume	*buf = save_buf;
1210156952Sume	*buflen = save_buflen;
1211156952Sume	return (-1);
1212156952Sume}
1213156952Sume
1214156952Sumestatic void
1215156952Sumeaddlen(size_t len, char **buf, size_t *buflen) {
1216156952Sume	INSIST(len <= *buflen);
1217156952Sume	*buf += len;
1218156952Sume	*buflen -= len;
1219156952Sume}
1220156952Sume
1221156952Sumestatic int
1222156952Sumeaddstr(const char *src, size_t len, char **buf, size_t *buflen) {
1223156952Sume	if (len >= *buflen) {
1224156952Sume		errno = ENOSPC;
1225156952Sume		return (-1);
1226156952Sume	}
1227156952Sume	memcpy(*buf, src, len);
1228156952Sume	addlen(len, buf, buflen);
1229156952Sume	**buf = '\0';
1230156952Sume	return (0);
1231156952Sume}
1232156952Sume
1233156952Sumestatic int
1234156952Sumeaddtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
1235156952Sume	size_t save_buflen = *buflen;
1236156952Sume	char *save_buf = *buf;
1237156952Sume	int t;
1238156952Sume
1239156952Sume	if (spaced || len >= target - 1) {
1240156952Sume		T(addstr("  ", 2, buf, buflen));
1241156952Sume		spaced = 1;
1242156952Sume	} else {
1243156952Sume		for (t = (target - len - 1) / 8; t >= 0; t--)
1244156952Sume			if (addstr("\t", 1, buf, buflen) < 0) {
1245156952Sume				*buflen = save_buflen;
1246156952Sume				*buf = save_buf;
1247156952Sume				return (-1);
1248156952Sume			}
1249156952Sume		spaced = 0;
1250156952Sume	}
1251156952Sume	return (spaced);
1252156952Sume}
1253170244Sume
1254170244Sume/*! \file */
1255