| /* | 
 |  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | 
 |  * Copyright (c) 1996-1999 by Internet Software Consortium. | 
 |  * | 
 |  * Permission to use, copy, modify, and distribute this software for any | 
 |  * purpose with or without fee is hereby granted, provided that the above | 
 |  * copyright notice and this permission notice appear in all copies. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | 
 |  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | 
 |  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | 
 |  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | 
 |  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | 
 |  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | 
 |  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | 
 |  * SOFTWARE. | 
 |  */ | 
 |  | 
 | #if !defined(_LIBC) && !defined(lint) | 
 | static const char rcsid[] = "$BINDId: ns_print.c,v 8.18 2000/02/29 05:48:12 vixie Exp $"; | 
 | #endif | 
 |  | 
 | /* Import. */ | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/socket.h> | 
 |  | 
 | #include <netinet/in.h> | 
 | #include <arpa/nameser.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #include <assert.h> | 
 | #include <errno.h> | 
 | #include <resolv.h> | 
 | #include <string.h> | 
 | #include <ctype.h> | 
 |  | 
 | #define SPRINTF(x) ((size_t)sprintf x) | 
 |  | 
 | /* Forward. */ | 
 |  | 
 | static size_t	prune_origin(const char *name, const char *origin); | 
 | static int	charstr(const u_char *rdata, const u_char *edata, | 
 | 			char **buf, size_t *buflen); | 
 | static int	addname(const u_char *msg, size_t msglen, | 
 | 			const u_char **p, const char *origin, | 
 | 			char **buf, size_t *buflen); | 
 | static void	addlen(size_t len, char **buf, size_t *buflen); | 
 | static int	addstr(const char *src, size_t len, | 
 | 		       char **buf, size_t *buflen); | 
 | static int	addtab(size_t len, size_t target, int spaced, | 
 | 		       char **buf, size_t *buflen); | 
 |  | 
 | static u_int16_t dst_s_dns_key_id(const u_char *, const int); | 
 |  | 
 | /* Macros. */ | 
 |  | 
 | #define	T(x) \ | 
 | 	do { \ | 
 | 		if ((x) < 0) \ | 
 | 			return (-1); \ | 
 | 	} while (0) | 
 |  | 
 | /* Public. */ | 
 |  | 
 | /*% | 
 |  *	Convert an RR to presentation format. | 
 |  * | 
 |  * return: | 
 |  *\li	Number of characters written to buf, or -1 (check errno). | 
 |  */ | 
 | int | 
 | ns_sprintrr(const ns_msg *handle, const ns_rr *rr, | 
 | 	    const char *name_ctx, const char *origin, | 
 | 	    char *buf, size_t buflen) | 
 | { | 
 | 	int n; | 
 |  | 
 | 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), | 
 | 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), | 
 | 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), | 
 | 			 name_ctx, origin, buf, buflen); | 
 | 	return (n); | 
 | } | 
 | libresolv_hidden_def (ns_sprintrr) | 
 |  | 
 | /*% | 
 |  *	Convert the fields of an RR into presentation format. | 
 |  * | 
 |  * return: | 
 |  *\li	Number of characters written to buf, or -1 (check errno). | 
 |  */ | 
 | int | 
 | ns_sprintrrf(const u_char *msg, size_t msglen, | 
 | 	    const char *name, ns_class class, ns_type type, | 
 | 	    u_long ttl, const u_char *rdata, size_t rdlen, | 
 | 	    const char *name_ctx, const char *origin, | 
 | 	    char *buf, size_t buflen) | 
 | { | 
 | 	const char *obuf = buf; | 
 | 	const u_char *edata = rdata + rdlen; | 
 | 	int spaced = 0; | 
 |  | 
 | 	const char *comment; | 
 | 	char tmp[100]; | 
 | 	char errbuf[40]; | 
 | 	int len, x; | 
 |  | 
 | 	/* | 
 | 	 * Owner. | 
 | 	 */ | 
 | 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { | 
 | 		T(addstr("\t\t\t", 3, &buf, &buflen)); | 
 | 	} else { | 
 | 		len = prune_origin(name, origin); | 
 | 		if (*name == '\0') { | 
 | 			goto root; | 
 | 		} else if (len == 0) { | 
 | 			T(addstr("@\t\t\t", 4, &buf, &buflen)); | 
 | 		} else { | 
 | 			T(addstr(name, len, &buf, &buflen)); | 
 | 			/* Origin not used or not root, and no trailing dot? */ | 
 | 			if (((origin == NULL || origin[0] == '\0') || | 
 | 			     (origin[0] != '.' && origin[1] != '\0' && | 
 | 			      name[len] == '\0')) && name[len - 1] != '.') { | 
 |  root: | 
 | 				T(addstr(".", 1, &buf, &buflen)); | 
 | 				len++; | 
 | 			} | 
 | 			T(spaced = addtab(len, 24, spaced, &buf, &buflen)); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * TTL, Class, Type. | 
 | 	 */ | 
 | 	T(x = ns_format_ttl(ttl, buf, buflen)); | 
 | 	addlen(x, &buf, &buflen); | 
 | 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); | 
 | 	T(addstr(tmp, len, &buf, &buflen)); | 
 | 	T(spaced = addtab(x + len, 16, spaced, &buf, &buflen)); | 
 |  | 
 | 	/* | 
 | 	 * RData. | 
 | 	 */ | 
 | 	switch (type) { | 
 | 	case ns_t_a: | 
 | 	  if (rdlen != (size_t)NS_INADDRSZ) | 
 | 			goto formerr; | 
 | 		(void) inet_ntop(AF_INET, rdata, buf, buflen); | 
 | 		addlen(strlen(buf), &buf, &buflen); | 
 | 		break; | 
 |  | 
 | 	case ns_t_cname: | 
 | 	case ns_t_mb: | 
 | 	case ns_t_mg: | 
 | 	case ns_t_mr: | 
 | 	case ns_t_ns: | 
 | 	case ns_t_ptr: | 
 | 	case ns_t_dname: | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		break; | 
 |  | 
 | 	case ns_t_hinfo: | 
 | 	case ns_t_isdn: | 
 | 		/* First word. */ | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 |  | 
 | 		/* Second word, optional in ISDN records. */ | 
 | 		if (type == ns_t_isdn && rdata == edata) | 
 | 			break; | 
 |  | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		break; | 
 |  | 
 | 	case ns_t_soa: { | 
 | 		u_long t; | 
 |  | 
 | 		/* Server name. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Administrator name. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" (\n", 3, &buf, &buflen)); | 
 | 		spaced = 0; | 
 |  | 
 | 		if ((edata - rdata) != 5*NS_INT32SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Serial number. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); | 
 | 		len = SPRINTF((tmp, "%lu", t)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		T(spaced = addtab(len, 16, spaced, &buf, &buflen)); | 
 | 		T(addstr("; serial\n", 9, &buf, &buflen)); | 
 | 		spaced = 0; | 
 |  | 
 | 		/* Refresh interval. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); | 
 | 		T(len = ns_format_ttl(t, buf, buflen)); | 
 | 		addlen(len, &buf, &buflen); | 
 | 		T(spaced = addtab(len, 16, spaced, &buf, &buflen)); | 
 | 		T(addstr("; refresh\n", 10, &buf, &buflen)); | 
 | 		spaced = 0; | 
 |  | 
 | 		/* Retry interval. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); | 
 | 		T(len = ns_format_ttl(t, buf, buflen)); | 
 | 		addlen(len, &buf, &buflen); | 
 | 		T(spaced = addtab(len, 16, spaced, &buf, &buflen)); | 
 | 		T(addstr("; retry\n", 8, &buf, &buflen)); | 
 | 		spaced = 0; | 
 |  | 
 | 		/* Expiry. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); | 
 | 		T(len = ns_format_ttl(t, buf, buflen)); | 
 | 		addlen(len, &buf, &buflen); | 
 | 		T(spaced = addtab(len, 16, spaced, &buf, &buflen)); | 
 | 		T(addstr("; expiry\n", 9, &buf, &buflen)); | 
 | 		spaced = 0; | 
 |  | 
 | 		/* Minimum TTL. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		T(addstr("\t\t\t\t\t", 5, &buf, &buflen)); | 
 | 		T(len = ns_format_ttl(t, buf, buflen)); | 
 | 		addlen(len, &buf, &buflen); | 
 | 		T(addstr(" )", 2, &buf, &buflen)); | 
 | 		T(spaced = addtab(len, 16, spaced, &buf, &buflen)); | 
 | 		T(addstr("; minimum\n", 10, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_mx: | 
 | 	case ns_t_afsdb: | 
 | 	case ns_t_rt: { | 
 | 		u_int t; | 
 |  | 
 | 		if (rdlen < (size_t)NS_INT16SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Priority. */ | 
 | 		t = ns_get16(rdata); | 
 | 		rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((tmp, "%u ", t)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Target. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_px: { | 
 | 		u_int t; | 
 |  | 
 | 		if (rdlen < (size_t)NS_INT16SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Priority. */ | 
 | 		t = ns_get16(rdata); | 
 | 		rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((tmp, "%u ", t)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Name1. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Name2. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_x25: | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		break; | 
 |  | 
 | 	case ns_t_txt: | 
 | 		while (rdata < edata) { | 
 | 			T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 			if (len == 0) | 
 | 				goto formerr; | 
 | 			rdata += len; | 
 | 			if (rdata < edata) | 
 | 				T(addstr(" ", 1, &buf, &buflen)); | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case ns_t_nsap: { | 
 | 		char t[2+255*3]; | 
 |  | 
 | 		(void) inet_nsap_ntoa(rdlen, rdata, t); | 
 | 		T(addstr(t, strlen(t), &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_aaaa: | 
 | 	  if (rdlen != (size_t)NS_IN6ADDRSZ) | 
 | 			goto formerr; | 
 | 		(void) inet_ntop(AF_INET6, rdata, buf, buflen); | 
 | 		addlen(strlen(buf), &buf, &buflen); | 
 | 		break; | 
 |  | 
 | 	case ns_t_loc: { | 
 | 		char t[255]; | 
 |  | 
 | 		/* XXX protocol format checking? */ | 
 | 		(void) loc_ntoa(rdata, t); | 
 | 		T(addstr(t, strlen(t), &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_naptr: { | 
 | 		u_int order, preference; | 
 | 		char t[50]; | 
 |  | 
 | 		if (rdlen < 2U*NS_INT16SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Order, Precedence. */ | 
 | 		order = ns_get16(rdata);	rdata += NS_INT16SZ; | 
 | 		preference = ns_get16(rdata);	rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((t, "%u %u ", order, preference)); | 
 | 		T(addstr(t, len, &buf, &buflen)); | 
 |  | 
 | 		/* Flags. */ | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Service. */ | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Regexp. */ | 
 | 		T(len = charstr(rdata, edata, &buf, &buflen)); | 
 | 		if (len < 0) | 
 | 			return (-1); | 
 | 		if (len == 0) | 
 | 			goto formerr; | 
 | 		rdata += len; | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Server. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_srv: { | 
 | 		u_int priority, weight, port; | 
 | 		char t[50]; | 
 |  | 
 | 		if (rdlen < 3U*NS_INT16SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Priority, Weight, Port. */ | 
 | 		priority = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		port     = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((t, "%u %u %u ", priority, weight, port)); | 
 | 		T(addstr(t, len, &buf, &buflen)); | 
 |  | 
 | 		/* Server. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_minfo: | 
 | 	case ns_t_rp: | 
 | 		/* Name1. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Name2. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 |  | 
 | 	case ns_t_wks: { | 
 | 		int n, lcnt; | 
 |  | 
 | 		if (rdlen < 1U + NS_INT32SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Address. */ | 
 | 		(void) inet_ntop(AF_INET, rdata, buf, buflen); | 
 | 		addlen(strlen(buf), &buf, &buflen); | 
 | 		rdata += NS_INADDRSZ; | 
 |  | 
 | 		/* Protocol. */ | 
 | 		len = SPRINTF((tmp, " %u ( ", *rdata)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		rdata += NS_INT8SZ; | 
 |  | 
 | 		/* Bit map. */ | 
 | 		n = 0; | 
 | 		lcnt = 0; | 
 | 		while (rdata < edata) { | 
 | 			u_int c = *rdata++; | 
 | 			do { | 
 | 				if (c & 0200) { | 
 | 					if (lcnt == 0) { | 
 | 						T(addstr("\n\t\t\t\t", 5, | 
 | 							 &buf, &buflen)); | 
 | 						lcnt = 10; | 
 | 						spaced = 0; | 
 | 					} | 
 | 					len = SPRINTF((tmp, "%d ", n)); | 
 | 					T(addstr(tmp, len, &buf, &buflen)); | 
 | 					lcnt--; | 
 | 				} | 
 | 				c <<= 1; | 
 | 			} while (++n & 07); | 
 | 		} | 
 | 		T(addstr(")", 1, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_key: { | 
 | 		char base64_key[NS_MD5RSA_MAX_BASE64]; | 
 | 		u_int keyflags, protocol, algorithm, key_id; | 
 | 		const char *leader; | 
 | 		int n; | 
 |  | 
 | 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Key flags, Protocol, Algorithm. */ | 
 | 		key_id = dst_s_dns_key_id(rdata, edata-rdata); | 
 | 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		protocol = *rdata++; | 
 | 		algorithm = *rdata++; | 
 | 		len = SPRINTF((tmp, "0x%04x %u %u", | 
 | 			       keyflags, protocol, algorithm)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Public key data. */ | 
 | 		len = b64_ntop(rdata, edata - rdata, | 
 | 			       base64_key, sizeof base64_key); | 
 | 		if (len < 0) | 
 | 			goto formerr; | 
 | 		if (len > 15) { | 
 | 			T(addstr(" (", 2, &buf, &buflen)); | 
 | 			leader = "\n\t\t"; | 
 | 			spaced = 0; | 
 | 		} else | 
 | 			leader = " "; | 
 | 		for (n = 0; n < len; n += 48) { | 
 | 			T(addstr(leader, strlen(leader), &buf, &buflen)); | 
 | 			T(addstr(base64_key + n, MIN(len - n, 48), | 
 | 				 &buf, &buflen)); | 
 | 		} | 
 | 		if (len > 15) | 
 | 			T(addstr(" )", 2, &buf, &buflen)); | 
 | 		n = SPRINTF((tmp, " ; key_tag= %u", key_id)); | 
 | 		T(addstr(tmp, n, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_sig: { | 
 | 		char base64_key[NS_MD5RSA_MAX_BASE64]; | 
 | 		u_int type, algorithm, labels, footprint; | 
 | 		const char *leader; | 
 | 		u_long t; | 
 | 		int n; | 
 |  | 
 | 		if (rdlen < 22U) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Type covered, Algorithm, Label count, Original TTL. */ | 
 | 	        type = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		algorithm = *rdata++; | 
 | 		labels = *rdata++; | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		len = SPRINTF((tmp, "%s %d %d %lu ", | 
 | 			       p_type(type), algorithm, labels, t)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		if (labels > (u_int)dn_count_labels(name)) | 
 | 			goto formerr; | 
 |  | 
 | 		/* Signature expiry. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Time signed. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Signature Footprint. */ | 
 | 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((tmp, "%u ", footprint)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Signer's name. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		/* Signature. */ | 
 | 		len = b64_ntop(rdata, edata - rdata, | 
 | 			       base64_key, sizeof base64_key); | 
 | 		if (len > 15) { | 
 | 			T(addstr(" (", 2, &buf, &buflen)); | 
 | 			leader = "\n\t\t"; | 
 | 			spaced = 0; | 
 | 		} else | 
 | 			leader = " "; | 
 | 		if (len < 0) | 
 | 			goto formerr; | 
 | 		for (n = 0; n < len; n += 48) { | 
 | 			T(addstr(leader, strlen(leader), &buf, &buflen)); | 
 | 			T(addstr(base64_key + n, MIN(len - n, 48), | 
 | 				 &buf, &buflen)); | 
 | 		} | 
 | 		if (len > 15) | 
 | 			T(addstr(" )", 2, &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_nxt: { | 
 | 		int n, c; | 
 |  | 
 | 		/* Next domain name. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		/* Type bit map. */ | 
 | 		n = edata - rdata; | 
 | 		for (c = 0; c < n*8; c++) | 
 | 			if (NS_NXT_BIT_ISSET(c, rdata)) { | 
 | 				len = SPRINTF((tmp, " %s", p_type(c))); | 
 | 				T(addstr(tmp, len, &buf, &buflen)); | 
 | 			} | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_cert: { | 
 | 		u_int c_type, key_tag, alg; | 
 | 		int n; | 
 | 		unsigned int siz; | 
 | 		char base64_cert[8192], tmp[40]; | 
 | 		const char *leader; | 
 |  | 
 | 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ; | 
 | 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ; | 
 | 		alg = (u_int) *rdata++; | 
 |  | 
 | 		len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ | 
 | 		if (siz > sizeof(base64_cert) * 3/4) { | 
 | 			const char *str = "record too long to print"; | 
 | 			T(addstr(str, strlen(str), &buf, &buflen)); | 
 | 		} | 
 | 		else { | 
 | 			len = b64_ntop(rdata, edata-rdata, base64_cert, siz); | 
 |  | 
 | 			if (len < 0) | 
 | 				goto formerr; | 
 | 			else if (len > 15) { | 
 | 				T(addstr(" (", 2, &buf, &buflen)); | 
 | 				leader = "\n\t\t"; | 
 | 				spaced = 0; | 
 | 			} | 
 | 			else | 
 | 				leader = " "; | 
 |  | 
 | 			for (n = 0; n < len; n += 48) { | 
 | 				T(addstr(leader, strlen(leader), | 
 | 					 &buf, &buflen)); | 
 | 				T(addstr(base64_cert + n, MIN(len - n, 48), | 
 | 					 &buf, &buflen)); | 
 | 			} | 
 | 			if (len > 15) | 
 | 				T(addstr(" )", 2, &buf, &buflen)); | 
 | 		} | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_tkey: { | 
 | 		/* KJD - need to complete this */ | 
 | 		u_long t; | 
 | 		int mode, err, keysize; | 
 |  | 
 | 		/* Algorithm name. */ | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 |  | 
 | 		/* Inception. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Experation. */ | 
 | 		t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
 | 		len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* Mode , Error, Key Size. */ | 
 | 		/* Priority, Weight, Port. */ | 
 | 		mode = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		err  = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ; | 
 | 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 |  | 
 | 		/* XXX need to dump key, print otherdata length & other data */ | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_tsig: { | 
 | 		/* BEW - need to complete this */ | 
 | 		int n; | 
 |  | 
 | 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 | 		rdata += 8; /*%< time */ | 
 | 		n = ns_get16(rdata); rdata += INT16SZ; | 
 | 		rdata += n; /*%< sig */ | 
 | 		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */ | 
 | 		sprintf(buf, "%d", ns_get16(rdata)); | 
 | 		rdata += INT16SZ; | 
 | 		addlen(strlen(buf), &buf, &buflen); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_a6: { | 
 | 		struct in6_addr a; | 
 | 		int pbyte, pbit; | 
 |  | 
 | 		/* prefix length */ | 
 | 		if (rdlen == 0U) goto formerr; | 
 | 		len = SPRINTF((tmp, "%d ", *rdata)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		pbit = *rdata; | 
 | 		if (pbit > 128) goto formerr; | 
 | 		pbyte = (pbit & ~7) / 8; | 
 | 		rdata++; | 
 |  | 
 | 		/* address suffix: provided only when prefix len != 128 */ | 
 | 		if (pbit < 128) { | 
 | 			if (rdata + pbyte >= edata) goto formerr; | 
 | 			memset(&a, 0, sizeof(a)); | 
 | 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); | 
 | 			(void) inet_ntop(AF_INET6, &a, buf, buflen); | 
 | 			addlen(strlen(buf), &buf, &buflen); | 
 | 			rdata += sizeof(a) - pbyte; | 
 | 		} | 
 |  | 
 | 		/* prefix name: provided only when prefix len > 0 */ | 
 | 		if (pbit == 0) | 
 | 			break; | 
 | 		if (rdata >= edata) goto formerr; | 
 | 		T(addstr(" ", 1, &buf, &buflen)); | 
 | 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
 |  | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	case ns_t_opt: { | 
 | 		len = SPRINTF((tmp, "%u bytes", class)); | 
 | 		T(addstr(tmp, len, &buf, &buflen)); | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	default: | 
 | 		snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type); | 
 | 		comment = errbuf; | 
 | 		goto hexify; | 
 | 	} | 
 | 	return (buf - obuf); | 
 |  formerr: | 
 | 	comment = "RR format error"; | 
 |  hexify: { | 
 | 	int n, m; | 
 | 	char *p; | 
 |  | 
 | 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata), | 
 | 		       rdlen != 0U ? " (" : "", comment)); | 
 | 	T(addstr(tmp, len, &buf, &buflen)); | 
 | 	while (rdata < edata) { | 
 | 		p = tmp; | 
 | 		p += SPRINTF((p, "\n\t")); | 
 | 		spaced = 0; | 
 | 		n = MIN(16, edata - rdata); | 
 | 		for (m = 0; m < n; m++) | 
 | 			p += SPRINTF((p, "%02x ", rdata[m])); | 
 | 		T(addstr(tmp, p - tmp, &buf, &buflen)); | 
 | 		if (n < 16) { | 
 | 			T(addstr(")", 1, &buf, &buflen)); | 
 | 			T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen)); | 
 | 		} | 
 | 		p = tmp; | 
 | 		p += SPRINTF((p, "; ")); | 
 | 		for (m = 0; m < n; m++) | 
 | 			*p++ = (isascii(rdata[m]) && isprint(rdata[m])) | 
 | 				? rdata[m] | 
 | 				: '.'; | 
 | 		T(addstr(tmp, p - tmp, &buf, &buflen)); | 
 | 		rdata += n; | 
 | 	} | 
 | 	return (buf - obuf); | 
 |     } | 
 | } | 
 | libresolv_hidden_def (ns_sprintrrf) | 
 |  | 
 | /* Private. */ | 
 |  | 
 | /*% | 
 |  * size_t | 
 |  * prune_origin(name, origin) | 
 |  *	Find out if the name is at or under the current origin. | 
 |  * return: | 
 |  *	Number of characters in name before start of origin, | 
 |  *	or length of name if origin does not match. | 
 |  * notes: | 
 |  *	This function should share code with samedomain(). | 
 |  */ | 
 | static size_t | 
 | prune_origin(const char *name, const char *origin) { | 
 | 	const char *oname = name; | 
 |  | 
 | 	while (*name != '\0') { | 
 | 		if (origin != NULL && ns_samename(name, origin) == 1) | 
 | 			return (name - oname - (name > oname)); | 
 | 		while (*name != '\0') { | 
 | 			if (*name == '\\') { | 
 | 				name++; | 
 | 				/* XXX need to handle \nnn form. */ | 
 | 				if (*name == '\0') | 
 | 					break; | 
 | 			} else if (*name == '.') { | 
 | 				name++; | 
 | 				break; | 
 | 			} | 
 | 			name++; | 
 | 		} | 
 | 	} | 
 | 	return (name - oname); | 
 | } | 
 |  | 
 | /*% | 
 |  * int | 
 |  * charstr(rdata, edata, buf, buflen) | 
 |  *	Format a <character-string> into the presentation buffer. | 
 |  * return: | 
 |  *	Number of rdata octets consumed | 
 |  *	0 for protocol format error | 
 |  *	-1 for output buffer error | 
 |  * side effects: | 
 |  *	buffer is advanced on success. | 
 |  */ | 
 | static int | 
 | charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { | 
 | 	const u_char *odata = rdata; | 
 | 	size_t save_buflen = *buflen; | 
 | 	char *save_buf = *buf; | 
 |  | 
 | 	if (addstr("\"", 1, buf, buflen) < 0) | 
 | 		goto enospc; | 
 | 	if (rdata < edata) { | 
 | 		int n = *rdata; | 
 |  | 
 | 		if (rdata + 1 + n <= edata) { | 
 | 			rdata++; | 
 | 			while (n-- > 0) { | 
 | 				if (strchr("\n\"\\", *rdata) != NULL) | 
 | 					if (addstr("\\", 1, buf, buflen) < 0) | 
 | 						goto enospc; | 
 | 				if (addstr((const char *)rdata, 1, | 
 | 					   buf, buflen) < 0) | 
 | 					goto enospc; | 
 | 				rdata++; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	if (addstr("\"", 1, buf, buflen) < 0) | 
 | 		goto enospc; | 
 | 	return (rdata - odata); | 
 |  enospc: | 
 | 	__set_errno (ENOSPC); | 
 | 	*buf = save_buf; | 
 | 	*buflen = save_buflen; | 
 | 	return (-1); | 
 | } | 
 |  | 
 | static int | 
 | addname(const u_char *msg, size_t msglen, | 
 | 	const u_char **pp, const char *origin, | 
 | 	char **buf, size_t *buflen) | 
 | { | 
 | 	size_t newlen, save_buflen = *buflen; | 
 | 	char *save_buf = *buf; | 
 | 	int n; | 
 |  | 
 | 	n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen); | 
 | 	if (n < 0) | 
 | 		goto enospc;	/*%< Guess. */ | 
 | 	newlen = prune_origin(*buf, origin); | 
 | 	if (**buf == '\0') { | 
 | 		goto root; | 
 | 	} else if (newlen == 0U) { | 
 | 		/* Use "@" instead of name. */ | 
 | 		if (newlen + 2 > *buflen) | 
 | 			goto enospc;        /* No room for "@\0". */ | 
 | 		(*buf)[newlen++] = '@'; | 
 | 		(*buf)[newlen] = '\0'; | 
 | 	} else { | 
 | 		if (((origin == NULL || origin[0] == '\0') || | 
 | 		    (origin[0] != '.' && origin[1] != '\0' && | 
 | 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { | 
 | 			/* No trailing dot. */ | 
 |  root: | 
 | 			if (newlen + 2 > *buflen) | 
 | 				goto enospc;	/* No room for ".\0". */ | 
 | 			(*buf)[newlen++] = '.'; | 
 | 			(*buf)[newlen] = '\0'; | 
 | 		} | 
 | 	} | 
 | 	*pp += n; | 
 | 	addlen(newlen, buf, buflen); | 
 | 	**buf = '\0'; | 
 | 	return (newlen); | 
 |  enospc: | 
 | 	__set_errno (ENOSPC); | 
 | 	*buf = save_buf; | 
 | 	*buflen = save_buflen; | 
 | 	return (-1); | 
 | } | 
 |  | 
 | static void | 
 | addlen(size_t len, char **buf, size_t *buflen) { | 
 | 	assert(len <= *buflen); | 
 | 	*buf += len; | 
 | 	*buflen -= len; | 
 | } | 
 |  | 
 | static int | 
 | addstr(const char *src, size_t len, char **buf, size_t *buflen) { | 
 | 	if (len >= *buflen) { | 
 | 		__set_errno (ENOSPC); | 
 | 		return (-1); | 
 | 	} | 
 | 	memcpy(*buf, src, len); | 
 | 	addlen(len, buf, buflen); | 
 | 	**buf = '\0'; | 
 | 	return (0); | 
 | } | 
 |  | 
 | static int | 
 | addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { | 
 | 	size_t save_buflen = *buflen; | 
 | 	char *save_buf = *buf; | 
 | 	int t; | 
 |  | 
 | 	if (spaced || len >= target - 1) { | 
 | 		T(addstr("  ", 2, buf, buflen)); | 
 | 		spaced = 1; | 
 | 	} else { | 
 | 		for (t = (target - len - 1) / 8; t >= 0; t--) | 
 | 			if (addstr("\t", 1, buf, buflen) < 0) { | 
 | 				*buflen = save_buflen; | 
 | 				*buf = save_buf; | 
 | 				return (-1); | 
 | 			} | 
 | 		spaced = 0; | 
 | 	} | 
 | 	return (spaced); | 
 | } | 
 |  | 
 | /* DST algorithm codes */ | 
 | #define KEY_RSA			1 | 
 | #define KEY_HMAC_MD5		157 | 
 |  | 
 | /*% | 
 |  * calculates a checksum used in dst for an id. | 
 |  * takes an array of bytes and a length. | 
 |  * returns a 16  bit checksum. | 
 |  */ | 
 | static u_int16_t | 
 | dst_s_id_calc(const u_char *key, const int keysize) | 
 | { | 
 | 	u_int32_t ac; | 
 | 	const u_char *kp = key; | 
 | 	int size = keysize; | 
 |  | 
 | 	if (!key || (keysize <= 0)) | 
 | 		return (0xffffU); | 
 |  | 
 | 	for (ac = 0; size > 1; size -= 2, kp += 2) | 
 | 		ac += ((*kp) << 8) + *(kp + 1); | 
 |  | 
 | 	if (size > 0) | 
 | 		ac += ((*kp) << 8); | 
 | 	ac += (ac >> 16) & 0xffff; | 
 |  | 
 | 	return (ac & 0xffff); | 
 | } | 
 |  | 
 | /*% | 
 |  * dst_s_get_int16 | 
 |  *     This routine extracts a 16 bit integer from a two byte character | 
 |  *     string.  The character string is assumed to be in network byte | 
 |  *     order and may be unaligned.  The number returned is in host order. | 
 |  * Parameter | 
 |  *     buf     A two byte character string. | 
 |  * Return | 
 |  *     The converted integer value. | 
 |  */ | 
 |  | 
 | static u_int16_t | 
 | dst_s_get_int16(const u_char *buf) | 
 | { | 
 | 	u_int16_t a = 0; | 
 | 	a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1])); | 
 | 	return (a); | 
 | } | 
 |  | 
 | /*% | 
 |  * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record | 
 |  *   rdata | 
 |  * Input: | 
 |  *	dns_key_rdata: the raw data in wire format | 
 |  *      rdata_len: the size of the input data | 
 |  * Output: | 
 |  *      the key footprint/id calculated from the key data | 
 |  */ | 
 | static u_int16_t | 
 | dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len) | 
 | { | 
 | 	if (!dns_key_rdata) | 
 | 		return 0; | 
 |  | 
 | 	/* compute id */ | 
 | 	if (dns_key_rdata[3] == KEY_RSA)	/*%< Algorithm RSA */ | 
 | 		return dst_s_get_int16((const u_char *) | 
 | 				       &dns_key_rdata[rdata_len - 3]); | 
 | 	else if (dns_key_rdata[3] == KEY_HMAC_MD5) | 
 | 		/* compatibility */ | 
 | 		return 0; | 
 | 	else | 
 | 		/* compute a checksum on the key part of the key rr */ | 
 | 		return dst_s_id_calc(dns_key_rdata, rdata_len); | 
 | } | 
 |  | 
 |  | 
 | /*! \file */ |