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