Home | History | Annotate | Line # | Download | only in nameser
ns_print.c revision 1.2
      1 /*	$NetBSD: ns_print.c,v 1.2 2004/05/20 20:35:05 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.4 2004/03/17 01:13:36 marka Exp";
     24 #else
     25 __RCSID("$NetBSD: ns_print.c,v 1.2 2004/05/20 20:35:05 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 <errno.h>
     43 #include <resolv.h>
     44 #include <string.h>
     45 #include <ctype.h>
     46 
     47 #include "port_after.h"
     48 
     49 #ifdef SPRINTF_CHAR
     50 # define SPRINTF(x) strlen(sprintf/**/x)
     51 #else
     52 # define SPRINTF(x) ((size_t)sprintf x)
     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 /* Public. */
     78 
     79 /*
     80  * int
     81  * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
     82  *	Convert an RR to presentation format.
     83  * return:
     84  *	Number of characters written to buf, or -1 (check errno).
     85  */
     86 int
     87 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
     88 	    const char *name_ctx, const char *origin,
     89 	    char *buf, size_t buflen)
     90 {
     91 	int n;
     92 
     93 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
     94 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
     95 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
     96 			 name_ctx, origin, buf, buflen);
     97 	return (n);
     98 }
     99 
    100 /*
    101  * int
    102  * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
    103  *	       name_ctx, origin, buf, buflen)
    104  *	Convert the fields of an RR into presentation format.
    105  * return:
    106  *	Number of characters written to buf, or -1 (check errno).
    107  */
    108 int
    109 ns_sprintrrf(const u_char *msg, size_t msglen,
    110 	    const char *name, ns_class class, ns_type type,
    111 	    u_long ttl, const u_char *rdata, size_t rdlen,
    112 	    const char *name_ctx, const char *origin,
    113 	    char *buf, size_t buflen)
    114 {
    115 	const char *obuf = buf;
    116 	const u_char *edata = rdata + rdlen;
    117 	int spaced = 0;
    118 
    119 	const char *comment;
    120 	char tmp[100];
    121 	int len, x;
    122 
    123 	/*
    124 	 * Owner.
    125 	 */
    126 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
    127 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
    128 	} else {
    129 		len = prune_origin(name, origin);
    130 		if (*name == '\0') {
    131 			goto root;
    132 		} else if (len == 0) {
    133 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
    134 		} else {
    135 			T(addstr(name, (size_t)len, &buf, &buflen));
    136 			/* Origin not used or not root, and no trailing dot? */
    137 			if (((origin == NULL || origin[0] == '\0') ||
    138 			    (origin[0] != '.' && origin[1] != '\0' &&
    139 			    name[len] == '\0')) && name[len - 1] != '.') {
    140  root:
    141 				T(addstr(".", (size_t)1, &buf, &buflen));
    142 				len++;
    143 			}
    144 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
    145 		}
    146 	}
    147 
    148 	/*
    149 	 * TTL, Class, Type.
    150 	 */
    151 	T(x = ns_format_ttl(ttl, buf, buflen));
    152 	addlen((size_t)x, &buf, &buflen);
    153 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
    154 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    155 	if (rdlen == 0U)
    156 		return (buf - obuf);
    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 		(void) inet_ntop(AF_INET, rdata, buf, 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 = SPRINTF((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 		u_int t;
    267 
    268 		if (rdlen < (size_t)NS_INT16SZ)
    269 			goto formerr;
    270 
    271 		/* Priority. */
    272 		t = ns_get16(rdata);
    273 		rdata += NS_INT16SZ;
    274 		len = SPRINTF((tmp, "%u ", t));
    275 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    276 
    277 		/* Target. */
    278 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    279 
    280 		break;
    281 	    }
    282 
    283 	case ns_t_px: {
    284 		u_int t;
    285 
    286 		if (rdlen < (size_t)NS_INT16SZ)
    287 			goto formerr;
    288 
    289 		/* Priority. */
    290 		t = ns_get16(rdata);
    291 		rdata += NS_INT16SZ;
    292 		len = SPRINTF((tmp, "%u ", t));
    293 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    294 
    295 		/* Name1. */
    296 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    297 		T(addstr(" ", (size_t)1, &buf, &buflen));
    298 
    299 		/* Name2. */
    300 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    301 
    302 		break;
    303 	    }
    304 
    305 	case ns_t_x25:
    306 		T(len = charstr(rdata, edata, &buf, &buflen));
    307 		if (len == 0)
    308 			goto formerr;
    309 		rdata += len;
    310 		break;
    311 
    312 	case ns_t_txt:
    313 		while (rdata < edata) {
    314 			T(len = charstr(rdata, edata, &buf, &buflen));
    315 			if (len == 0)
    316 				goto formerr;
    317 			rdata += len;
    318 			if (rdata < edata)
    319 				T(addstr(" ", (size_t)1, &buf, &buflen));
    320 		}
    321 		break;
    322 
    323 	case ns_t_nsap: {
    324 		char t[2+255*3];
    325 
    326 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
    327 		T(addstr(t, strlen(t), &buf, &buflen));
    328 		break;
    329 	    }
    330 
    331 	case ns_t_aaaa:
    332 		if (rdlen != (size_t)NS_IN6ADDRSZ)
    333 			goto formerr;
    334 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
    335 		addlen(strlen(buf), &buf, &buflen);
    336 		break;
    337 
    338 	case ns_t_loc: {
    339 		char t[255];
    340 
    341 		/* XXX protocol format checking? */
    342 		(void) loc_ntoa(rdata, t);
    343 		T(addstr(t, strlen(t), &buf, &buflen));
    344 		break;
    345 	    }
    346 
    347 	case ns_t_naptr: {
    348 		u_int order, preference;
    349 		char t[50];
    350 
    351 		if (rdlen < 2U*NS_INT16SZ)
    352 			goto formerr;
    353 
    354 		/* Order, Precedence. */
    355 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
    356 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
    357 		len = SPRINTF((t, "%u %u ", order, preference));
    358 		T(addstr(t, (size_t)len, &buf, &buflen));
    359 
    360 		/* Flags. */
    361 		T(len = charstr(rdata, edata, &buf, &buflen));
    362 		if (len == 0)
    363 			goto formerr;
    364 		rdata += len;
    365 		T(addstr(" ", (size_t)1, &buf, &buflen));
    366 
    367 		/* Service. */
    368 		T(len = charstr(rdata, edata, &buf, &buflen));
    369 		if (len == 0)
    370 			goto formerr;
    371 		rdata += len;
    372 		T(addstr(" ", (size_t)1, &buf, &buflen));
    373 
    374 		/* Regexp. */
    375 		T(len = charstr(rdata, edata, &buf, &buflen));
    376 		if (len < 0)
    377 			return (-1);
    378 		if (len == 0)
    379 			goto formerr;
    380 		rdata += len;
    381 		T(addstr(" ", (size_t)1, &buf, &buflen));
    382 
    383 		/* Server. */
    384 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    385 		break;
    386 	    }
    387 
    388 	case ns_t_srv: {
    389 		u_int priority, weight, port;
    390 		char t[50];
    391 
    392 		if (rdlen < 3U*NS_INT16SZ)
    393 			goto formerr;
    394 
    395 		/* Priority, Weight, Port. */
    396 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
    397 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
    398 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
    399 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
    400 		T(addstr(t, (size_t)len, &buf, &buflen));
    401 
    402 		/* Server. */
    403 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    404 		break;
    405 	    }
    406 
    407 	case ns_t_minfo:
    408 	case ns_t_rp:
    409 		/* Name1. */
    410 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    411 		T(addstr(" ", (size_t)1, &buf, &buflen));
    412 
    413 		/* Name2. */
    414 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    415 
    416 		break;
    417 
    418 	case ns_t_wks: {
    419 		int n, lcnt;
    420 
    421 		if (rdlen < 1U + NS_INT32SZ)
    422 			goto formerr;
    423 
    424 		/* Address. */
    425 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
    426 		addlen(strlen(buf), &buf, &buflen);
    427 		rdata += NS_INADDRSZ;
    428 
    429 		/* Protocol. */
    430 		len = SPRINTF((tmp, " %u ( ", *rdata));
    431 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    432 		rdata += NS_INT8SZ;
    433 
    434 		/* Bit map. */
    435 		n = 0;
    436 		lcnt = 0;
    437 		while (rdata < edata) {
    438 			u_int c = *rdata++;
    439 			do {
    440 				if (c & 0200) {
    441 					if (lcnt == 0) {
    442 						T(addstr("\n\t\t\t\t", (size_t)5,
    443 							 &buf, &buflen));
    444 						lcnt = 10;
    445 						spaced = 0;
    446 					}
    447 					len = SPRINTF((tmp, "%d ", n));
    448 					T(addstr(tmp, (size_t)len, &buf, &buflen));
    449 					lcnt--;
    450 				}
    451 				c <<= 1;
    452 			} while (++n & 07);
    453 		}
    454 		T(addstr(")", (size_t)1, &buf, &buflen));
    455 
    456 		break;
    457 	    }
    458 
    459 	case ns_t_key: {
    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 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
    470 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
    471 		protocol = *rdata++;
    472 		algorithm = *rdata++;
    473 		len = SPRINTF((tmp, "0x%04x %u %u",
    474 			       keyflags, protocol, algorithm));
    475 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    476 
    477 		/* Public key data. */
    478 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    479 			       base64_key, sizeof base64_key);
    480 		if (len < 0)
    481 			goto formerr;
    482 		if (len > 15) {
    483 			T(addstr(" (", (size_t)2, &buf, &buflen));
    484 			leader = "\n\t\t";
    485 			spaced = 0;
    486 		} else
    487 			leader = " ";
    488 		for (n = 0; n < len; n += 48) {
    489 			T(addstr(leader, strlen(leader), &buf, &buflen));
    490 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    491 				 &buf, &buflen));
    492 		}
    493 		if (len > 15)
    494 			T(addstr(" )", (size_t)2, &buf, &buflen));
    495 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
    496 		T(addstr(tmp, (size_t)n, &buf, &buflen));
    497 
    498 		break;
    499 	    }
    500 
    501 	case ns_t_sig: {
    502 		char base64_key[NS_MD5RSA_MAX_BASE64];
    503 		u_int typ, algorithm, labels, footprint;
    504 		const char *leader;
    505 		u_long t;
    506 		int n;
    507 
    508 		if (rdlen < 22U)
    509 			goto formerr;
    510 
    511 		/* Type covered, Algorithm, Label count, Original TTL. */
    512 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
    513 		algorithm = *rdata++;
    514 		labels = *rdata++;
    515 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    516 		len = SPRINTF((tmp, "%s %d %d %lu ",
    517 			       p_type((int)typ), algorithm, labels, t));
    518 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    519 		if (labels > (u_int)dn_count_labels(name))
    520 			goto formerr;
    521 
    522 		/* Signature expiry. */
    523 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    524 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    525 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    526 
    527 		/* Time signed. */
    528 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    529 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    530 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    531 
    532 		/* Signature Footprint. */
    533 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
    534 		len = SPRINTF((tmp, "%u ", footprint));
    535 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    536 
    537 		/* Signer's name. */
    538 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    539 
    540 		/* Signature. */
    541 		len = b64_ntop(rdata, (size_t)(edata - rdata),
    542 			       base64_key, sizeof base64_key);
    543 		if (len > 15) {
    544 			T(addstr(" (", (size_t)2, &buf, &buflen));
    545 			leader = "\n\t\t";
    546 			spaced = 0;
    547 		} else
    548 			leader = " ";
    549 		if (len < 0)
    550 			goto formerr;
    551 		for (n = 0; n < len; n += 48) {
    552 			T(addstr(leader, strlen(leader), &buf, &buflen));
    553 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
    554 				 &buf, &buflen));
    555 		}
    556 		if (len > 15)
    557 			T(addstr(" )", (size_t)2, &buf, &buflen));
    558 		break;
    559 	    }
    560 
    561 	case ns_t_nxt: {
    562 		int n, c;
    563 
    564 		/* Next domain name. */
    565 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    566 
    567 		/* Type bit map. */
    568 		n = edata - rdata;
    569 		for (c = 0; c < n*8; c++)
    570 			if (NS_NXT_BIT_ISSET(c, rdata)) {
    571 				len = SPRINTF((tmp, " %s", p_type(c)));
    572 				T(addstr(tmp, (size_t)len, &buf, &buflen));
    573 			}
    574 		break;
    575 	    }
    576 
    577 	case ns_t_cert: {
    578 		u_int c_type, key_tag, alg;
    579 		int n;
    580 		unsigned int siz;
    581 		char base64_cert[8192], tmp1[40];
    582 		const char *leader;
    583 
    584 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
    585 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
    586 		alg = (u_int) *rdata++;
    587 
    588 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
    589 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
    590 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
    591 		if (siz > sizeof(base64_cert) * 3/4) {
    592 			const char *str = "record too long to print";
    593 			T(addstr(str, strlen(str), &buf, &buflen));
    594 		}
    595 		else {
    596 			len = b64_ntop(rdata, (size_t)(edata-rdata),
    597 			    base64_cert, siz);
    598 
    599 			if (len < 0)
    600 				goto formerr;
    601 			else if (len > 15) {
    602 				T(addstr(" (", (size_t)2, &buf, &buflen));
    603 				leader = "\n\t\t";
    604 				spaced = 0;
    605 			}
    606 			else
    607 				leader = " ";
    608 
    609 			for (n = 0; n < len; n += 48) {
    610 				T(addstr(leader, strlen(leader),
    611 					 &buf, &buflen));
    612 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
    613 					 &buf, &buflen));
    614 			}
    615 			if (len > 15)
    616 				T(addstr(" )", (size_t)2, &buf, &buflen));
    617 		}
    618 		break;
    619 	    }
    620 
    621 	case ns_t_tkey: {
    622 		/* KJD - need to complete this */
    623 		u_long t;
    624 		int mode, err, keysize;
    625 
    626 		/* Algorithm name. */
    627 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    628 		T(addstr(" ", (size_t)1, &buf, &buflen));
    629 
    630 		/* Inception. */
    631 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    632 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    633 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    634 
    635 		/* Experation. */
    636 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
    637 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
    638 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    639 
    640 		/* Mode , Error, Key Size. */
    641 		/* Priority, Weight, Port. */
    642 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
    643 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
    644 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
    645 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
    646 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    647 
    648 		/* XXX need to dump key, print otherdata length & other data */
    649 		break;
    650 	    }
    651 
    652 	case ns_t_tsig: {
    653 		/* BEW - need to complete this */
    654 		int n;
    655 
    656 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
    657 		T(addstr(" ", (size_t)1, &buf, &buflen));
    658 		rdata += 8; /* time */
    659 		n = ns_get16(rdata); rdata += INT16SZ;
    660 		rdata += n; /* sig */
    661 		n = ns_get16(rdata); rdata += INT16SZ; /* original id */
    662 		sprintf(buf, "%d", ns_get16(rdata));
    663 		rdata += INT16SZ;
    664 		addlen(strlen(buf), &buf, &buflen);
    665 		break;
    666 	    }
    667 
    668 	case ns_t_a6: {
    669 		struct in6_addr a;
    670 		int pbyte, pbit;
    671 
    672 		/* prefix length */
    673 		if (rdlen == 0U) goto formerr;
    674 		len = SPRINTF((tmp, "%d ", *rdata));
    675 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    676 		pbit = *rdata;
    677 		if (pbit > 128) goto formerr;
    678 		pbyte = (pbit & ~7) / 8;
    679 		rdata++;
    680 
    681 		/* address suffix: provided only when prefix len != 128 */
    682 		if (pbit < 128) {
    683 			if (rdata + pbyte >= edata) goto formerr;
    684 			memset(&a, 0, sizeof(a));
    685 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
    686 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
    687 			addlen(strlen(buf), &buf, &buflen);
    688 			rdata += sizeof(a) - pbyte;
    689 		}
    690 
    691 		/* prefix name: provided only when prefix len > 0 */
    692 		if (pbit == 0)
    693 			break;
    694 		if (rdata >= edata) goto formerr;
    695 		T(addstr(" ", (size_t)1, &buf, &buflen));
    696 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
    697 
    698 		break;
    699 	    }
    700 
    701 	case ns_t_opt: {
    702 		len = SPRINTF((tmp, "%u bytes", class));
    703 		T(addstr(tmp, (size_t)len, &buf, &buflen));
    704 		break;
    705 	    }
    706 
    707 	default:
    708 		comment = "unknown RR type";
    709 		goto hexify;
    710 	}
    711 	return (buf - obuf);
    712  formerr:
    713 	comment = "RR format error";
    714  hexify: {
    715 	int n, m;
    716 	char *p;
    717 
    718 	len = SPRINTF((tmp, "\\# %u (\t; %s", edata - rdata, comment));
    719 	T(addstr(tmp, (size_t)len, &buf, &buflen));
    720 	while (rdata < edata) {
    721 		p = tmp;
    722 		p += SPRINTF((p, "\n\t"));
    723 		spaced = 0;
    724 		n = MIN(16, edata - rdata);
    725 		for (m = 0; m < n; m++)
    726 			p += SPRINTF((p, "%02x ", rdata[m]));
    727 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
    728 		if (n < 16) {
    729 			T(addstr(")", (size_t)1, &buf, &buflen));
    730 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
    731 		}
    732 		p = tmp;
    733 		p += SPRINTF((p, "; "));
    734 		for (m = 0; m < n; m++)
    735 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
    736 				? rdata[m]
    737 				: '.';
    738 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
    739 		rdata += n;
    740 	}
    741 	return (buf - obuf);
    742     }
    743 }
    744 
    745 /* Private. */
    746 
    747 /*
    748  * size_t
    749  * prune_origin(name, origin)
    750  *	Find out if the name is at or under the current origin.
    751  * return:
    752  *	Number of characters in name before start of origin,
    753  *	or length of name if origin does not match.
    754  * notes:
    755  *	This function should share code with samedomain().
    756  */
    757 static size_t
    758 prune_origin(const char *name, const char *origin) {
    759 	const char *oname = name;
    760 
    761 	while (*name != '\0') {
    762 		if (origin != NULL && ns_samename(name, origin) == 1)
    763 			return (name - oname - (name > oname));
    764 		while (*name != '\0') {
    765 			if (*name == '\\') {
    766 				name++;
    767 				/* XXX need to handle \nnn form. */
    768 				if (*name == '\0')
    769 					break;
    770 			} else if (*name == '.') {
    771 				name++;
    772 				break;
    773 			}
    774 			name++;
    775 		}
    776 	}
    777 	return (name - oname);
    778 }
    779 
    780 /*
    781  * int
    782  * charstr(rdata, edata, buf, buflen)
    783  *	Format a <character-string> into the presentation buffer.
    784  * return:
    785  *	Number of rdata octets consumed
    786  *	0 for protocol format error
    787  *	-1 for output buffer error
    788  * side effects:
    789  *	buffer is advanced on success.
    790  */
    791 static int
    792 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
    793 	const u_char *odata = rdata;
    794 	size_t save_buflen = *buflen;
    795 	char *save_buf = *buf;
    796 
    797 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
    798 		goto enospc;
    799 	if (rdata < edata) {
    800 		int n = *rdata;
    801 
    802 		if (rdata + 1 + n <= edata) {
    803 			rdata++;
    804 			while (n-- > 0) {
    805 				if (strchr("\n\"\\", *rdata) != NULL)
    806 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
    807 						goto enospc;
    808 				if (addstr((const char *)rdata, (size_t)1,
    809 					   buf, buflen) < 0)
    810 					goto enospc;
    811 				rdata++;
    812 			}
    813 		}
    814 	}
    815 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
    816 		goto enospc;
    817 	return (rdata - odata);
    818  enospc:
    819 	errno = ENOSPC;
    820 	*buf = save_buf;
    821 	*buflen = save_buflen;
    822 	return (-1);
    823 }
    824 
    825 static int
    826 addname(const u_char *msg, size_t msglen,
    827 	const u_char **pp, const char *origin,
    828 	char **buf, size_t *buflen)
    829 {
    830 	size_t newlen, save_buflen = *buflen;
    831 	char *save_buf = *buf;
    832 	int n;
    833 
    834 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
    835 	if (n < 0)
    836 		goto enospc;	/* Guess. */
    837 	newlen = prune_origin(*buf, origin);
    838 	if (**buf == '\0') {
    839 		goto root;
    840 	} else if (newlen == 0U) {
    841 		/* Use "@" instead of name. */
    842 		if (newlen + 2 > *buflen)
    843 			goto enospc;        /* No room for "@\0". */
    844 		(*buf)[newlen++] = '@';
    845 		(*buf)[newlen] = '\0';
    846 	} else {
    847 		if (((origin == NULL || origin[0] == '\0') ||
    848 		    (origin[0] != '.' && origin[1] != '\0' &&
    849 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
    850 			/* No trailing dot. */
    851  root:
    852 			if (newlen + 2 > *buflen)
    853 				goto enospc;	/* No room for ".\0". */
    854 			(*buf)[newlen++] = '.';
    855 			(*buf)[newlen] = '\0';
    856 		}
    857 	}
    858 	*pp += n;
    859 	addlen(newlen, buf, buflen);
    860 	**buf = '\0';
    861 	return (newlen);
    862  enospc:
    863 	errno = ENOSPC;
    864 	*buf = save_buf;
    865 	*buflen = save_buflen;
    866 	return (-1);
    867 }
    868 
    869 static void
    870 addlen(size_t len, char **buf, size_t *buflen) {
    871 	INSIST(len <= *buflen);
    872 	*buf += len;
    873 	*buflen -= len;
    874 }
    875 
    876 static int
    877 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
    878 	if (len >= *buflen) {
    879 		errno = ENOSPC;
    880 		return (-1);
    881 	}
    882 	memcpy(*buf, src, len);
    883 	addlen(len, buf, buflen);
    884 	**buf = '\0';
    885 	return (0);
    886 }
    887 
    888 static int
    889 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
    890 	size_t save_buflen = *buflen;
    891 	char *save_buf = *buf;
    892 	int t;
    893 
    894 	if (spaced || len >= target - 1) {
    895 		T(addstr("  ", (size_t)2, buf, buflen));
    896 		spaced = 1;
    897 	} else {
    898 		for (t = (target - len - 1) / 8; t >= 0; t--)
    899 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
    900 				*buflen = save_buflen;
    901 				*buf = save_buf;
    902 				return (-1);
    903 			}
    904 		spaced = 0;
    905 	}
    906 	return (spaced);
    907 }
    908