|  | /*	$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $	*/ | 
|  |  | 
|  | /* | 
|  | * 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 ISC DISCLAIMS ALL WARRANTIES | 
|  | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
|  | * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC 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. | 
|  | */ | 
|  |  | 
|  | #include <sys/cdefs.h> | 
|  | #ifndef lint | 
|  | #ifdef notdef | 
|  | static const char rcsid[] = "Id: ns_print.c,v 1.3.2.1.4.5 2004/07/28 20:16:45 marka Exp"; | 
|  | #else | 
|  | __RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $"); | 
|  | #endif | 
|  | #endif | 
|  |  | 
|  | /* Import. */ | 
|  |  | 
|  | #include <sys/types.h> | 
|  | #include <sys/socket.h> | 
|  |  | 
|  | #include <netinet/in.h> | 
|  | #include "arpa_nameser.h" | 
|  | #include <arpa/inet.h> | 
|  |  | 
|  | #include <isc/assertions.h> | 
|  | #include <isc/dst.h> | 
|  | #include <errno.h> | 
|  | #ifdef ANDROID_CHANGES | 
|  | #include "resolv_private.h" | 
|  | #else | 
|  | #include <resolv.h> | 
|  | #endif | 
|  | #include <string.h> | 
|  | #include <ctype.h> | 
|  | #include <assert.h> | 
|  |  | 
|  | #ifdef SPRINTF_CHAR | 
|  | # define SPRINTF(x) strlen(sprintf/**/x) | 
|  | #else | 
|  | # define SPRINTF(x) ((size_t)sprintf x) | 
|  | #endif | 
|  |  | 
|  | #ifndef MIN | 
|  | #define	MIN(x,y)	((x)<(y)?(x):(y)) | 
|  | #endif | 
|  |  | 
|  | /* 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); | 
|  |  | 
|  | /* Macros. */ | 
|  |  | 
|  | #define	T(x) \ | 
|  | do { \ | 
|  | if ((x) < 0) \ | 
|  | return (-1); \ | 
|  | } while (/*CONSTCOND*/0) | 
|  |  | 
|  | /* Public. */ | 
|  |  | 
|  | /* | 
|  | * int | 
|  | * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) | 
|  | *	Convert an RR to presentation format. | 
|  | * return: | 
|  | *	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); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * int | 
|  | * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, | 
|  | *	       name_ctx, origin, buf, buflen) | 
|  | *	Convert the fields of an RR into presentation format. | 
|  | * return: | 
|  | *	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]; | 
|  | int len, x; | 
|  |  | 
|  | /* | 
|  | * Owner. | 
|  | */ | 
|  | if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { | 
|  | T(addstr("\t\t\t", (size_t)3, &buf, &buflen)); | 
|  | } else { | 
|  | len = prune_origin(name, origin); | 
|  | if (*name == '\0') { | 
|  | goto root; | 
|  | } else if (len == 0) { | 
|  | T(addstr("@\t\t\t", (size_t)4, &buf, &buflen)); | 
|  | } else { | 
|  | T(addstr(name, (size_t)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(".", (size_t)1, &buf, &buflen)); | 
|  | len++; | 
|  | } | 
|  | T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * TTL, Class, Type. | 
|  | */ | 
|  | T(x = ns_format_ttl(ttl, buf, buflen)); | 
|  | addlen((size_t)x, &buf, &buflen); | 
|  | len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  | T(spaced = addtab((size_t)(x + len), (size_t)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(" ", (size_t)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(" ", (size_t)1, &buf, &buflen)); | 
|  |  | 
|  | /* Administrator name. */ | 
|  | T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
|  | T(addstr(" (\n", (size_t)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", (size_t)5, &buf, &buflen)); | 
|  | len = SPRINTF((tmp, "%lu", t)); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  | T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); | 
|  | T(addstr("; serial\n", (size_t)9, &buf, &buflen)); | 
|  | spaced = 0; | 
|  |  | 
|  | /* Refresh interval. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); | 
|  | T(len = ns_format_ttl(t, buf, buflen)); | 
|  | addlen((size_t)len, &buf, &buflen); | 
|  | T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); | 
|  | T(addstr("; refresh\n", (size_t)10, &buf, &buflen)); | 
|  | spaced = 0; | 
|  |  | 
|  | /* Retry interval. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); | 
|  | T(len = ns_format_ttl(t, buf, buflen)); | 
|  | addlen((size_t)len, &buf, &buflen); | 
|  | T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); | 
|  | T(addstr("; retry\n", (size_t)8, &buf, &buflen)); | 
|  | spaced = 0; | 
|  |  | 
|  | /* Expiry. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); | 
|  | T(len = ns_format_ttl(t, buf, buflen)); | 
|  | addlen((size_t)len, &buf, &buflen); | 
|  | T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); | 
|  | T(addstr("; expiry\n", (size_t)9, &buf, &buflen)); | 
|  | spaced = 0; | 
|  |  | 
|  | /* Minimum TTL. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); | 
|  | T(len = ns_format_ttl(t, buf, buflen)); | 
|  | addlen((size_t)len, &buf, &buflen); | 
|  | T(addstr(" )", (size_t)2, &buf, &buflen)); | 
|  | T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); | 
|  | T(addstr("; minimum\n", (size_t)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, (size_t)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, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Name1. */ | 
|  | T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
|  | T(addstr(" ", (size_t)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(" ", (size_t)1, &buf, &buflen)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ns_t_nsap: { | 
|  | char t[2+255*3]; | 
|  |  | 
|  | (void) inet_nsap_ntoa((int)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, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Flags. */ | 
|  | T(len = charstr(rdata, edata, &buf, &buflen)); | 
|  | if (len == 0) | 
|  | goto formerr; | 
|  | rdata += len; | 
|  | T(addstr(" ", (size_t)1, &buf, &buflen)); | 
|  |  | 
|  | /* Service. */ | 
|  | T(len = charstr(rdata, edata, &buf, &buflen)); | 
|  | if (len == 0) | 
|  | goto formerr; | 
|  | rdata += len; | 
|  | T(addstr(" ", (size_t)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(" ", (size_t)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, (size_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(" ", (size_t)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, (size_t)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", (size_t)5, | 
|  | &buf, &buflen)); | 
|  | lcnt = 10; | 
|  | spaced = 0; | 
|  | } | 
|  | len = SPRINTF((tmp, "%d ", n)); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  | lcnt--; | 
|  | } | 
|  | c <<= 1; | 
|  | } while (++n & 07); | 
|  | } | 
|  | T(addstr(")", (size_t)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. */ | 
|  | #ifndef _LIBC | 
|  | key_id = dst_s_dns_key_id(rdata, edata-rdata); | 
|  | #else | 
|  | key_id = 0; | 
|  | #endif | 
|  | keyflags = ns_get16(rdata);  rdata += NS_INT16SZ; | 
|  | protocol = *rdata++; | 
|  | algorithm = *rdata++; | 
|  | len = SPRINTF((tmp, "0x%04x %u %u", | 
|  | keyflags, protocol, algorithm)); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Public key data. */ | 
|  | len = b64_ntop(rdata, (size_t)(edata - rdata), | 
|  | base64_key, sizeof base64_key); | 
|  | if (len < 0) | 
|  | goto formerr; | 
|  | if (len > 15) { | 
|  | T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48), | 
|  | &buf, &buflen)); | 
|  | } | 
|  | if (len > 15) | 
|  | T(addstr(" )", (size_t)2, &buf, &buflen)); | 
|  | n = SPRINTF((tmp, " ; key_tag= %u", key_id)); | 
|  | T(addstr(tmp, (size_t)n, &buf, &buflen)); | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ns_t_sig: { | 
|  | char base64_key[NS_MD5RSA_MAX_BASE64]; | 
|  | u_int typ, algorithm, labels, footprint; | 
|  | const char *leader; | 
|  | u_long t; | 
|  | int n; | 
|  |  | 
|  | if (rdlen < 22U) | 
|  | goto formerr; | 
|  |  | 
|  | /* Type covered, Algorithm, Label count, Original TTL. */ | 
|  | typ = 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((int)typ), algorithm, labels, t)); | 
|  | T(addstr(tmp, (size_t)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, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Time signed. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Signature Footprint. */ | 
|  | footprint = ns_get16(rdata);  rdata += NS_INT16SZ; | 
|  | len = SPRINTF((tmp, "%u ", footprint)); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Signer's name. */ | 
|  | T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); | 
|  |  | 
|  | /* Signature. */ | 
|  | len = b64_ntop(rdata, (size_t)(edata - rdata), | 
|  | base64_key, sizeof base64_key); | 
|  | if (len > 15) { | 
|  | T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48), | 
|  | &buf, &buflen)); | 
|  | } | 
|  | if (len > 15) | 
|  | T(addstr(" )", (size_t)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, (size_t)len, &buf, &buflen)); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ns_t_cert: { | 
|  | u_int c_type, key_tag, alg; | 
|  | int n; | 
|  | unsigned int siz; | 
|  | char base64_cert[8192], tmp1[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((tmp1, "%d %d %d ", c_type, key_tag, alg)); | 
|  | T(addstr(tmp1, (size_t)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, (size_t)(edata-rdata), | 
|  | base64_cert, siz); | 
|  |  | 
|  | if (len < 0) | 
|  | goto formerr; | 
|  | else if (len > 15) { | 
|  | T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48), | 
|  | &buf, &buflen)); | 
|  | } | 
|  | if (len > 15) | 
|  | T(addstr(" )", (size_t)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(" ", (size_t)1, &buf, &buflen)); | 
|  |  | 
|  | /* Inception. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
|  | T(addstr(tmp, (size_t)len, &buf, &buflen)); | 
|  |  | 
|  | /* Experation. */ | 
|  | t = ns_get32(rdata);  rdata += NS_INT32SZ; | 
|  | len = SPRINTF((tmp, "%s ", p_secstodate(t))); | 
|  | T(addstr(tmp, (size_t)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, (size_t)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(" ", (size_t)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, (size_t)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(" ", (size_t)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, (size_t)len, &buf, &buflen)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | comment = "unknown RR type"; | 
|  | goto hexify; | 
|  | } | 
|  | return (buf - obuf); | 
|  | formerr: | 
|  | comment = "RR format error"; | 
|  | hexify: { | 
|  | int n, m; | 
|  | char *p; | 
|  |  | 
|  | len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata, | 
|  | rdlen != 0 ? " (" : "", comment)); | 
|  | T(addstr(tmp, (size_t)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, (size_t)(p - tmp), &buf, &buflen)); | 
|  | if (n < 16) { | 
|  | T(addstr(")", (size_t)1, &buf, &buflen)); | 
|  | T(addtab((size_t)(p - tmp + 1), (size_t)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, (size_t)(p - tmp), &buf, &buflen)); | 
|  | rdata += n; | 
|  | } | 
|  | return (buf - obuf); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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("\"", (size_t)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("\\", (size_t)1, buf, buflen) < 0) | 
|  | goto enospc; | 
|  | if (addstr((const char *)rdata, (size_t)1, | 
|  | buf, buflen) < 0) | 
|  | goto enospc; | 
|  | rdata++; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (addstr("\"", (size_t)1, buf, buflen) < 0) | 
|  | goto enospc; | 
|  | return (rdata - odata); | 
|  | enospc: | 
|  | 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, (int)*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: | 
|  | 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) { | 
|  | 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("  ", (size_t)2, buf, buflen)); | 
|  | spaced = 1; | 
|  | } else { | 
|  | for (t = (target - len - 1) / 8; t >= 0; t--) | 
|  | if (addstr("\t", (size_t)1, buf, buflen) < 0) { | 
|  | *buflen = save_buflen; | 
|  | *buf = save_buf; | 
|  | return (-1); | 
|  | } | 
|  | spaced = 0; | 
|  | } | 
|  | return (spaced); | 
|  | } |