xref: /minix/lib/libc/nameser/ns_print.c (revision f14fb602)
1*f14fb602SLionel Sambuc /*	$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52fe8fb19SBen Gras  * Copyright (c) 1996-1999 by Internet Software Consortium.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Permission to use, copy, modify, and distribute this software for any
82fe8fb19SBen Gras  * purpose with or without fee is hereby granted, provided that the above
92fe8fb19SBen Gras  * copyright notice and this permission notice appear in all copies.
102fe8fb19SBen Gras  *
112fe8fb19SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
122fe8fb19SBen Gras  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
132fe8fb19SBen Gras  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
142fe8fb19SBen Gras  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
152fe8fb19SBen Gras  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
162fe8fb19SBen Gras  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
172fe8fb19SBen Gras  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182fe8fb19SBen Gras  */
192fe8fb19SBen Gras 
202fe8fb19SBen Gras #include <sys/cdefs.h>
212fe8fb19SBen Gras #ifndef lint
222fe8fb19SBen Gras #ifdef notdef
232fe8fb19SBen Gras static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp";
242fe8fb19SBen Gras #else
25*f14fb602SLionel Sambuc __RCSID("$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 christos Exp $");
262fe8fb19SBen Gras #endif
272fe8fb19SBen Gras #endif
282fe8fb19SBen Gras 
292fe8fb19SBen Gras /* Import. */
302fe8fb19SBen Gras 
312fe8fb19SBen Gras #include "port_before.h"
322fe8fb19SBen Gras 
332fe8fb19SBen Gras #include <sys/types.h>
342fe8fb19SBen Gras #include <sys/socket.h>
352fe8fb19SBen Gras 
362fe8fb19SBen Gras #include <netinet/in.h>
372fe8fb19SBen Gras #include <arpa/nameser.h>
382fe8fb19SBen Gras #include <arpa/inet.h>
392fe8fb19SBen Gras 
402fe8fb19SBen Gras #include <isc/assertions.h>
412fe8fb19SBen Gras #include <isc/dst.h>
42*f14fb602SLionel Sambuc #include <assert.h>
432fe8fb19SBen Gras #include <errno.h>
442fe8fb19SBen Gras #include <resolv.h>
45*f14fb602SLionel Sambuc #include <stddef.h>
462fe8fb19SBen Gras #include <string.h>
472fe8fb19SBen Gras #include <ctype.h>
482fe8fb19SBen Gras 
492fe8fb19SBen Gras #include "port_after.h"
502fe8fb19SBen Gras 
512fe8fb19SBen Gras #ifdef SPRINTF_CHAR
52*f14fb602SLionel Sambuc # define SPRINTF(x) ((int)strlen(sprintf/**/x))
532fe8fb19SBen Gras #else
54*f14fb602SLionel Sambuc # define SPRINTF(x) (sprintf x)
552fe8fb19SBen Gras #endif
562fe8fb19SBen Gras 
572fe8fb19SBen Gras /* Forward. */
582fe8fb19SBen Gras 
592fe8fb19SBen Gras static size_t	prune_origin(const char *name, const char *origin);
602fe8fb19SBen Gras static int	charstr(const u_char *rdata, const u_char *edata,
612fe8fb19SBen Gras 			char **buf, size_t *buflen);
622fe8fb19SBen Gras static int	addname(const u_char *msg, size_t msglen,
632fe8fb19SBen Gras 			const u_char **p, const char *origin,
642fe8fb19SBen Gras 			char **buf, size_t *buflen);
652fe8fb19SBen Gras static void	addlen(size_t len, char **buf, size_t *buflen);
662fe8fb19SBen Gras static int	addstr(const char *src, size_t len,
672fe8fb19SBen Gras 		       char **buf, size_t *buflen);
682fe8fb19SBen Gras static int	addtab(size_t len, size_t target, int spaced,
692fe8fb19SBen Gras 		       char **buf, size_t *buflen);
702fe8fb19SBen Gras 
712fe8fb19SBen Gras /* Macros. */
722fe8fb19SBen Gras 
732fe8fb19SBen Gras #define	T(x) \
742fe8fb19SBen Gras 	do { \
752fe8fb19SBen Gras 		if ((x) < 0) \
762fe8fb19SBen Gras 			return (-1); \
772fe8fb19SBen Gras 	} while (/*CONSTCOND*/0)
782fe8fb19SBen Gras 
792fe8fb19SBen Gras static const char base32hex[] =
802fe8fb19SBen Gras         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
812fe8fb19SBen Gras 
822fe8fb19SBen Gras /* Public. */
832fe8fb19SBen Gras 
842fe8fb19SBen Gras /*%
852fe8fb19SBen Gras  *	Convert an RR to presentation format.
862fe8fb19SBen Gras  *
872fe8fb19SBen Gras  * return:
882fe8fb19SBen Gras  *\li	Number of characters written to buf, or -1 (check errno).
892fe8fb19SBen Gras  */
902fe8fb19SBen Gras int
ns_sprintrr(const ns_msg * handle,const ns_rr * rr,const char * name_ctx,const char * origin,char * buf,size_t buflen)912fe8fb19SBen Gras ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
922fe8fb19SBen Gras 	    const char *name_ctx, const char *origin,
932fe8fb19SBen Gras 	    char *buf, size_t buflen)
942fe8fb19SBen Gras {
952fe8fb19SBen Gras 	int n;
962fe8fb19SBen Gras 
972fe8fb19SBen Gras 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
982fe8fb19SBen Gras 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
992fe8fb19SBen Gras 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
1002fe8fb19SBen Gras 			 name_ctx, origin, buf, buflen);
1012fe8fb19SBen Gras 	return (n);
1022fe8fb19SBen Gras }
1032fe8fb19SBen Gras 
1042fe8fb19SBen Gras /*%
1052fe8fb19SBen Gras  *	Convert the fields of an RR into presentation format.
1062fe8fb19SBen Gras  *
1072fe8fb19SBen Gras  * return:
1082fe8fb19SBen Gras  *\li	Number of characters written to buf, or -1 (check errno).
1092fe8fb19SBen Gras  */
1102fe8fb19SBen Gras 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)1112fe8fb19SBen Gras ns_sprintrrf(const u_char *msg, size_t msglen,
1122fe8fb19SBen Gras 	    const char *name, ns_class class, ns_type type,
1132fe8fb19SBen Gras 	    u_long ttl, const u_char *rdata, size_t rdlen,
1142fe8fb19SBen Gras 	    const char *name_ctx, const char *origin,
1152fe8fb19SBen Gras 	    char *buf, size_t buflen)
1162fe8fb19SBen Gras {
1172fe8fb19SBen Gras 	const char *obuf = buf;
1182fe8fb19SBen Gras 	const u_char *edata = rdata + rdlen;
1192fe8fb19SBen Gras 	int spaced = 0;
1202fe8fb19SBen Gras 
1212fe8fb19SBen Gras 	const char *comment;
1222fe8fb19SBen Gras 	char tmp[100];
1232fe8fb19SBen Gras 	int len, x;
1242fe8fb19SBen Gras 
1252fe8fb19SBen Gras 	/*
1262fe8fb19SBen Gras 	 * Owner.
1272fe8fb19SBen Gras 	 */
1282fe8fb19SBen Gras 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
1292fe8fb19SBen Gras 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
1302fe8fb19SBen Gras 	} else {
131*f14fb602SLionel Sambuc 		len = (int)prune_origin(name, origin);
1322fe8fb19SBen Gras 		if (*name == '\0') {
1332fe8fb19SBen Gras 			goto root;
1342fe8fb19SBen Gras 		} else if (len == 0) {
1352fe8fb19SBen Gras 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
1362fe8fb19SBen Gras 		} else {
1372fe8fb19SBen Gras 			T(addstr(name, (size_t)len, &buf, &buflen));
1382fe8fb19SBen Gras 			/* Origin not used or not root, and no trailing dot? */
1392fe8fb19SBen Gras 			if (((origin == NULL || origin[0] == '\0') ||
1402fe8fb19SBen Gras 			    (origin[0] != '.' && origin[1] != '\0' &&
1412fe8fb19SBen Gras 			    name[len] == '\0')) && name[len - 1] != '.') {
1422fe8fb19SBen Gras  root:
1432fe8fb19SBen Gras 				T(addstr(".", (size_t)1, &buf, &buflen));
1442fe8fb19SBen Gras 				len++;
1452fe8fb19SBen Gras 			}
1462fe8fb19SBen Gras 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
1472fe8fb19SBen Gras 		}
1482fe8fb19SBen Gras 	}
1492fe8fb19SBen Gras 
1502fe8fb19SBen Gras 	/*
1512fe8fb19SBen Gras 	 * TTL, Class, Type.
1522fe8fb19SBen Gras 	 */
1532fe8fb19SBen Gras 	T(x = ns_format_ttl(ttl, buf, buflen));
1542fe8fb19SBen Gras 	addlen((size_t)x, &buf, &buflen);
1552fe8fb19SBen Gras 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
1562fe8fb19SBen Gras 	T(addstr(tmp, (size_t)len, &buf, &buflen));
1572fe8fb19SBen Gras 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
1582fe8fb19SBen Gras 
1592fe8fb19SBen Gras 	/*
1602fe8fb19SBen Gras 	 * RData.
1612fe8fb19SBen Gras 	 */
1622fe8fb19SBen Gras 	switch (type) {
1632fe8fb19SBen Gras 	case ns_t_a:
1642fe8fb19SBen Gras 		if (rdlen != (size_t)NS_INADDRSZ)
1652fe8fb19SBen Gras 			goto formerr;
166*f14fb602SLionel Sambuc 		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
1672fe8fb19SBen Gras 		addlen(strlen(buf), &buf, &buflen);
1682fe8fb19SBen Gras 		break;
1692fe8fb19SBen Gras 
1702fe8fb19SBen Gras 	case ns_t_cname:
1712fe8fb19SBen Gras 	case ns_t_mb:
1722fe8fb19SBen Gras 	case ns_t_mg:
1732fe8fb19SBen Gras 	case ns_t_mr:
1742fe8fb19SBen Gras 	case ns_t_ns:
1752fe8fb19SBen Gras 	case ns_t_ptr:
1762fe8fb19SBen Gras 	case ns_t_dname:
1772fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
1782fe8fb19SBen Gras 		break;
1792fe8fb19SBen Gras 
1802fe8fb19SBen Gras 	case ns_t_hinfo:
1812fe8fb19SBen Gras 	case ns_t_isdn:
1822fe8fb19SBen Gras 		/* First word. */
1832fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
1842fe8fb19SBen Gras 		if (len == 0)
1852fe8fb19SBen Gras 			goto formerr;
1862fe8fb19SBen Gras 		rdata += len;
1872fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
1882fe8fb19SBen Gras 
1892fe8fb19SBen Gras 
1902fe8fb19SBen Gras 		/* Second word, optional in ISDN records. */
1912fe8fb19SBen Gras 		if (type == ns_t_isdn && rdata == edata)
1922fe8fb19SBen Gras 			break;
1932fe8fb19SBen Gras 
1942fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
1952fe8fb19SBen Gras 		if (len == 0)
1962fe8fb19SBen Gras 			goto formerr;
1972fe8fb19SBen Gras 		rdata += len;
1982fe8fb19SBen Gras 		break;
1992fe8fb19SBen Gras 
2002fe8fb19SBen Gras 	case ns_t_soa: {
2012fe8fb19SBen Gras 		u_long t;
2022fe8fb19SBen Gras 
2032fe8fb19SBen Gras 		/* Server name. */
2042fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2052fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
2062fe8fb19SBen Gras 
2072fe8fb19SBen Gras 		/* Administrator name. */
2082fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2092fe8fb19SBen Gras 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
2102fe8fb19SBen Gras 		spaced = 0;
2112fe8fb19SBen Gras 
2122fe8fb19SBen Gras 		if ((edata - rdata) != 5*NS_INT32SZ)
2132fe8fb19SBen Gras 			goto formerr;
2142fe8fb19SBen Gras 
2152fe8fb19SBen Gras 		/* Serial number. */
2162fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
2172fe8fb19SBen Gras 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
2182fe8fb19SBen Gras 		len = SPRINTF((tmp, "%lu", t));
2192fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
2202fe8fb19SBen Gras 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
2212fe8fb19SBen Gras 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
2222fe8fb19SBen Gras 		spaced = 0;
2232fe8fb19SBen Gras 
2242fe8fb19SBen Gras 		/* Refresh interval. */
2252fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
2262fe8fb19SBen Gras 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
2272fe8fb19SBen Gras 		T(len = ns_format_ttl(t, buf, buflen));
2282fe8fb19SBen Gras 		addlen((size_t)len, &buf, &buflen);
2292fe8fb19SBen Gras 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
2302fe8fb19SBen Gras 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
2312fe8fb19SBen Gras 		spaced = 0;
2322fe8fb19SBen Gras 
2332fe8fb19SBen Gras 		/* Retry interval. */
2342fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
2352fe8fb19SBen Gras 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
2362fe8fb19SBen Gras 		T(len = ns_format_ttl(t, buf, buflen));
2372fe8fb19SBen Gras 		addlen((size_t)len, &buf, &buflen);
2382fe8fb19SBen Gras 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
2392fe8fb19SBen Gras 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
2402fe8fb19SBen Gras 		spaced = 0;
2412fe8fb19SBen Gras 
2422fe8fb19SBen Gras 		/* Expiry. */
2432fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
2442fe8fb19SBen Gras 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
2452fe8fb19SBen Gras 		T(len = ns_format_ttl(t, buf, buflen));
2462fe8fb19SBen Gras 		addlen((size_t)len, &buf, &buflen);
2472fe8fb19SBen Gras 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
2482fe8fb19SBen Gras 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
2492fe8fb19SBen Gras 		spaced = 0;
2502fe8fb19SBen Gras 
2512fe8fb19SBen Gras 		/* Minimum TTL. */
2522fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
2532fe8fb19SBen Gras 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
2542fe8fb19SBen Gras 		T(len = ns_format_ttl(t, buf, buflen));
2552fe8fb19SBen Gras 		addlen((size_t)len, &buf, &buflen);
2562fe8fb19SBen Gras 		T(addstr(" )", (size_t)2, &buf, &buflen));
2572fe8fb19SBen Gras 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
2582fe8fb19SBen Gras 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
2592fe8fb19SBen Gras 
2602fe8fb19SBen Gras 		break;
2612fe8fb19SBen Gras 	    }
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras 	case ns_t_mx:
2642fe8fb19SBen Gras 	case ns_t_afsdb:
2652fe8fb19SBen Gras 	case ns_t_rt:
2662fe8fb19SBen Gras 	case ns_t_kx: {
2672fe8fb19SBen Gras 		u_int t;
2682fe8fb19SBen Gras 
2692fe8fb19SBen Gras 		if (rdlen < (size_t)NS_INT16SZ)
2702fe8fb19SBen Gras 			goto formerr;
2712fe8fb19SBen Gras 
2722fe8fb19SBen Gras 		/* Priority. */
2732fe8fb19SBen Gras 		t = ns_get16(rdata);
2742fe8fb19SBen Gras 		rdata += NS_INT16SZ;
2752fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", t));
2762fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
2772fe8fb19SBen Gras 
2782fe8fb19SBen Gras 		/* Target. */
2792fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2802fe8fb19SBen Gras 
2812fe8fb19SBen Gras 		break;
2822fe8fb19SBen Gras 	    }
2832fe8fb19SBen Gras 
2842fe8fb19SBen Gras 	case ns_t_px: {
2852fe8fb19SBen Gras 		u_int t;
2862fe8fb19SBen Gras 
2872fe8fb19SBen Gras 		if (rdlen < (size_t)NS_INT16SZ)
2882fe8fb19SBen Gras 			goto formerr;
2892fe8fb19SBen Gras 
2902fe8fb19SBen Gras 		/* Priority. */
2912fe8fb19SBen Gras 		t = ns_get16(rdata);
2922fe8fb19SBen Gras 		rdata += NS_INT16SZ;
2932fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", t));
2942fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
2952fe8fb19SBen Gras 
2962fe8fb19SBen Gras 		/* Name1. */
2972fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2982fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
2992fe8fb19SBen Gras 
3002fe8fb19SBen Gras 		/* Name2. */
3012fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
3022fe8fb19SBen Gras 
3032fe8fb19SBen Gras 		break;
3042fe8fb19SBen Gras 	    }
3052fe8fb19SBen Gras 
3062fe8fb19SBen Gras 	case ns_t_x25:
3072fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
3082fe8fb19SBen Gras 		if (len == 0)
3092fe8fb19SBen Gras 			goto formerr;
3102fe8fb19SBen Gras 		rdata += len;
3112fe8fb19SBen Gras 		break;
3122fe8fb19SBen Gras 
3132fe8fb19SBen Gras 	case ns_t_txt:
3142fe8fb19SBen Gras 	case ns_t_spf:
3152fe8fb19SBen Gras 		while (rdata < edata) {
3162fe8fb19SBen Gras 			T(len = charstr(rdata, edata, &buf, &buflen));
3172fe8fb19SBen Gras 			if (len == 0)
3182fe8fb19SBen Gras 				goto formerr;
3192fe8fb19SBen Gras 			rdata += len;
3202fe8fb19SBen Gras 			if (rdata < edata)
3212fe8fb19SBen Gras 				T(addstr(" ", (size_t)1, &buf, &buflen));
3222fe8fb19SBen Gras 		}
3232fe8fb19SBen Gras 		break;
3242fe8fb19SBen Gras 
3252fe8fb19SBen Gras 	case ns_t_nsap: {
3262fe8fb19SBen Gras 		char t[2+255*3];
3272fe8fb19SBen Gras 
3282fe8fb19SBen Gras 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
3292fe8fb19SBen Gras 		T(addstr(t, strlen(t), &buf, &buflen));
3302fe8fb19SBen Gras 		break;
3312fe8fb19SBen Gras 	    }
3322fe8fb19SBen Gras 
3332fe8fb19SBen Gras 	case ns_t_aaaa:
3342fe8fb19SBen Gras 		if (rdlen != (size_t)NS_IN6ADDRSZ)
3352fe8fb19SBen Gras 			goto formerr;
336*f14fb602SLionel Sambuc 		(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
3372fe8fb19SBen Gras 		addlen(strlen(buf), &buf, &buflen);
3382fe8fb19SBen Gras 		break;
3392fe8fb19SBen Gras 
3402fe8fb19SBen Gras 	case ns_t_loc: {
3412fe8fb19SBen Gras 		char t[255];
3422fe8fb19SBen Gras 
3432fe8fb19SBen Gras 		/* XXX protocol format checking? */
3442fe8fb19SBen Gras 		(void) loc_ntoa(rdata, t);
3452fe8fb19SBen Gras 		T(addstr(t, strlen(t), &buf, &buflen));
3462fe8fb19SBen Gras 		break;
3472fe8fb19SBen Gras 	    }
3482fe8fb19SBen Gras 
3492fe8fb19SBen Gras 	case ns_t_naptr: {
3502fe8fb19SBen Gras 		u_int order, preference;
3512fe8fb19SBen Gras 		char t[50];
3522fe8fb19SBen Gras 
3532fe8fb19SBen Gras 		if (rdlen < 2U*NS_INT16SZ)
3542fe8fb19SBen Gras 			goto formerr;
3552fe8fb19SBen Gras 
3562fe8fb19SBen Gras 		/* Order, Precedence. */
3572fe8fb19SBen Gras 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
3582fe8fb19SBen Gras 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
3592fe8fb19SBen Gras 		len = SPRINTF((t, "%u %u ", order, preference));
3602fe8fb19SBen Gras 		T(addstr(t, (size_t)len, &buf, &buflen));
3612fe8fb19SBen Gras 
3622fe8fb19SBen Gras 		/* Flags. */
3632fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
3642fe8fb19SBen Gras 		if (len == 0)
3652fe8fb19SBen Gras 			goto formerr;
3662fe8fb19SBen Gras 		rdata += len;
3672fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
3682fe8fb19SBen Gras 
3692fe8fb19SBen Gras 		/* Service. */
3702fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
3712fe8fb19SBen Gras 		if (len == 0)
3722fe8fb19SBen Gras 			goto formerr;
3732fe8fb19SBen Gras 		rdata += len;
3742fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
3752fe8fb19SBen Gras 
3762fe8fb19SBen Gras 		/* Regexp. */
3772fe8fb19SBen Gras 		T(len = charstr(rdata, edata, &buf, &buflen));
3782fe8fb19SBen Gras 		if (len < 0)
3792fe8fb19SBen Gras 			return (-1);
3802fe8fb19SBen Gras 		if (len == 0)
3812fe8fb19SBen Gras 			goto formerr;
3822fe8fb19SBen Gras 		rdata += len;
3832fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
3842fe8fb19SBen Gras 
3852fe8fb19SBen Gras 		/* Server. */
3862fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
3872fe8fb19SBen Gras 		break;
3882fe8fb19SBen Gras 	    }
3892fe8fb19SBen Gras 
3902fe8fb19SBen Gras 	case ns_t_srv: {
3912fe8fb19SBen Gras 		u_int priority, weight, port;
3922fe8fb19SBen Gras 		char t[50];
3932fe8fb19SBen Gras 
3942fe8fb19SBen Gras 		if (rdlen < 3U*NS_INT16SZ)
3952fe8fb19SBen Gras 			goto formerr;
3962fe8fb19SBen Gras 
3972fe8fb19SBen Gras 		/* Priority, Weight, Port. */
3982fe8fb19SBen Gras 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
3992fe8fb19SBen Gras 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
4002fe8fb19SBen Gras 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
4012fe8fb19SBen Gras 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
4022fe8fb19SBen Gras 		T(addstr(t, (size_t)len, &buf, &buflen));
4032fe8fb19SBen Gras 
4042fe8fb19SBen Gras 		/* Server. */
4052fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
4062fe8fb19SBen Gras 		break;
4072fe8fb19SBen Gras 	    }
4082fe8fb19SBen Gras 
4092fe8fb19SBen Gras 	case ns_t_minfo:
4102fe8fb19SBen Gras 	case ns_t_rp:
4112fe8fb19SBen Gras 		/* Name1. */
4122fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
4132fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
4142fe8fb19SBen Gras 
4152fe8fb19SBen Gras 		/* Name2. */
4162fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
4172fe8fb19SBen Gras 
4182fe8fb19SBen Gras 		break;
4192fe8fb19SBen Gras 
4202fe8fb19SBen Gras 	case ns_t_wks: {
4212fe8fb19SBen Gras 		int n, lcnt;
4222fe8fb19SBen Gras 
4232fe8fb19SBen Gras 		if (rdlen < 1U + NS_INT32SZ)
4242fe8fb19SBen Gras 			goto formerr;
4252fe8fb19SBen Gras 
4262fe8fb19SBen Gras 		/* Address. */
427*f14fb602SLionel Sambuc 		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
4282fe8fb19SBen Gras 		addlen(strlen(buf), &buf, &buflen);
4292fe8fb19SBen Gras 		rdata += NS_INADDRSZ;
4302fe8fb19SBen Gras 
4312fe8fb19SBen Gras 		/* Protocol. */
4322fe8fb19SBen Gras 		len = SPRINTF((tmp, " %u ( ", *rdata));
4332fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
4342fe8fb19SBen Gras 		rdata += NS_INT8SZ;
4352fe8fb19SBen Gras 
4362fe8fb19SBen Gras 		/* Bit map. */
4372fe8fb19SBen Gras 		n = 0;
4382fe8fb19SBen Gras 		lcnt = 0;
4392fe8fb19SBen Gras 		while (rdata < edata) {
4402fe8fb19SBen Gras 			u_int c = *rdata++;
4412fe8fb19SBen Gras 			do {
4422fe8fb19SBen Gras 				if (c & 0200) {
4432fe8fb19SBen Gras 					if (lcnt == 0) {
4442fe8fb19SBen Gras 						T(addstr("\n\t\t\t\t", (size_t)5,
4452fe8fb19SBen Gras 							 &buf, &buflen));
4462fe8fb19SBen Gras 						lcnt = 10;
4472fe8fb19SBen Gras 						spaced = 0;
4482fe8fb19SBen Gras 					}
4492fe8fb19SBen Gras 					len = SPRINTF((tmp, "%d ", n));
4502fe8fb19SBen Gras 					T(addstr(tmp, (size_t)len, &buf, &buflen));
4512fe8fb19SBen Gras 					lcnt--;
4522fe8fb19SBen Gras 				}
4532fe8fb19SBen Gras 				c <<= 1;
4542fe8fb19SBen Gras 			} while (++n & 07);
4552fe8fb19SBen Gras 		}
4562fe8fb19SBen Gras 		T(addstr(")", (size_t)1, &buf, &buflen));
4572fe8fb19SBen Gras 
4582fe8fb19SBen Gras 		break;
4592fe8fb19SBen Gras 	    }
4602fe8fb19SBen Gras 
4612fe8fb19SBen Gras 	case ns_t_key:
4622fe8fb19SBen Gras 	case ns_t_dnskey: {
4632fe8fb19SBen Gras 		char base64_key[NS_MD5RSA_MAX_BASE64];
4642fe8fb19SBen Gras 		u_int keyflags, protocol, algorithm, key_id;
4652fe8fb19SBen Gras 		const char *leader;
4662fe8fb19SBen Gras 		int n;
4672fe8fb19SBen Gras 
4682fe8fb19SBen Gras 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
4692fe8fb19SBen Gras 			goto formerr;
4702fe8fb19SBen Gras 
4712fe8fb19SBen Gras 		/* Key flags, Protocol, Algorithm. */
4722fe8fb19SBen Gras #ifndef _LIBC
4732fe8fb19SBen Gras 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
4742fe8fb19SBen Gras #else
4752fe8fb19SBen Gras 		key_id = 0;
4762fe8fb19SBen Gras #endif
4772fe8fb19SBen Gras 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
4782fe8fb19SBen Gras 		protocol = *rdata++;
4792fe8fb19SBen Gras 		algorithm = *rdata++;
4802fe8fb19SBen Gras 		len = SPRINTF((tmp, "0x%04x %u %u",
4812fe8fb19SBen Gras 			       keyflags, protocol, algorithm));
4822fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
4832fe8fb19SBen Gras 
4842fe8fb19SBen Gras 		/* Public key data. */
4852fe8fb19SBen Gras 		len = b64_ntop(rdata, (size_t)(edata - rdata),
4862fe8fb19SBen Gras 			       base64_key, sizeof base64_key);
4872fe8fb19SBen Gras 		if (len < 0)
4882fe8fb19SBen Gras 			goto formerr;
4892fe8fb19SBen Gras 		if (len > 15) {
4902fe8fb19SBen Gras 			T(addstr(" (", (size_t)2, &buf, &buflen));
4912fe8fb19SBen Gras 			leader = "\n\t\t";
4922fe8fb19SBen Gras 			spaced = 0;
4932fe8fb19SBen Gras 		} else
4942fe8fb19SBen Gras 			leader = " ";
4952fe8fb19SBen Gras 		for (n = 0; n < len; n += 48) {
4962fe8fb19SBen Gras 			T(addstr(leader, strlen(leader), &buf, &buflen));
4972fe8fb19SBen Gras 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
4982fe8fb19SBen Gras 				 &buf, &buflen));
4992fe8fb19SBen Gras 		}
5002fe8fb19SBen Gras 		if (len > 15)
5012fe8fb19SBen Gras 			T(addstr(" )", (size_t)2, &buf, &buflen));
5022fe8fb19SBen Gras 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
5032fe8fb19SBen Gras 		T(addstr(tmp, (size_t)n, &buf, &buflen));
5042fe8fb19SBen Gras 
5052fe8fb19SBen Gras 		break;
5062fe8fb19SBen Gras 	    }
5072fe8fb19SBen Gras 
5082fe8fb19SBen Gras 	case ns_t_sig:
5092fe8fb19SBen Gras 	case ns_t_rrsig: {
5102fe8fb19SBen Gras 		char base64_key[NS_MD5RSA_MAX_BASE64];
5112fe8fb19SBen Gras 		u_int typ, algorithm, labels, footprint;
5122fe8fb19SBen Gras 		const char *leader;
5132fe8fb19SBen Gras 		u_long t;
5142fe8fb19SBen Gras 		int n;
5152fe8fb19SBen Gras 
5162fe8fb19SBen Gras 		if (rdlen < 22U)
5172fe8fb19SBen Gras 			goto formerr;
5182fe8fb19SBen Gras 
5192fe8fb19SBen Gras 		/* Type covered, Algorithm, Label count, Original TTL. */
5202fe8fb19SBen Gras 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
5212fe8fb19SBen Gras 		algorithm = *rdata++;
5222fe8fb19SBen Gras 		labels = *rdata++;
5232fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
5242fe8fb19SBen Gras 		len = SPRINTF((tmp, "%s %d %d %lu ",
5252fe8fb19SBen Gras 			       p_type((int)typ), algorithm, labels, t));
5262fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
5272fe8fb19SBen Gras 		if (labels > (u_int)dn_count_labels(name))
5282fe8fb19SBen Gras 			goto formerr;
5292fe8fb19SBen Gras 
5302fe8fb19SBen Gras 		/* Signature expiry. */
5312fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
5322fe8fb19SBen Gras 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
5332fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
5342fe8fb19SBen Gras 
5352fe8fb19SBen Gras 		/* Time signed. */
5362fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
5372fe8fb19SBen Gras 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
5382fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
5392fe8fb19SBen Gras 
5402fe8fb19SBen Gras 		/* Signature Footprint. */
5412fe8fb19SBen Gras 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
5422fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", footprint));
5432fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
5442fe8fb19SBen Gras 
5452fe8fb19SBen Gras 		/* Signer's name. */
5462fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
5472fe8fb19SBen Gras 
5482fe8fb19SBen Gras 		/* Signature. */
5492fe8fb19SBen Gras 		len = b64_ntop(rdata, (size_t)(edata - rdata),
5502fe8fb19SBen Gras 			       base64_key, sizeof base64_key);
5512fe8fb19SBen Gras 		if (len > 15) {
5522fe8fb19SBen Gras 			T(addstr(" (", (size_t)2, &buf, &buflen));
5532fe8fb19SBen Gras 			leader = "\n\t\t";
5542fe8fb19SBen Gras 			spaced = 0;
5552fe8fb19SBen Gras 		} else
5562fe8fb19SBen Gras 			leader = " ";
5572fe8fb19SBen Gras 		if (len < 0)
5582fe8fb19SBen Gras 			goto formerr;
5592fe8fb19SBen Gras 		for (n = 0; n < len; n += 48) {
5602fe8fb19SBen Gras 			T(addstr(leader, strlen(leader), &buf, &buflen));
5612fe8fb19SBen Gras 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
5622fe8fb19SBen Gras 				 &buf, &buflen));
5632fe8fb19SBen Gras 		}
5642fe8fb19SBen Gras 		if (len > 15)
5652fe8fb19SBen Gras 			T(addstr(" )", (size_t)2, &buf, &buflen));
5662fe8fb19SBen Gras 		break;
5672fe8fb19SBen Gras 	    }
5682fe8fb19SBen Gras 
5692fe8fb19SBen Gras 	case ns_t_nxt: {
570*f14fb602SLionel Sambuc 		ptrdiff_t n, c;
5712fe8fb19SBen Gras 
5722fe8fb19SBen Gras 		/* Next domain name. */
5732fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
5742fe8fb19SBen Gras 
5752fe8fb19SBen Gras 		/* Type bit map. */
5762fe8fb19SBen Gras 		n = edata - rdata;
5772fe8fb19SBen Gras 		for (c = 0; c < n*8; c++)
5782fe8fb19SBen Gras 			if (NS_NXT_BIT_ISSET(c, rdata)) {
579*f14fb602SLionel Sambuc 				len = SPRINTF((tmp, " %s", p_type((int)c)));
5802fe8fb19SBen Gras 				T(addstr(tmp, (size_t)len, &buf, &buflen));
5812fe8fb19SBen Gras 			}
5822fe8fb19SBen Gras 		break;
5832fe8fb19SBen Gras 	    }
5842fe8fb19SBen Gras 
5852fe8fb19SBen Gras 	case ns_t_cert: {
5862fe8fb19SBen Gras 		u_int c_type, key_tag, alg;
5872fe8fb19SBen Gras 		int n;
588*f14fb602SLionel Sambuc 		size_t siz;
5892fe8fb19SBen Gras 		char base64_cert[8192], tmp1[40];
5902fe8fb19SBen Gras 		const char *leader;
5912fe8fb19SBen Gras 
5922fe8fb19SBen Gras 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
5932fe8fb19SBen Gras 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
5942fe8fb19SBen Gras 		alg = (u_int) *rdata++;
5952fe8fb19SBen Gras 
5962fe8fb19SBen Gras 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
5972fe8fb19SBen Gras 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
5982fe8fb19SBen Gras 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
5992fe8fb19SBen Gras 		if (siz > sizeof(base64_cert) * 3/4) {
6002fe8fb19SBen Gras 			const char *str = "record too long to print";
6012fe8fb19SBen Gras 			T(addstr(str, strlen(str), &buf, &buflen));
6022fe8fb19SBen Gras 		}
6032fe8fb19SBen Gras 		else {
6042fe8fb19SBen Gras 			len = b64_ntop(rdata, (size_t)(edata-rdata),
6052fe8fb19SBen Gras 			    base64_cert, siz);
6062fe8fb19SBen Gras 
6072fe8fb19SBen Gras 			if (len < 0)
6082fe8fb19SBen Gras 				goto formerr;
6092fe8fb19SBen Gras 			else if (len > 15) {
6102fe8fb19SBen Gras 				T(addstr(" (", (size_t)2, &buf, &buflen));
6112fe8fb19SBen Gras 				leader = "\n\t\t";
6122fe8fb19SBen Gras 				spaced = 0;
6132fe8fb19SBen Gras 			}
6142fe8fb19SBen Gras 			else
6152fe8fb19SBen Gras 				leader = " ";
6162fe8fb19SBen Gras 
6172fe8fb19SBen Gras 			for (n = 0; n < len; n += 48) {
6182fe8fb19SBen Gras 				T(addstr(leader, strlen(leader),
6192fe8fb19SBen Gras 					 &buf, &buflen));
6202fe8fb19SBen Gras 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
6212fe8fb19SBen Gras 					 &buf, &buflen));
6222fe8fb19SBen Gras 			}
6232fe8fb19SBen Gras 			if (len > 15)
6242fe8fb19SBen Gras 				T(addstr(" )", (size_t)2, &buf, &buflen));
6252fe8fb19SBen Gras 		}
6262fe8fb19SBen Gras 		break;
6272fe8fb19SBen Gras 	    }
6282fe8fb19SBen Gras 
6292fe8fb19SBen Gras 	case ns_t_tkey: {
6302fe8fb19SBen Gras 		/* KJD - need to complete this */
6312fe8fb19SBen Gras 		u_long t;
6322fe8fb19SBen Gras 		int mode, err, keysize;
6332fe8fb19SBen Gras 
6342fe8fb19SBen Gras 		/* Algorithm name. */
6352fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
6362fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
6372fe8fb19SBen Gras 
6382fe8fb19SBen Gras 		/* Inception. */
6392fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
6402fe8fb19SBen Gras 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
6412fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
6422fe8fb19SBen Gras 
6432fe8fb19SBen Gras 		/* Experation. */
6442fe8fb19SBen Gras 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
6452fe8fb19SBen Gras 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
6462fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
6472fe8fb19SBen Gras 
6482fe8fb19SBen Gras 		/* Mode , Error, Key Size. */
6492fe8fb19SBen Gras 		/* Priority, Weight, Port. */
6502fe8fb19SBen Gras 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
6512fe8fb19SBen Gras 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
6522fe8fb19SBen Gras 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
6532fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
6542fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
6552fe8fb19SBen Gras 
6562fe8fb19SBen Gras 		/* XXX need to dump key, print otherdata length & other data */
6572fe8fb19SBen Gras 		break;
6582fe8fb19SBen Gras 	    }
6592fe8fb19SBen Gras 
6602fe8fb19SBen Gras 	case ns_t_tsig: {
6612fe8fb19SBen Gras 		/* BEW - need to complete this */
6622fe8fb19SBen Gras 		int n;
6632fe8fb19SBen Gras 
6642fe8fb19SBen Gras 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
6652fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
6662fe8fb19SBen Gras 		rdata += 8; /*%< time */
6672fe8fb19SBen Gras 		n = ns_get16(rdata); rdata += INT16SZ;
6682fe8fb19SBen Gras 		rdata += n; /*%< sig */
6692fe8fb19SBen Gras 		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
6702fe8fb19SBen Gras 		sprintf(buf, "%d", ns_get16(rdata));
6712fe8fb19SBen Gras 		rdata += INT16SZ;
6722fe8fb19SBen Gras 		addlen(strlen(buf), &buf, &buflen);
6732fe8fb19SBen Gras 		break;
6742fe8fb19SBen Gras 	    }
6752fe8fb19SBen Gras 
6762fe8fb19SBen Gras 	case ns_t_a6: {
6772fe8fb19SBen Gras 		struct in6_addr a;
6782fe8fb19SBen Gras 		int pbyte, pbit;
6792fe8fb19SBen Gras 
6802fe8fb19SBen Gras 		/* prefix length */
6812fe8fb19SBen Gras 		if (rdlen == 0U) goto formerr;
6822fe8fb19SBen Gras 		len = SPRINTF((tmp, "%d ", *rdata));
6832fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
6842fe8fb19SBen Gras 		pbit = *rdata;
6852fe8fb19SBen Gras 		if (pbit > 128) goto formerr;
6862fe8fb19SBen Gras 		pbyte = (pbit & ~7) / 8;
6872fe8fb19SBen Gras 		rdata++;
6882fe8fb19SBen Gras 
6892fe8fb19SBen Gras 		/* address suffix: provided only when prefix len != 128 */
6902fe8fb19SBen Gras 		if (pbit < 128) {
6912fe8fb19SBen Gras 			if (rdata + pbyte >= edata) goto formerr;
6922fe8fb19SBen Gras 			memset(&a, 0, sizeof(a));
6932fe8fb19SBen Gras 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
694*f14fb602SLionel Sambuc 			(void) inet_ntop(AF_INET6, &a, buf, (socklen_t)buflen);
6952fe8fb19SBen Gras 			addlen(strlen(buf), &buf, &buflen);
6962fe8fb19SBen Gras 			rdata += sizeof(a) - pbyte;
6972fe8fb19SBen Gras 		}
6982fe8fb19SBen Gras 
6992fe8fb19SBen Gras 		/* prefix name: provided only when prefix len > 0 */
7002fe8fb19SBen Gras 		if (pbit == 0)
7012fe8fb19SBen Gras 			break;
7022fe8fb19SBen Gras 		if (rdata >= edata) goto formerr;
7032fe8fb19SBen Gras 		T(addstr(" ", (size_t)1, &buf, &buflen));
7042fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
7052fe8fb19SBen Gras 
7062fe8fb19SBen Gras 		break;
7072fe8fb19SBen Gras 	    }
7082fe8fb19SBen Gras 
7092fe8fb19SBen Gras 	case ns_t_opt: {
7102fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u bytes", class));
7112fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7122fe8fb19SBen Gras 		break;
7132fe8fb19SBen Gras 	    }
7142fe8fb19SBen Gras 
7152fe8fb19SBen Gras 	case ns_t_ds:
7162fe8fb19SBen Gras 	case ns_t_dlv:
7172fe8fb19SBen Gras 	case ns_t_sshfp: {
7182fe8fb19SBen Gras 		u_int t;
7192fe8fb19SBen Gras 
7202fe8fb19SBen Gras 		if (type == ns_t_ds || type == ns_t_dlv) {
7212fe8fb19SBen Gras 			if (rdlen < 4U) goto formerr;
7222fe8fb19SBen Gras 			t = ns_get16(rdata);
7232fe8fb19SBen Gras 			rdata += NS_INT16SZ;
7242fe8fb19SBen Gras 			len = SPRINTF((tmp, "%u ", t));
7252fe8fb19SBen Gras 			T(addstr(tmp, (size_t)len, &buf, &buflen));
7262fe8fb19SBen Gras 		} else
7272fe8fb19SBen Gras 			if (rdlen < 2U) goto formerr;
7282fe8fb19SBen Gras 
7292fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
7302fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7312fe8fb19SBen Gras 		rdata++;
7322fe8fb19SBen Gras 
7332fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
7342fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7352fe8fb19SBen Gras 		rdata++;
7362fe8fb19SBen Gras 
7372fe8fb19SBen Gras 		while (rdata < edata) {
7382fe8fb19SBen Gras 			len = SPRINTF((tmp, "%02X", *rdata));
7392fe8fb19SBen Gras 			T(addstr(tmp, (size_t)len, &buf, &buflen));
7402fe8fb19SBen Gras 			rdata++;
7412fe8fb19SBen Gras 		}
7422fe8fb19SBen Gras 		break;
7432fe8fb19SBen Gras 	    }
7442fe8fb19SBen Gras 
7452fe8fb19SBen Gras 	case ns_t_nsec3:
7462fe8fb19SBen Gras 	case ns_t_nsec3param: {
7472fe8fb19SBen Gras 		u_int t, w, l, j, k, c;
7482fe8fb19SBen Gras 
7492fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
7502fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7512fe8fb19SBen Gras 		rdata++;
7522fe8fb19SBen Gras 
7532fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
7542fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7552fe8fb19SBen Gras 		rdata++;
7562fe8fb19SBen Gras 
7572fe8fb19SBen Gras 		t = ns_get16(rdata);
7582fe8fb19SBen Gras 		rdata += NS_INT16SZ;
7592fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", t));
7602fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
7612fe8fb19SBen Gras 
7622fe8fb19SBen Gras 		t = *rdata++;
7632fe8fb19SBen Gras 		if (t == 0) {
7642fe8fb19SBen Gras 			T(addstr("-", 1, &buf, &buflen));
7652fe8fb19SBen Gras 		} else {
7662fe8fb19SBen Gras 			while (t-- > 0) {
7672fe8fb19SBen Gras 				len = SPRINTF((tmp, "%02X", *rdata));
7682fe8fb19SBen Gras 				T(addstr(tmp, (size_t)len, &buf, &buflen));
7692fe8fb19SBen Gras 				rdata++;
7702fe8fb19SBen Gras 			}
7712fe8fb19SBen Gras 		}
7722fe8fb19SBen Gras 		if (type == ns_t_nsec3param)
7732fe8fb19SBen Gras 			break;
7742fe8fb19SBen Gras 		T(addstr(" ", 1, &buf, &buflen));
7752fe8fb19SBen Gras 
7762fe8fb19SBen Gras 		t = *rdata++;
7772fe8fb19SBen Gras 		while (t > 0) {
7782fe8fb19SBen Gras 			switch (t) {
7792fe8fb19SBen Gras 			case 1:
7802fe8fb19SBen Gras 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
7812fe8fb19SBen Gras 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)];
7822fe8fb19SBen Gras 				tmp[2] = tmp[3] = tmp[4] = '=';
7832fe8fb19SBen Gras 				tmp[5] = tmp[6] = tmp[7] = '=';
7842fe8fb19SBen Gras 				break;
7852fe8fb19SBen Gras 			case 2:
7862fe8fb19SBen Gras 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
7872fe8fb19SBen Gras 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
7882fe8fb19SBen Gras 						   (((uint32_t)rdata[1]>>6)&0x03)];
7892fe8fb19SBen Gras 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
7902fe8fb19SBen Gras 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)];
7912fe8fb19SBen Gras 				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
7922fe8fb19SBen Gras 				break;
7932fe8fb19SBen Gras 			case 3:
7942fe8fb19SBen Gras 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
7952fe8fb19SBen Gras 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
7962fe8fb19SBen Gras 						   (((uint32_t)rdata[1]>>6)&0x03)];
7972fe8fb19SBen Gras 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
7982fe8fb19SBen Gras 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
7992fe8fb19SBen Gras 						   (((uint32_t)rdata[2]>>4)&0x0f)];
8002fe8fb19SBen Gras 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)];
8012fe8fb19SBen Gras 				tmp[5] = tmp[6] = tmp[7] = '=';
8022fe8fb19SBen Gras 				break;
8032fe8fb19SBen Gras 			case 4:
8042fe8fb19SBen Gras 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
8052fe8fb19SBen Gras 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
8062fe8fb19SBen Gras 						   (((uint32_t)rdata[1]>>6)&0x03)];
8072fe8fb19SBen Gras 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
8082fe8fb19SBen Gras 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
8092fe8fb19SBen Gras 						   (((uint32_t)rdata[2]>>4)&0x0f)];
8102fe8fb19SBen Gras 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
8112fe8fb19SBen Gras 						   (((uint32_t)rdata[3]>>7)&0x01)];
8122fe8fb19SBen Gras 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
8132fe8fb19SBen Gras 				tmp[6] = base32hex[((uint32_t)rdata[3]<<3)&0x18];
8142fe8fb19SBen Gras 				tmp[7] = '=';
8152fe8fb19SBen Gras 				break;
8162fe8fb19SBen Gras 			default:
8172fe8fb19SBen Gras 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
8182fe8fb19SBen Gras 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
8192fe8fb19SBen Gras 						   (((uint32_t)rdata[1]>>6)&0x03)];
8202fe8fb19SBen Gras 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
8212fe8fb19SBen Gras 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
8222fe8fb19SBen Gras 						   (((uint32_t)rdata[2]>>4)&0x0f)];
8232fe8fb19SBen Gras 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
8242fe8fb19SBen Gras 						   (((uint32_t)rdata[3]>>7)&0x01)];
8252fe8fb19SBen Gras 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
8262fe8fb19SBen Gras 				tmp[6] = base32hex[(((uint32_t)rdata[3]<<3)&0x18)|
8272fe8fb19SBen Gras 						   (((uint32_t)rdata[4]>>5)&0x07)];
8282fe8fb19SBen Gras 				tmp[7] = base32hex[(rdata[4]&0x1f)];
8292fe8fb19SBen Gras 				break;
8302fe8fb19SBen Gras 			}
8312fe8fb19SBen Gras 			T(addstr(tmp, 8, &buf, &buflen));
8322fe8fb19SBen Gras 			if (t >= 5) {
8332fe8fb19SBen Gras 				rdata += 5;
8342fe8fb19SBen Gras 				t -= 5;
8352fe8fb19SBen Gras 			} else {
8362fe8fb19SBen Gras 				rdata += t;
8372fe8fb19SBen Gras 				t -= t;
8382fe8fb19SBen Gras 			}
8392fe8fb19SBen Gras 		}
8402fe8fb19SBen Gras 
8412fe8fb19SBen Gras 		while (rdata < edata) {
8422fe8fb19SBen Gras 			w = *rdata++;
8432fe8fb19SBen Gras 			l = *rdata++;
8442fe8fb19SBen Gras 			for (j = 0; j < l; j++) {
8452fe8fb19SBen Gras 				if (rdata[j] == 0)
8462fe8fb19SBen Gras 					continue;
8472fe8fb19SBen Gras 				for (k = 0; k < 8; k++) {
8482fe8fb19SBen Gras 					if ((rdata[j] & (0x80 >> k)) == 0)
8492fe8fb19SBen Gras 						continue;
8502fe8fb19SBen Gras 					c = w * 256 + j * 8 + k;
8512fe8fb19SBen Gras 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
8522fe8fb19SBen Gras 					T(addstr(tmp, (size_t)len, &buf, &buflen));
8532fe8fb19SBen Gras 				}
8542fe8fb19SBen Gras 			}
8552fe8fb19SBen Gras 			rdata += l;
8562fe8fb19SBen Gras 		}
8572fe8fb19SBen Gras 		break;
8582fe8fb19SBen Gras 	    }
8592fe8fb19SBen Gras 
8602fe8fb19SBen Gras 	case ns_t_nsec: {
8612fe8fb19SBen Gras 		u_int w, l, j, k, c;
8622fe8fb19SBen Gras 
8632fe8fb19SBen Gras 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
8642fe8fb19SBen Gras 
8652fe8fb19SBen Gras 		while (rdata < edata) {
8662fe8fb19SBen Gras 			w = *rdata++;
8672fe8fb19SBen Gras 			l = *rdata++;
8682fe8fb19SBen Gras 			for (j = 0; j < l; j++) {
8692fe8fb19SBen Gras 				if (rdata[j] == 0)
8702fe8fb19SBen Gras 					continue;
8712fe8fb19SBen Gras 				for (k = 0; k < 8; k++) {
8722fe8fb19SBen Gras 					if ((rdata[j] & (0x80 >> k)) == 0)
8732fe8fb19SBen Gras 						continue;
8742fe8fb19SBen Gras 					c = w * 256 + j * 8 + k;
8752fe8fb19SBen Gras 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
8762fe8fb19SBen Gras 					T(addstr(tmp, (size_t)len, &buf, &buflen));
8772fe8fb19SBen Gras 				}
8782fe8fb19SBen Gras 			}
8792fe8fb19SBen Gras 			rdata += l;
8802fe8fb19SBen Gras 		}
8812fe8fb19SBen Gras 		break;
8822fe8fb19SBen Gras 	    }
8832fe8fb19SBen Gras 
8842fe8fb19SBen Gras 	case ns_t_dhcid: {
8852fe8fb19SBen Gras 		int n;
8862fe8fb19SBen Gras 		unsigned int siz;
8872fe8fb19SBen Gras 		char base64_dhcid[8192];
8882fe8fb19SBen Gras 		const char *leader;
8892fe8fb19SBen Gras 
890*f14fb602SLionel Sambuc 		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
8912fe8fb19SBen Gras 		if (siz > sizeof(base64_dhcid) * 3/4) {
8922fe8fb19SBen Gras 			const char *str = "record too long to print";
8932fe8fb19SBen Gras 			T(addstr(str, strlen(str), &buf, &buflen));
8942fe8fb19SBen Gras 		} else {
8952fe8fb19SBen Gras 			len = b64_ntop(rdata, (size_t)(edata-rdata),
8962fe8fb19SBen Gras 			    base64_dhcid, siz);
8972fe8fb19SBen Gras 
8982fe8fb19SBen Gras 			if (len < 0)
8992fe8fb19SBen Gras 				goto formerr;
9002fe8fb19SBen Gras 
9012fe8fb19SBen Gras 			else if (len > 15) {
9022fe8fb19SBen Gras 				T(addstr(" (", 2, &buf, &buflen));
9032fe8fb19SBen Gras 				leader = "\n\t\t";
9042fe8fb19SBen Gras 				spaced = 0;
9052fe8fb19SBen Gras 			}
9062fe8fb19SBen Gras 			else
9072fe8fb19SBen Gras 				leader = " ";
9082fe8fb19SBen Gras 
9092fe8fb19SBen Gras 			for (n = 0; n < len; n += 48) {
9102fe8fb19SBen Gras 				T(addstr(leader, strlen(leader),
9112fe8fb19SBen Gras 					 &buf, &buflen));
9122fe8fb19SBen Gras 				T(addstr(base64_dhcid + n,
9132fe8fb19SBen Gras 				    (size_t)MIN(len - n, 48), &buf, &buflen));
9142fe8fb19SBen Gras 			}
9152fe8fb19SBen Gras 			if (len > 15)
9162fe8fb19SBen Gras 				T(addstr(" )", 2, &buf, &buflen));
9172fe8fb19SBen Gras 		}
9182fe8fb19SBen Gras 		break;
9192fe8fb19SBen Gras 	}
9202fe8fb19SBen Gras 
9212fe8fb19SBen Gras 	case ns_t_ipseckey: {
9222fe8fb19SBen Gras 		int n;
9232fe8fb19SBen Gras 		unsigned int siz;
9242fe8fb19SBen Gras 		char base64_key[8192];
9252fe8fb19SBen Gras 		const char *leader;
9262fe8fb19SBen Gras 
9272fe8fb19SBen Gras 		if (rdlen < 2)
9282fe8fb19SBen Gras 			goto formerr;
9292fe8fb19SBen Gras 
9302fe8fb19SBen Gras 		switch (rdata[1]) {
9312fe8fb19SBen Gras 		case 0:
9322fe8fb19SBen Gras 		case 3:
9332fe8fb19SBen Gras 			if (rdlen < 3)
9342fe8fb19SBen Gras 				goto formerr;
9352fe8fb19SBen Gras 			break;
9362fe8fb19SBen Gras 		case 1:
9372fe8fb19SBen Gras 			if (rdlen < 7)
9382fe8fb19SBen Gras 				goto formerr;
9392fe8fb19SBen Gras 			break;
9402fe8fb19SBen Gras 		case 2:
9412fe8fb19SBen Gras 			if (rdlen < 19)
9422fe8fb19SBen Gras 				goto formerr;
9432fe8fb19SBen Gras 			break;
9442fe8fb19SBen Gras 		default:
9452fe8fb19SBen Gras 			comment = "unknown IPSECKEY gateway type";
9462fe8fb19SBen Gras 			goto hexify;
9472fe8fb19SBen Gras 		}
9482fe8fb19SBen Gras 
9492fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
9502fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
9512fe8fb19SBen Gras 		rdata++;
9522fe8fb19SBen Gras 
9532fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
9542fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
9552fe8fb19SBen Gras 		rdata++;
9562fe8fb19SBen Gras 
9572fe8fb19SBen Gras 		len = SPRINTF((tmp, "%u ", *rdata));
9582fe8fb19SBen Gras 		T(addstr(tmp, (size_t)len, &buf, &buflen));
9592fe8fb19SBen Gras 		rdata++;
9602fe8fb19SBen Gras 
9612fe8fb19SBen Gras 		switch (rdata[-2]) {
9622fe8fb19SBen Gras 		case 0:
9632fe8fb19SBen Gras 			T(addstr(".", 1, &buf, &buflen));
9642fe8fb19SBen Gras 			break;
9652fe8fb19SBen Gras 		case 1:
966*f14fb602SLionel Sambuc 			(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
9672fe8fb19SBen Gras 			addlen(strlen(buf), &buf, &buflen);
9682fe8fb19SBen Gras 			rdata += 4;
9692fe8fb19SBen Gras 			break;
9702fe8fb19SBen Gras 		case 2:
971*f14fb602SLionel Sambuc 			(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
9722fe8fb19SBen Gras 			addlen(strlen(buf), &buf, &buflen);
9732fe8fb19SBen Gras 			rdata += 16;
9742fe8fb19SBen Gras 			break;
9752fe8fb19SBen Gras 		case 3:
9762fe8fb19SBen Gras 			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
9772fe8fb19SBen Gras 			break;
9782fe8fb19SBen Gras 		}
9792fe8fb19SBen Gras 
9802fe8fb19SBen Gras 		if (rdata >= edata)
9812fe8fb19SBen Gras 			break;
9822fe8fb19SBen Gras 
983*f14fb602SLionel Sambuc 		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
9842fe8fb19SBen Gras 		if (siz > sizeof(base64_key) * 3/4) {
9852fe8fb19SBen Gras 			const char *str = "record too long to print";
9862fe8fb19SBen Gras 			T(addstr(str, strlen(str), &buf, &buflen));
9872fe8fb19SBen Gras 		} else {
9882fe8fb19SBen Gras 			len = b64_ntop(rdata, (size_t)(edata-rdata),
9892fe8fb19SBen Gras 			    base64_key, siz);
9902fe8fb19SBen Gras 
9912fe8fb19SBen Gras 			if (len < 0)
9922fe8fb19SBen Gras 				goto formerr;
9932fe8fb19SBen Gras 
9942fe8fb19SBen Gras 			else if (len > 15) {
9952fe8fb19SBen Gras 				T(addstr(" (", 2, &buf, &buflen));
9962fe8fb19SBen Gras 				leader = "\n\t\t";
9972fe8fb19SBen Gras 				spaced = 0;
9982fe8fb19SBen Gras 			}
9992fe8fb19SBen Gras 			else
10002fe8fb19SBen Gras 				leader = " ";
10012fe8fb19SBen Gras 
10022fe8fb19SBen Gras 			for (n = 0; n < len; n += 48) {
10032fe8fb19SBen Gras 				T(addstr(leader, strlen(leader),
10042fe8fb19SBen Gras 					 &buf, &buflen));
10052fe8fb19SBen Gras 				T(addstr(base64_key + n,
10062fe8fb19SBen Gras 				    (size_t)MIN(len - n, 48), &buf, &buflen));
10072fe8fb19SBen Gras 			}
10082fe8fb19SBen Gras 			if (len > 15)
10092fe8fb19SBen Gras 				T(addstr(" )", 2, &buf, &buflen));
10102fe8fb19SBen Gras 		}
10112fe8fb19SBen Gras 		break;
10122fe8fb19SBen Gras 	}
10132fe8fb19SBen Gras 
10142fe8fb19SBen Gras 	case ns_t_hip: {
10152fe8fb19SBen Gras 		unsigned int i, hip_len, algorithm, key_len;
10162fe8fb19SBen Gras 		char base64_key[NS_MD5RSA_MAX_BASE64];
10172fe8fb19SBen Gras 		unsigned int siz;
10182fe8fb19SBen Gras 		const char *leader = "\n\t\t\t\t\t";
10192fe8fb19SBen Gras 
10202fe8fb19SBen Gras 		hip_len = *rdata++;
10212fe8fb19SBen Gras 		algorithm = *rdata++;
10222fe8fb19SBen Gras 		key_len = ns_get16(rdata);
10232fe8fb19SBen Gras 		rdata += NS_INT16SZ;
10242fe8fb19SBen Gras 
10252fe8fb19SBen Gras 		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
10262fe8fb19SBen Gras 		if (siz > sizeof(base64_key) * 3/4) {
10272fe8fb19SBen Gras 			const char *str = "record too long to print";
10282fe8fb19SBen Gras 			T(addstr(str, strlen(str), &buf, &buflen));
10292fe8fb19SBen Gras 		} else {
10302fe8fb19SBen Gras 			len = sprintf(tmp, "( %u ", algorithm);
10312fe8fb19SBen Gras 			T(addstr(tmp, (size_t)len, &buf, &buflen));
10322fe8fb19SBen Gras 
10332fe8fb19SBen Gras 			for (i = 0; i < hip_len; i++) {
10342fe8fb19SBen Gras 				len = sprintf(tmp, "%02X", *rdata);
10352fe8fb19SBen Gras 				T(addstr(tmp, (size_t)len, &buf, &buflen));
10362fe8fb19SBen Gras 				rdata++;
10372fe8fb19SBen Gras 			}
10382fe8fb19SBen Gras 			T(addstr(leader, strlen(leader), &buf, &buflen));
10392fe8fb19SBen Gras 
10402fe8fb19SBen Gras 			len = b64_ntop(rdata, key_len, base64_key, siz);
10412fe8fb19SBen Gras 			if (len < 0)
10422fe8fb19SBen Gras 				goto formerr;
10432fe8fb19SBen Gras 
10442fe8fb19SBen Gras 			T(addstr(base64_key, (size_t)len, &buf, &buflen));
10452fe8fb19SBen Gras 
10462fe8fb19SBen Gras 			rdata += key_len;
10472fe8fb19SBen Gras 			while (rdata < edata) {
10482fe8fb19SBen Gras 				T(addstr(leader, strlen(leader), &buf, &buflen));
10492fe8fb19SBen Gras 				T(addname(msg, msglen, &rdata, origin,
10502fe8fb19SBen Gras 					  &buf, &buflen));
10512fe8fb19SBen Gras 			}
10522fe8fb19SBen Gras 			T(addstr(" )", 2, &buf, &buflen));
10532fe8fb19SBen Gras 		}
10542fe8fb19SBen Gras 		break;
10552fe8fb19SBen Gras 	}
10562fe8fb19SBen Gras 
10572fe8fb19SBen Gras 	default:
10582fe8fb19SBen Gras 		comment = "unknown RR type";
10592fe8fb19SBen Gras 		goto hexify;
10602fe8fb19SBen Gras 	}
1061*f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, buf - obuf));
1062*f14fb602SLionel Sambuc 	return (int)(buf - obuf);
10632fe8fb19SBen Gras  formerr:
10642fe8fb19SBen Gras 	comment = "RR format error";
10652fe8fb19SBen Gras  hexify: {
10662fe8fb19SBen Gras 	int n, m;
10672fe8fb19SBen Gras 	char *p;
10682fe8fb19SBen Gras 
10692fe8fb19SBen Gras 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
10702fe8fb19SBen Gras 		       rdlen != 0U ? " (" : "", comment));
10712fe8fb19SBen Gras 	T(addstr(tmp, (size_t)len, &buf, &buflen));
10722fe8fb19SBen Gras 	while (rdata < edata) {
10732fe8fb19SBen Gras 		p = tmp;
10742fe8fb19SBen Gras 		p += SPRINTF((p, "\n\t"));
10752fe8fb19SBen Gras 		spaced = 0;
1076*f14fb602SLionel Sambuc 		n = MIN(16, (int)(edata - rdata));
10772fe8fb19SBen Gras 		for (m = 0; m < n; m++)
10782fe8fb19SBen Gras 			p += SPRINTF((p, "%02x ", rdata[m]));
10792fe8fb19SBen Gras 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
10802fe8fb19SBen Gras 		if (n < 16) {
10812fe8fb19SBen Gras 			T(addstr(")", (size_t)1, &buf, &buflen));
10822fe8fb19SBen Gras 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
10832fe8fb19SBen Gras 		}
10842fe8fb19SBen Gras 		p = tmp;
10852fe8fb19SBen Gras 		p += SPRINTF((p, "; "));
10862fe8fb19SBen Gras 		for (m = 0; m < n; m++)
10872fe8fb19SBen Gras 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
10882fe8fb19SBen Gras 				? rdata[m]
10892fe8fb19SBen Gras 				: '.';
10902fe8fb19SBen Gras 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
10912fe8fb19SBen Gras 		rdata += n;
10922fe8fb19SBen Gras 	}
1093*f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, buf - obuf));
1094*f14fb602SLionel Sambuc 	return (int)(buf - obuf);
10952fe8fb19SBen Gras     }
10962fe8fb19SBen Gras }
10972fe8fb19SBen Gras 
10982fe8fb19SBen Gras /* Private. */
10992fe8fb19SBen Gras 
11002fe8fb19SBen Gras /*%
11012fe8fb19SBen Gras  * size_t
11022fe8fb19SBen Gras  * prune_origin(name, origin)
11032fe8fb19SBen Gras  *	Find out if the name is at or under the current origin.
11042fe8fb19SBen Gras  * return:
11052fe8fb19SBen Gras  *	Number of characters in name before start of origin,
11062fe8fb19SBen Gras  *	or length of name if origin does not match.
11072fe8fb19SBen Gras  * notes:
11082fe8fb19SBen Gras  *	This function should share code with samedomain().
11092fe8fb19SBen Gras  */
11102fe8fb19SBen Gras static size_t
prune_origin(const char * name,const char * origin)11112fe8fb19SBen Gras prune_origin(const char *name, const char *origin) {
11122fe8fb19SBen Gras 	const char *oname = name;
11132fe8fb19SBen Gras 
11142fe8fb19SBen Gras 	while (*name != '\0') {
11152fe8fb19SBen Gras 		if (origin != NULL && ns_samename(name, origin) == 1)
11162fe8fb19SBen Gras 			return (name - oname - (name > oname));
11172fe8fb19SBen Gras 		while (*name != '\0') {
11182fe8fb19SBen Gras 			if (*name == '\\') {
11192fe8fb19SBen Gras 				name++;
11202fe8fb19SBen Gras 				/* XXX need to handle \nnn form. */
11212fe8fb19SBen Gras 				if (*name == '\0')
11222fe8fb19SBen Gras 					break;
11232fe8fb19SBen Gras 			} else if (*name == '.') {
11242fe8fb19SBen Gras 				name++;
11252fe8fb19SBen Gras 				break;
11262fe8fb19SBen Gras 			}
11272fe8fb19SBen Gras 			name++;
11282fe8fb19SBen Gras 		}
11292fe8fb19SBen Gras 	}
11302fe8fb19SBen Gras 	return (name - oname);
11312fe8fb19SBen Gras }
11322fe8fb19SBen Gras 
11332fe8fb19SBen Gras /*%
11342fe8fb19SBen Gras  * int
11352fe8fb19SBen Gras  * charstr(rdata, edata, buf, buflen)
11362fe8fb19SBen Gras  *	Format a <character-string> into the presentation buffer.
11372fe8fb19SBen Gras  * return:
11382fe8fb19SBen Gras  *	Number of rdata octets consumed
11392fe8fb19SBen Gras  *	0 for protocol format error
11402fe8fb19SBen Gras  *	-1 for output buffer error
11412fe8fb19SBen Gras  * side effects:
11422fe8fb19SBen Gras  *	buffer is advanced on success.
11432fe8fb19SBen Gras  */
11442fe8fb19SBen Gras static int
charstr(const u_char * rdata,const u_char * edata,char ** buf,size_t * buflen)11452fe8fb19SBen Gras charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
11462fe8fb19SBen Gras 	const u_char *odata = rdata;
11472fe8fb19SBen Gras 	size_t save_buflen = *buflen;
11482fe8fb19SBen Gras 	char *save_buf = *buf;
11492fe8fb19SBen Gras 
11502fe8fb19SBen Gras 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
11512fe8fb19SBen Gras 		goto enospc;
11522fe8fb19SBen Gras 	if (rdata < edata) {
11532fe8fb19SBen Gras 		int n = *rdata;
11542fe8fb19SBen Gras 
11552fe8fb19SBen Gras 		if (rdata + 1 + n <= edata) {
11562fe8fb19SBen Gras 			rdata++;
11572fe8fb19SBen Gras 			while (n-- > 0) {
11582fe8fb19SBen Gras 				if (strchr("\n\"\\", *rdata) != NULL)
11592fe8fb19SBen Gras 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
11602fe8fb19SBen Gras 						goto enospc;
11612fe8fb19SBen Gras 				if (addstr((const char *)rdata, (size_t)1,
11622fe8fb19SBen Gras 					   buf, buflen) < 0)
11632fe8fb19SBen Gras 					goto enospc;
11642fe8fb19SBen Gras 				rdata++;
11652fe8fb19SBen Gras 			}
11662fe8fb19SBen Gras 		}
11672fe8fb19SBen Gras 	}
11682fe8fb19SBen Gras 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
11692fe8fb19SBen Gras 		goto enospc;
1170*f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, rdata - odata));
1171*f14fb602SLionel Sambuc 	return (int)(rdata - odata);
11722fe8fb19SBen Gras  enospc:
11732fe8fb19SBen Gras 	errno = ENOSPC;
11742fe8fb19SBen Gras 	*buf = save_buf;
11752fe8fb19SBen Gras 	*buflen = save_buflen;
11762fe8fb19SBen Gras 	return (-1);
11772fe8fb19SBen Gras }
11782fe8fb19SBen Gras 
11792fe8fb19SBen Gras static int
addname(const u_char * msg,size_t msglen,const u_char ** pp,const char * origin,char ** buf,size_t * buflen)11802fe8fb19SBen Gras addname(const u_char *msg, size_t msglen,
11812fe8fb19SBen Gras 	const u_char **pp, const char *origin,
11822fe8fb19SBen Gras 	char **buf, size_t *buflen)
11832fe8fb19SBen Gras {
11842fe8fb19SBen Gras 	size_t newlen, save_buflen = *buflen;
11852fe8fb19SBen Gras 	char *save_buf = *buf;
11862fe8fb19SBen Gras 	int n;
11872fe8fb19SBen Gras 
11882fe8fb19SBen Gras 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
11892fe8fb19SBen Gras 	if (n < 0)
11902fe8fb19SBen Gras 		goto enospc;	/*%< Guess. */
11912fe8fb19SBen Gras 	newlen = prune_origin(*buf, origin);
11922fe8fb19SBen Gras 	if (**buf == '\0') {
11932fe8fb19SBen Gras 		goto root;
11942fe8fb19SBen Gras 	} else if (newlen == 0U) {
11952fe8fb19SBen Gras 		/* Use "@" instead of name. */
11962fe8fb19SBen Gras 		if (newlen + 2 > *buflen)
11972fe8fb19SBen Gras 			goto enospc;        /* No room for "@\0". */
11982fe8fb19SBen Gras 		(*buf)[newlen++] = '@';
11992fe8fb19SBen Gras 		(*buf)[newlen] = '\0';
12002fe8fb19SBen Gras 	} else {
12012fe8fb19SBen Gras 		if (((origin == NULL || origin[0] == '\0') ||
12022fe8fb19SBen Gras 		    (origin[0] != '.' && origin[1] != '\0' &&
12032fe8fb19SBen Gras 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
12042fe8fb19SBen Gras 			/* No trailing dot. */
12052fe8fb19SBen Gras  root:
12062fe8fb19SBen Gras 			if (newlen + 2 > *buflen)
12072fe8fb19SBen Gras 				goto enospc;	/* No room for ".\0". */
12082fe8fb19SBen Gras 			(*buf)[newlen++] = '.';
12092fe8fb19SBen Gras 			(*buf)[newlen] = '\0';
12102fe8fb19SBen Gras 		}
12112fe8fb19SBen Gras 	}
12122fe8fb19SBen Gras 	*pp += n;
12132fe8fb19SBen Gras 	addlen(newlen, buf, buflen);
12142fe8fb19SBen Gras 	**buf = '\0';
1215*f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, newlen));
1216*f14fb602SLionel Sambuc 	return (int)newlen;
12172fe8fb19SBen Gras  enospc:
12182fe8fb19SBen Gras 	errno = ENOSPC;
12192fe8fb19SBen Gras 	*buf = save_buf;
12202fe8fb19SBen Gras 	*buflen = save_buflen;
12212fe8fb19SBen Gras 	return (-1);
12222fe8fb19SBen Gras }
12232fe8fb19SBen Gras 
12242fe8fb19SBen Gras static void
addlen(size_t len,char ** buf,size_t * buflen)12252fe8fb19SBen Gras addlen(size_t len, char **buf, size_t *buflen) {
12262fe8fb19SBen Gras 	INSIST(len <= *buflen);
12272fe8fb19SBen Gras 	*buf += len;
12282fe8fb19SBen Gras 	*buflen -= len;
12292fe8fb19SBen Gras }
12302fe8fb19SBen Gras 
12312fe8fb19SBen Gras static int
addstr(const char * src,size_t len,char ** buf,size_t * buflen)12322fe8fb19SBen Gras addstr(const char *src, size_t len, char **buf, size_t *buflen) {
12332fe8fb19SBen Gras 	if (len >= *buflen) {
12342fe8fb19SBen Gras 		errno = ENOSPC;
12352fe8fb19SBen Gras 		return (-1);
12362fe8fb19SBen Gras 	}
12372fe8fb19SBen Gras 	memcpy(*buf, src, len);
12382fe8fb19SBen Gras 	addlen(len, buf, buflen);
12392fe8fb19SBen Gras 	**buf = '\0';
12402fe8fb19SBen Gras 	return (0);
12412fe8fb19SBen Gras }
12422fe8fb19SBen Gras 
12432fe8fb19SBen Gras static int
addtab(size_t len,size_t target,int spaced,char ** buf,size_t * buflen)12442fe8fb19SBen Gras addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
12452fe8fb19SBen Gras 	size_t save_buflen = *buflen;
12462fe8fb19SBen Gras 	char *save_buf = *buf;
1247*f14fb602SLionel Sambuc 	ptrdiff_t t;
12482fe8fb19SBen Gras 
12492fe8fb19SBen Gras 	if (spaced || len >= target - 1) {
12502fe8fb19SBen Gras 		T(addstr("  ", (size_t)2, buf, buflen));
12512fe8fb19SBen Gras 		spaced = 1;
12522fe8fb19SBen Gras 	} else {
12532fe8fb19SBen Gras 		for (t = (target - len - 1) / 8; t >= 0; t--)
12542fe8fb19SBen Gras 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
12552fe8fb19SBen Gras 				*buflen = save_buflen;
12562fe8fb19SBen Gras 				*buf = save_buf;
12572fe8fb19SBen Gras 				return (-1);
12582fe8fb19SBen Gras 			}
12592fe8fb19SBen Gras 		spaced = 0;
12602fe8fb19SBen Gras 	}
12612fe8fb19SBen Gras 	return (spaced);
12622fe8fb19SBen Gras }
12632fe8fb19SBen Gras 
12642fe8fb19SBen Gras /*! \file */
1265