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