Home | History | Annotate | Download | only in nameser
      1 /*	$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 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.3.2.1.4.5 2004/07/28 20:16:45 marka Exp";
     24 #else
     25 __RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 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 <errno.h>
     41 #ifdef ANDROID_CHANGES
     42 #include "resolv_private.h"
     43 #else
     44 #include <resolv.h>
     45 #endif
     46 #include <string.h>
     47 #include <ctype.h>
     48 #include <assert.h>
     49 
     50 #ifdef SPRINTF_CHAR
     51 # define SPRINTF(x) strlen(sprintf/**/x)
     52 #else
     53 # define SPRINTF(x) ((size_t)sprintf x)
     54 #endif
     55 
     56 #ifndef MIN
     57 #define	MIN(x,y)	((x)<(y)?(x):(y))
     58 #endif
     59 
     60 /* Forward. */
     61 
     62 static size_t	prune_origin(const char *name, const char *origin);
     63 static int	charstr(const u_char *rdata, const u_char *edata,
     64 			char **buf, size_t *buflen);
     65 static int	addname(const u_char *msg, size_t msglen,
     66 			const u_char **p, const char *origin,
     67 			char **buf, size_t *buflen);
     68 static void	addlen(size_t len, char **buf, size_t *buflen);
     69 static int	addstr(const char *src, size_t len,
     70 		       char **buf, size_t *buflen);
     71 static int	addtab(size_t len, size_t target, int spaced,
     72 		       char **buf, size_t *buflen);
     73 
     74 /* Macros. */
     75 
     76 #define	T(x) \
     77 	do { \
     78 		if ((x) < 0) \
     79 			return (-1); \
     80 	} while (/*CONSTCOND*/0)
     81 
     82 /* Public. */
     83 
     84 /*
     85  * int
     86  * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
     87  *	Convert an RR to presentation format.
     88  * return:
     89  *	Number of characters written to buf, or -1 (check errno).
     90  */
     91 int
     92 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
     93 	    const char *name_ctx, const char *origin,
     94 	    char *buf, size_t buflen)
     95 {
     96 	int n;
     97 
     98 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
     99 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
    100 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
    101 			 name_ctx, origin, buf, buflen);
    102 	return (n);
    103 }
    104 
    105 /*
    106  * int
    107  * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
    108  *	       name_ctx, origin, buf, buflen)
    109  *	Convert the fields of an RR into presentation format.
    110  * return:
    111  *	Number of characters written to buf, or -1 (check errno).
    112  */
    113 int
    114 ns_sprintrrf(const u_char *msg, size_t msglen,
    115 	    const char *name, ns_class class, ns_type type,
    116 	    u_long ttl, const u_char *rdata, size_t rdlen,
    117 	    const char *name_ctx, const char *origin,
    118 	    char *buf, size_t buflen)
    119 {
    120 	const char *obuf = buf;
    121 	const u_char *edata = rdata + rdlen;
    122 	int spaced = 0;
    123 
    124 	const char *comment;
    125 	char tmp[100];
    126 	int len, x;
    127 
    128 	/*
    129 	 * Owner.
    130 	 */
    131 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
    132 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
    133 	} else {
    134 		len = prune_origin(name, origin);
    135 		if (*name == '\0') {
    136 			goto root;
    137 		} else if (len == 0) {
    138 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
    139 		} else {
    140 			T(addstr(name, (size_t)len, &buf, &buflen));
    141 			/* Origin not used or not root, and no trailing dot? */
    142 			if (((origin == NULL || origin[0] == '\0') ||
    143 			    (origin[0] != '.' && origin[1] != '\0' &&
    144 			    name[len] == '\0')) && name[len - 1] != '.') {
    145  root:
    146 				T(addstr(".", (size_t)1, &buf, &buflen));
    147 				len++;
    148 			}
    149 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
    150 		}
    151 	}
    152 
    153 	/*
    154 	 * TTL, Class, Type.
    155 	 */
    156 	T(x = ns_format_ttl(ttl, buf, buflen));
    157 	addlen((size_t)x, &buf, &buflen);
    158 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
    159 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    160 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
    161 
    162 	/*
    163 	 * RData.
    164 	 */
    165 	switch (type) {
    166 	case ns_t_a:
    167 		if (rdlen != (size_t)NS_INADDRSZ)
    168 			goto formerr;
    169 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
    170 		addlen(strlen(buf), &buf, &buflen);
    171 		break;
    172 
    173 	case ns_t_cname:
    174 	case ns_t_mb:
    175 	case ns_t_mg:
    176 	case ns_t_mr:
    177 	case ns_t_ns:
    178 	case ns_t_ptr:
    179 	case ns_t_dname:
    180 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    181 		break;
    182 
    183 	case ns_t_hinfo:
    184 	case ns_t_isdn:
    185 		/* First word. */
    186 		T(len = charstr(rdata, edata, &buf, &buflen));
    187 		if (len == 0)
    188 			goto formerr;
    189 		rdata += len;
    190 		T(addstr(" ", (size_t)1, &buf, &buflen));
    191 
    192 
    193 		/* Second word, optional in ISDN records. */
    194 		if (type == ns_t_isdn && rdata == edata)
    195 			break;
    196 
    197 		T(len = charstr(rdata, edata, &buf, &buflen));
    198 		if (len == 0)
    199 			goto formerr;
    200 		rdata += len;
    201 		break;
    202 
    203 	case ns_t_soa: {
    204 		u_long t;
    205 
    206 		/* Server name. */
    207 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    208 		T(addstr(" ", (size_t)1, &buf, &buflen));
    209 
    210 		/* Administrator name. */
    211 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    212 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
    213 		spaced = 0;
    214 
    215 		if ((edata - rdata) != 5*NS_INT32SZ)
    216 			goto formerr;
    217 
    218 		/* Serial number. */
    219 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    220 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    221 		len = SPRINTF((tmp, "%lu", t));
    222 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    223 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    224 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
    225 		spaced = 0;
    226 
    227 		/* Refresh interval. */
    228 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    229 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    230 		T(len = ns_format_ttl(t, buf, buflen));
    231 		addlen((size_t)len, &buf, &buflen);
    232 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    233 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
    234 		spaced = 0;
    235 
    236 		/* Retry interval. */
    237 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    238 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    239 		T(len = ns_format_ttl(t, buf, buflen));
    240 		addlen((size_t)len, &buf, &buflen);
    241 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    242 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
    243 		spaced = 0;
    244 
    245 		/* Expiry. */
    246 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    247 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    248 		T(len = ns_format_ttl(t, buf, buflen));
    249 		addlen((size_t)len, &buf, &buflen);
    250 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    251 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
    252 		spaced = 0;
    253 
    254 		/* Minimum TTL. */
    255 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    256 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
    257 		T(len = ns_format_ttl(t, buf, buflen));
    258 		addlen((size_t)len, &buf, &buflen);
    259 		T(addstr(" )", (size_t)2, &buf, &buflen));
    260 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
    261 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
    262 
    263 		break;
    264 	    }
    265 
    266 	case ns_t_mx:
    267 	case ns_t_afsdb:
    268 	case ns_t_rt: {
    269 		u_int t;
    270 
    271 		if (rdlen < (size_t)NS_INT16SZ)
    272 			goto formerr;
    273 
    274 		/* Priority. */
    275 		t = ns_get16(rdata);
    276 		rdata += NS_INT16SZ;
    277 		len = SPRINTF((tmp, "%u ", t));
    278 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    279 
    280 		/* Target. */
    281 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    282 
    283 		break;
    284 	    }
    285 
    286 	case ns_t_px: {
    287 		u_int t;
    288 
    289 		if (rdlen < (size_t)NS_INT16SZ)
    290 			goto formerr;
    291 
    292 		/* Priority. */
    293 		t = ns_get16(rdata);
    294 		rdata += NS_INT16SZ;
    295 		len = SPRINTF((tmp, "%u ", t));
    296 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    297 
    298 		/* Name1. */
    299 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    300 		T(addstr(" ", (size_t)1, &buf, &buflen));
    301 
    302 		/* Name2. */
    303 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    304 
    305 		break;
    306 	    }
    307 
    308 	case ns_t_x25:
    309 		T(len = charstr(rdata, edata, &buf, &buflen));
    310 		if (len == 0)
    311 			goto formerr;
    312 		rdata += len;
    313 		break;
    314 
    315 	case ns_t_txt:
    316 		while (rdata < edata) {
    317 			T(len = charstr(rdata, edata, &buf, &buflen));
    318 			if (len == 0)
    319 				goto formerr;
    320 			rdata += len;
    321 			if (rdata < edata)
    322 				T(addstr(" ", (size_t)1, &buf, &buflen));
    323 		}
    324 		break;
    325 
    326 	case ns_t_nsap: {
    327 		char t[2+255*3];
    328 
    329 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
    330 		T(addstr(t, strlen(t), &buf, &buflen));
    331 		break;
    332 	    }
    333 
    334 	case ns_t_aaaa:
    335 		if (rdlen != (size_t)NS_IN6ADDRSZ)
    336 			goto formerr;
    337 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
    338 		addlen(strlen(buf), &buf, &buflen);
    339 		break;
    340 
    341 	case ns_t_loc: {
    342 		char t[255];
    343 
    344 		/* XXX protocol format checking? */
    345 		(void) loc_ntoa(rdata, t);
    346 		T(addstr(t, strlen(t), &buf, &buflen));
    347 		break;
    348 	    }
    349 
    350 	case ns_t_naptr: {
    351 		u_int order, preference;
    352 		char t[50];
    353 
    354 		if (rdlen < 2U*NS_INT16SZ)
    355 			goto formerr;
    356 
    357 		/* Order, Precedence. */
    358 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
    359 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
    360 		len = SPRINTF((t, "%u %u ", order, preference));
    361 		T(addstr(t, (size_t)len, &buf, &buflen));
    362 
    363 		/* Flags. */
    364 		T(len = charstr(rdata, edata, &buf, &buflen));
    365 		if (len == 0)
    366 			goto formerr;
    367 		rdata += len;
    368 		T(addstr(" ", (size_t)1, &buf, &buflen));
    369 
    370 		/* Service. */
    371 		T(len = charstr(rdata, edata, &buf, &buflen));
    372 		if (len == 0)
    373 			goto formerr;
    374 		rdata += len;
    375 		T(addstr(" ", (size_t)1, &buf, &buflen));
    376 
    377 		/* Regexp. */
    378 		T(len = charstr(rdata, edata, &buf, &buflen));
    379 		if (len < 0)
    380 			return (-1);
    381 		if (len == 0)
    382 			goto formerr;
    383 		rdata += len;
    384 		T(addstr(" ", (size_t)1, &buf, &buflen));
    385 
    386 		/* Server. */
    387 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    388 		break;
    389 	    }
    390 
    391 	case ns_t_srv: {
    392 		u_int priority, weight, port;
    393 		char t[50];
    394 
    395 		if (rdlen < 3U*NS_INT16SZ)
    396 			goto formerr;
    397 
    398 		/* Priority, Weight, Port. */
    399 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
    400 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
    401 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
    402 		len = SPRINTF((t, "%u %u %u ", priority, weight, 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 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
    429 		addlen(strlen(buf), &buf, &buflen);
    430 		rdata += NS_INADDRSZ;
    431 
    432 		/* Protocol. */
    433 		len = SPRINTF((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 = SPRINTF((tmp, "%d ", n));
    451 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    452 					lcnt--;
    453 				}
    454 				c <<= 1;
    455 			} while (++n & 07);
    456 		}
    457 		T(addstr(")", (size_t)1, &buf, &buflen));
    458 
    459 		break;
    460 	    }
    461 
    462 	case ns_t_key: {
    463 		char base64_key[NS_MD5RSA_MAX_BASE64];
    464 		u_int keyflags, protocol, algorithm, key_id;
    465 		const char *leader;
    466 		int n;
    467 
    468 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
    469 			goto formerr;
    470 
    471 		/* Key flags, Protocol, Algorithm. */
    472 #ifndef _LIBC
    473 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
    474 #else
    475 		key_id = 0;
    476 #endif
    477 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
    478 		protocol = *rdata++;
    479 		algorithm = *rdata++;
    480 		len = SPRINTF((tmp, "0x%04x %u %u",
    481 			       keyflags, protocol, algorithm));
    482 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    483 
    484 		/* Public key data. */
    485 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    486 			       base64_key, sizeof base64_key);
    487 		if (len < 0)
    488 			goto formerr;
    489 		if (len > 15) {
    490 			T(addstr(" (", (size_t)2, &buf, &buflen));
    491 			leader = "\n\t\t";
    492 			spaced = 0;
    493 		} else
    494 			leader = " ";
    495 		for (n = 0; n < len; n += 48) {
    496 			T(addstr(leader, strlen(leader), &buf, &buflen));
    497 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    498 				 &buf, &buflen));
    499 		}
    500 		if (len > 15)
    501 			T(addstr(" )", (size_t)2, &buf, &buflen));
    502 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
    503 		T(addstr(tmp, (size_t)n, &buf, &buflen));
    504 
    505 		break;
    506 	    }
    507 
    508 	case ns_t_sig: {
    509 		char base64_key[NS_MD5RSA_MAX_BASE64];
    510 		u_int typ, algorithm, labels, footprint;
    511 		const char *leader;
    512 		u_long t;
    513 		int n;
    514 
    515 		if (rdlen < 22U)
    516 			goto formerr;
    517 
    518 		/* Type covered, Algorithm, Label count, Original TTL. */
    519 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
    520 		algorithm = *rdata++;
    521 		labels = *rdata++;
    522 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    523 		len = SPRINTF((tmp, "%s %d %d %lu ",
    524 			       p_type((int)typ), algorithm, labels, t));
    525 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    526 		if (labels > (u_int)dn_count_labels(name))
    527 			goto formerr;
    528 
    529 		/* Signature expiry. */
    530 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    531 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    532 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    533 
    534 		/* Time signed. */
    535 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    536 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    537 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    538 
    539 		/* Signature Footprint. */
    540 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
    541 		len = SPRINTF((tmp, "%u ", footprint));
    542 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    543 
    544 		/* Signer's name. */
    545 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    546 
    547 		/* Signature. */
    548 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    549 			       base64_key, sizeof base64_key);
    550 		if (len > 15) {
    551 			T(addstr(" (", (size_t)2, &buf, &buflen));
    552 			leader = "\n\t\t";
    553 			spaced = 0;
    554 		} else
    555 			leader = " ";
    556 		if (len < 0)
    557 			goto formerr;
    558 		for (n = 0; n < len; n += 48) {
    559 			T(addstr(leader, strlen(leader), &buf, &buflen));
    560 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    561 				 &buf, &buflen));
    562 		}
    563 		if (len > 15)
    564 			T(addstr(" )", (size_t)2, &buf, &buflen));
    565 		break;
    566 	    }
    567 
    568 	case ns_t_nxt: {
    569 		int n, c;
    570 
    571 		/* Next domain name. */
    572 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    573 
    574 		/* Type bit map. */
    575 		n = edata - rdata;
    576 		for (c = 0; c < n*8; c++)
    577 			if (NS_NXT_BIT_ISSET(c, rdata)) {
    578 				len = SPRINTF((tmp, " %s", p_type(c)));
    579 				T(addstr(tmp, (size_t)len, &buf, &buflen));
    580 			}
    581 		break;
    582 	    }
    583 
    584 	case ns_t_cert: {
    585 		u_int c_type, key_tag, alg;
    586 		int n;
    587 		unsigned int siz;
    588 		char base64_cert[8192], tmp1[40];
    589 		const char *leader;
    590 
    591 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
    592 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
    593 		alg = (u_int) *rdata++;
    594 
    595 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
    596 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
    597 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    598 		if (siz > sizeof(base64_cert) * 3/4) {
    599 			const char *str = "record too long to print";
    600 			T(addstr(str, strlen(str), &buf, &buflen));
    601 		}
    602 		else {
    603 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    604 			    base64_cert, siz);
    605 
    606 			if (len < 0)
    607 				goto formerr;
    608 			else if (len > 15) {
    609 				T(addstr(" (", (size_t)2, &buf, &buflen));
    610 				leader = "\n\t\t";
    611 				spaced = 0;
    612 			}
    613 			else
    614 				leader = " ";
    615 
    616 			for (n = 0; n < len; n += 48) {
    617 				T(addstr(leader, strlen(leader),
    618 					 &buf, &buflen));
    619 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
    620 					 &buf, &buflen));
    621 			}
    622 			if (len > 15)
    623 				T(addstr(" )", (size_t)2, &buf, &buflen));
    624 		}
    625 		break;
    626 	    }
    627 
    628 	case ns_t_tkey: {
    629 		/* KJD - need to complete this */
    630 		u_long t;
    631 		int mode, err, keysize;
    632 
    633 		/* Algorithm name. */
    634 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    635 		T(addstr(" ", (size_t)1, &buf, &buflen));
    636 
    637 		/* Inception. */
    638 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    639 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    640 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    641 
    642 		/* Experation. */
    643 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    644 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    645 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    646 
    647 		/* Mode , Error, Key Size. */
    648 		/* Priority, Weight, Port. */
    649 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
    650 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
    651 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
    652 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
    653 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    654 
    655 		/* XXX need to dump key, print otherdata length & other data */
    656 		break;
    657 	    }
    658 
    659 	case ns_t_tsig: {
    660 		/* BEW - need to complete this */
    661 		int n;
    662 
    663 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
    664 		T(addstr(" ", (size_t)1, &buf, &buflen));
    665 		rdata += 8; /* time */
    666 		n = ns_get16(rdata); rdata += INT16SZ;
    667 		rdata += n; /* sig */
    668 		n = ns_get16(rdata); rdata += INT16SZ; /* original id */
    669 		sprintf(buf, "%d", ns_get16(rdata));
    670 		rdata += INT16SZ;
    671 		addlen(strlen(buf), &buf, &buflen);
    672 		break;
    673 	    }
    674 
    675 	case ns_t_a6: {
    676 		struct in6_addr a;
    677 		int pbyte, pbit;
    678 
    679 		/* prefix length */
    680 		if (rdlen == 0U) goto formerr;
    681 		len = SPRINTF((tmp, "%d ", *rdata));
    682 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    683 		pbit = *rdata;
    684 		if (pbit > 128) goto formerr;
    685 		pbyte = (pbit & ~7) / 8;
    686 		rdata++;
    687 
    688 		/* address suffix: provided only when prefix len != 128 */
    689 		if (pbit < 128) {
    690 			if (rdata + pbyte >= edata) goto formerr;
    691 			memset(&a, 0, sizeof(a));
    692 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
    693 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
    694 			addlen(strlen(buf), &buf, &buflen);
    695 			rdata += sizeof(a) - pbyte;
    696 		}
    697 
    698 		/* prefix name: provided only when prefix len > 0 */
    699 		if (pbit == 0)
    700 			break;
    701 		if (rdata >= edata) goto formerr;
    702 		T(addstr(" ", (size_t)1, &buf, &buflen));
    703 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    704 
    705 		break;
    706 	    }
    707 
    708 	case ns_t_opt: {
    709 		len = SPRINTF((tmp, "%u bytes", class));
    710 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    711 		break;
    712 	    }
    713 
    714 	default:
    715 		comment = "unknown RR type";
    716 		goto hexify;
    717 	}
    718 	return (buf - obuf);
    719  formerr:
    720 	comment = "RR format error";
    721  hexify: {
    722 	int n, m;
    723 	char *p;
    724 
    725 	len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata,
    726 		       rdlen != 0 ? " (" : "", comment));
    727 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    728 	while (rdata < edata) {
    729 		p = tmp;
    730 		p += SPRINTF((p, "\n\t"));
    731 		spaced = 0;
    732 		n = MIN(16, edata - rdata);
    733 		for (m = 0; m < n; m++)
    734 			p += SPRINTF((p, "%02x ", rdata[m]));
    735 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
    736 		if (n < 16) {
    737 			T(addstr(")", (size_t)1, &buf, &buflen));
    738 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
    739 		}
    740 		p = tmp;
    741 		p += SPRINTF((p, "; "));
    742 		for (m = 0; m < n; m++)
    743 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
    744 				? rdata[m]
    745 				: '.';
    746 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
    747 		rdata += n;
    748 	}
    749 	return (buf - obuf);
    750     }
    751 }
    752 
    753 /* Private. */
    754 
    755 /*
    756  * size_t
    757  * prune_origin(name, origin)
    758  *	Find out if the name is at or under the current origin.
    759  * return:
    760  *	Number of characters in name before start of origin,
    761  *	or length of name if origin does not match.
    762  * notes:
    763  *	This function should share code with samedomain().
    764  */
    765 static size_t
    766 prune_origin(const char *name, const char *origin) {
    767 	const char *oname = name;
    768 
    769 	while (*name != '\0') {
    770 		if (origin != NULL && ns_samename(name, origin) == 1)
    771 			return (name - oname - (name > oname));
    772 		while (*name != '\0') {
    773 			if (*name == '\\') {
    774 				name++;
    775 				/* XXX need to handle \nnn form. */
    776 				if (*name == '\0')
    777 					break;
    778 			} else if (*name == '.') {
    779 				name++;
    780 				break;
    781 			}
    782 			name++;
    783 		}
    784 	}
    785 	return (name - oname);
    786 }
    787 
    788 /*
    789  * int
    790  * charstr(rdata, edata, buf, buflen)
    791  *	Format a <character-string> into the presentation buffer.
    792  * return:
    793  *	Number of rdata octets consumed
    794  *	0 for protocol format error
    795  *	-1 for output buffer error
    796  * side effects:
    797  *	buffer is advanced on success.
    798  */
    799 static int
    800 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
    801 	const u_char *odata = rdata;
    802 	size_t save_buflen = *buflen;
    803 	char *save_buf = *buf;
    804 
    805 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
    806 		goto enospc;
    807 	if (rdata < edata) {
    808 		int n = *rdata;
    809 
    810 		if (rdata + 1 + n <= edata) {
    811 			rdata++;
    812 			while (n-- > 0) {
    813 				if (strchr("\n\"\\", *rdata) != NULL)
    814 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
    815 						goto enospc;
    816 				if (addstr((const char *)rdata, (size_t)1,
    817 					   buf, buflen) < 0)
    818 					goto enospc;
    819 				rdata++;
    820 			}
    821 		}
    822 	}
    823 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
    824 		goto enospc;
    825 	return (rdata - odata);
    826  enospc:
    827 	errno = ENOSPC;
    828 	*buf = save_buf;
    829 	*buflen = save_buflen;
    830 	return (-1);
    831 }
    832 
    833 static int
    834 addname(const u_char *msg, size_t msglen,
    835 	const u_char **pp, const char *origin,
    836 	char **buf, size_t *buflen)
    837 {
    838 	size_t newlen, save_buflen = *buflen;
    839 	char *save_buf = *buf;
    840 	int n;
    841 
    842 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
    843 	if (n < 0)
    844 		goto enospc;	/* Guess. */
    845 	newlen = prune_origin(*buf, origin);
    846 	if (**buf == '\0') {
    847 		goto root;
    848 	} else if (newlen == 0U) {
    849 		/* Use "@" instead of name. */
    850 		if (newlen + 2 > *buflen)
    851 			goto enospc;        /* No room for "@\0". */
    852 		(*buf)[newlen++] = '@';
    853 		(*buf)[newlen] = '\0';
    854 	} else {
    855 		if (((origin == NULL || origin[0] == '\0') ||
    856 		    (origin[0] != '.' && origin[1] != '\0' &&
    857 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
    858 			/* No trailing dot. */
    859  root:
    860 			if (newlen + 2 > *buflen)
    861 				goto enospc;	/* No room for ".\0". */
    862 			(*buf)[newlen++] = '.';
    863 			(*buf)[newlen] = '\0';
    864 		}
    865 	}
    866 	*pp += n;
    867 	addlen(newlen, buf, buflen);
    868 	**buf = '\0';
    869 	return (newlen);
    870  enospc:
    871 	errno = ENOSPC;
    872 	*buf = save_buf;
    873 	*buflen = save_buflen;
    874 	return (-1);
    875 }
    876 
    877 static void
    878 addlen(size_t len, char **buf, size_t *buflen) {
    879 	assert(len <= *buflen);
    880 	*buf += len;
    881 	*buflen -= len;
    882 }
    883 
    884 static int
    885 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
    886 	if (len >= *buflen) {
    887 		errno = ENOSPC;
    888 		return (-1);
    889 	}
    890 	memcpy(*buf, src, len);
    891 	addlen(len, buf, buflen);
    892 	**buf = '\0';
    893 	return (0);
    894 }
    895 
    896 static int
    897 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
    898 	size_t save_buflen = *buflen;
    899 	char *save_buf = *buf;
    900 	int t;
    901 
    902 	if (spaced || len >= target - 1) {
    903 		T(addstr("  ", (size_t)2, buf, buflen));
    904 		spaced = 1;
    905 	} else {
    906 		for (t = (target - len - 1) / 8; t >= 0; t--)
    907 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
    908 				*buflen = save_buflen;
    909 				*buf = save_buf;
    910 				return (-1);
    911 			}
    912 		spaced = 0;
    913 	}
    914 	return (spaced);
    915 }
    916