michael@0: /* $NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $ */ michael@0: michael@0: /* michael@0: * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") michael@0: * Copyright (c) 1996-1999 by Internet Software Consortium. michael@0: * michael@0: * Permission to use, copy, modify, and distribute this software for any michael@0: * purpose with or without fee is hereby granted, provided that the above michael@0: * copyright notice and this permission notice appear in all copies. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES michael@0: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF michael@0: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR michael@0: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN michael@0: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT michael@0: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: */ michael@0: michael@0: /* michael@0: * This version of this file is derived from Android 2.3 "Gingerbread", michael@0: * which contains uncredited changes by Android/Google developers. It has michael@0: * been modified in 2011 for use in the Android build of Mozilla Firefox by michael@0: * Mozilla contributors (including Michael Edwards , michael@0: * and Steve Workman ). michael@0: * These changes are offered under the same license as the original NetBSD michael@0: * file, whose copyright and license are unchanged above. michael@0: */ michael@0: michael@0: #define ANDROID_CHANGES 1 michael@0: #define MOZILLA_NECKO_EXCLUDE_CODE 1 michael@0: michael@0: #include michael@0: #ifndef lint michael@0: #ifdef notdef michael@0: static const char rcsid[] = "Id: ns_print.c,v 1.3.2.1.4.5 2004/07/28 20:16:45 marka Exp"; michael@0: #else michael@0: __RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $"); michael@0: #endif michael@0: #endif michael@0: michael@0: /* Import. */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include "arpa_nameser.h" michael@0: #include michael@0: michael@0: #include "assertions.h" michael@0: #include "dst.h" michael@0: #include michael@0: #ifdef ANDROID_CHANGES michael@0: #include "resolv_private.h" michael@0: #else michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef SPRINTF_CHAR michael@0: # define SPRINTF(x) strlen(sprintf/**/x) michael@0: #else michael@0: # define SPRINTF(x) ((size_t)sprintf x) michael@0: #endif michael@0: michael@0: #ifndef MIN michael@0: #define MIN(x,y) ((x)<(y)?(x):(y)) michael@0: #endif michael@0: michael@0: /* Forward. */ michael@0: michael@0: static size_t prune_origin(const char *name, const char *origin); michael@0: static int charstr(const u_char *rdata, const u_char *edata, michael@0: char **buf, size_t *buflen); michael@0: static int addname(const u_char *msg, size_t msglen, michael@0: const u_char **p, const char *origin, michael@0: char **buf, size_t *buflen); michael@0: static void addlen(size_t len, char **buf, size_t *buflen); michael@0: static int addstr(const char *src, size_t len, michael@0: char **buf, size_t *buflen); michael@0: static int addtab(size_t len, size_t target, int spaced, michael@0: char **buf, size_t *buflen); michael@0: michael@0: /* Macros. */ michael@0: michael@0: #define T(x) \ michael@0: do { \ michael@0: if ((x) < 0) \ michael@0: return (-1); \ michael@0: } while (/*CONSTCOND*/0) michael@0: michael@0: /* Public. */ michael@0: michael@0: /* michael@0: * int michael@0: * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) michael@0: * Convert an RR to presentation format. michael@0: * return: michael@0: * Number of characters written to buf, or -1 (check errno). michael@0: */ michael@0: int michael@0: ns_sprintrr(const ns_msg *handle, const ns_rr *rr, michael@0: const char *name_ctx, const char *origin, michael@0: char *buf, size_t buflen) michael@0: { michael@0: int n; michael@0: michael@0: n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), michael@0: ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), michael@0: ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), michael@0: name_ctx, origin, buf, buflen); michael@0: return (n); michael@0: } michael@0: michael@0: /* michael@0: * int michael@0: * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, michael@0: * name_ctx, origin, buf, buflen) michael@0: * Convert the fields of an RR into presentation format. michael@0: * return: michael@0: * Number of characters written to buf, or -1 (check errno). michael@0: */ michael@0: int michael@0: ns_sprintrrf(const u_char *msg, size_t msglen, michael@0: const char *name, ns_class class, ns_type type, michael@0: u_long ttl, const u_char *rdata, size_t rdlen, michael@0: const char *name_ctx, const char *origin, michael@0: char *buf, size_t buflen) michael@0: { michael@0: const char *obuf = buf; michael@0: const u_char *edata = rdata + rdlen; michael@0: int spaced = 0; michael@0: michael@0: const char *comment; michael@0: char tmp[100]; michael@0: int len, x; michael@0: michael@0: /* michael@0: * Owner. michael@0: */ michael@0: if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { michael@0: T(addstr("\t\t\t", (size_t)3, &buf, &buflen)); michael@0: } else { michael@0: len = prune_origin(name, origin); michael@0: if (*name == '\0') { michael@0: goto root; michael@0: } else if (len == 0) { michael@0: T(addstr("@\t\t\t", (size_t)4, &buf, &buflen)); michael@0: } else { michael@0: T(addstr(name, (size_t)len, &buf, &buflen)); michael@0: /* Origin not used or not root, and no trailing dot? */ michael@0: if (((origin == NULL || origin[0] == '\0') || michael@0: (origin[0] != '.' && origin[1] != '\0' && michael@0: name[len] == '\0')) && name[len - 1] != '.') { michael@0: root: michael@0: T(addstr(".", (size_t)1, &buf, &buflen)); michael@0: len++; michael@0: } michael@0: T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen)); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * TTL, Class, Type. michael@0: */ michael@0: T(x = ns_format_ttl(ttl, buf, buflen)); michael@0: addlen((size_t)x, &buf, &buflen); michael@0: len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen)); michael@0: michael@0: /* michael@0: * RData. michael@0: */ michael@0: switch (type) { michael@0: case ns_t_a: michael@0: if (rdlen != (size_t)NS_INADDRSZ) michael@0: goto formerr; michael@0: (void) inet_ntop(AF_INET, rdata, buf, buflen); michael@0: addlen(strlen(buf), &buf, &buflen); michael@0: break; michael@0: michael@0: case ns_t_cname: michael@0: case ns_t_mb: michael@0: case ns_t_mg: michael@0: case ns_t_mr: michael@0: case ns_t_ns: michael@0: case ns_t_ptr: michael@0: case ns_t_dname: michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: break; michael@0: michael@0: case ns_t_hinfo: michael@0: case ns_t_isdn: michael@0: /* First word. */ michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: michael@0: /* Second word, optional in ISDN records. */ michael@0: if (type == ns_t_isdn && rdata == edata) michael@0: break; michael@0: michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: break; michael@0: michael@0: case ns_t_soa: { michael@0: u_long t; michael@0: michael@0: /* Server name. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Administrator name. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" (\n", (size_t)3, &buf, &buflen)); michael@0: spaced = 0; michael@0: michael@0: if ((edata - rdata) != 5*NS_INT32SZ) michael@0: goto formerr; michael@0: michael@0: /* Serial number. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); michael@0: len = SPRINTF((tmp, "%lu", t)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); michael@0: T(addstr("; serial\n", (size_t)9, &buf, &buflen)); michael@0: spaced = 0; michael@0: michael@0: /* Refresh interval. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); michael@0: T(len = ns_format_ttl(t, buf, buflen)); michael@0: addlen((size_t)len, &buf, &buflen); michael@0: T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); michael@0: T(addstr("; refresh\n", (size_t)10, &buf, &buflen)); michael@0: spaced = 0; michael@0: michael@0: /* Retry interval. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); michael@0: T(len = ns_format_ttl(t, buf, buflen)); michael@0: addlen((size_t)len, &buf, &buflen); michael@0: T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); michael@0: T(addstr("; retry\n", (size_t)8, &buf, &buflen)); michael@0: spaced = 0; michael@0: michael@0: /* Expiry. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); michael@0: T(len = ns_format_ttl(t, buf, buflen)); michael@0: addlen((size_t)len, &buf, &buflen); michael@0: T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); michael@0: T(addstr("; expiry\n", (size_t)9, &buf, &buflen)); michael@0: spaced = 0; michael@0: michael@0: /* Minimum TTL. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); michael@0: T(len = ns_format_ttl(t, buf, buflen)); michael@0: addlen((size_t)len, &buf, &buflen); michael@0: T(addstr(" )", (size_t)2, &buf, &buflen)); michael@0: T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); michael@0: T(addstr("; minimum\n", (size_t)10, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_mx: michael@0: case ns_t_afsdb: michael@0: case ns_t_rt: { michael@0: u_int t; michael@0: michael@0: if (rdlen < (size_t)NS_INT16SZ) michael@0: goto formerr; michael@0: michael@0: /* Priority. */ michael@0: t = ns_get16(rdata); michael@0: rdata += NS_INT16SZ; michael@0: len = SPRINTF((tmp, "%u ", t)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Target. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_px: { michael@0: u_int t; michael@0: michael@0: if (rdlen < (size_t)NS_INT16SZ) michael@0: goto formerr; michael@0: michael@0: /* Priority. */ michael@0: t = ns_get16(rdata); michael@0: rdata += NS_INT16SZ; michael@0: len = SPRINTF((tmp, "%u ", t)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Name1. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Name2. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_x25: michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: break; michael@0: michael@0: case ns_t_txt: michael@0: while (rdata < edata) { michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: if (rdata < edata) michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: } michael@0: break; michael@0: michael@0: case ns_t_nsap: { michael@0: char t[2+255*3]; michael@0: michael@0: (void) inet_nsap_ntoa((int)rdlen, rdata, t); michael@0: T(addstr(t, strlen(t), &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_aaaa: michael@0: if (rdlen != (size_t)NS_IN6ADDRSZ) michael@0: goto formerr; michael@0: (void) inet_ntop(AF_INET6, rdata, buf, buflen); michael@0: addlen(strlen(buf), &buf, &buflen); michael@0: break; michael@0: michael@0: case ns_t_loc: { michael@0: char t[255]; michael@0: michael@0: /* XXX protocol format checking? */ michael@0: (void) loc_ntoa(rdata, t); michael@0: T(addstr(t, strlen(t), &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_naptr: { michael@0: u_int order, preference; michael@0: char t[50]; michael@0: michael@0: if (rdlen < 2U*NS_INT16SZ) michael@0: goto formerr; michael@0: michael@0: /* Order, Precedence. */ michael@0: order = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: preference = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: len = SPRINTF((t, "%u %u ", order, preference)); michael@0: T(addstr(t, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Flags. */ michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Service. */ michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Regexp. */ michael@0: T(len = charstr(rdata, edata, &buf, &buflen)); michael@0: if (len < 0) michael@0: return (-1); michael@0: if (len == 0) michael@0: goto formerr; michael@0: rdata += len; michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Server. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_srv: { michael@0: u_int priority, weight, port; michael@0: char t[50]; michael@0: michael@0: if (rdlen < 3U*NS_INT16SZ) michael@0: goto formerr; michael@0: michael@0: /* Priority, Weight, Port. */ michael@0: priority = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: weight = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: port = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: len = SPRINTF((t, "%u %u %u ", priority, weight, port)); michael@0: T(addstr(t, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Server. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_minfo: michael@0: case ns_t_rp: michael@0: /* Name1. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Name2. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: break; michael@0: michael@0: case ns_t_wks: { michael@0: int n, lcnt; michael@0: michael@0: if (rdlen < 1U + NS_INT32SZ) michael@0: goto formerr; michael@0: michael@0: /* Address. */ michael@0: (void) inet_ntop(AF_INET, rdata, buf, buflen); michael@0: addlen(strlen(buf), &buf, &buflen); michael@0: rdata += NS_INADDRSZ; michael@0: michael@0: /* Protocol. */ michael@0: len = SPRINTF((tmp, " %u ( ", *rdata)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: rdata += NS_INT8SZ; michael@0: michael@0: /* Bit map. */ michael@0: n = 0; michael@0: lcnt = 0; michael@0: while (rdata < edata) { michael@0: u_int c = *rdata++; michael@0: do { michael@0: if (c & 0200) { michael@0: if (lcnt == 0) { michael@0: T(addstr("\n\t\t\t\t", (size_t)5, michael@0: &buf, &buflen)); michael@0: lcnt = 10; michael@0: spaced = 0; michael@0: } michael@0: len = SPRINTF((tmp, "%d ", n)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: lcnt--; michael@0: } michael@0: c <<= 1; michael@0: } while (++n & 07); michael@0: } michael@0: T(addstr(")", (size_t)1, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_key: { michael@0: char base64_key[NS_MD5RSA_MAX_BASE64]; michael@0: u_int keyflags, protocol, algorithm, key_id; michael@0: const char *leader; michael@0: int n; michael@0: michael@0: if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) michael@0: goto formerr; michael@0: michael@0: /* Key flags, Protocol, Algorithm. */ michael@0: #if !defined(MOZILLA_NECKO_EXCLUDE_CODE) && !defined(_LIBC) michael@0: key_id = dst_s_dns_key_id(rdata, edata-rdata); michael@0: #else michael@0: key_id = 0; michael@0: #endif michael@0: keyflags = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: protocol = *rdata++; michael@0: algorithm = *rdata++; michael@0: len = SPRINTF((tmp, "0x%04x %u %u", michael@0: keyflags, protocol, algorithm)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Public key data. */ michael@0: len = b64_ntop(rdata, (size_t)(edata - rdata), michael@0: base64_key, sizeof base64_key); michael@0: if (len < 0) michael@0: goto formerr; michael@0: if (len > 15) { michael@0: T(addstr(" (", (size_t)2, &buf, &buflen)); michael@0: leader = "\n\t\t"; michael@0: spaced = 0; michael@0: } else michael@0: leader = " "; michael@0: for (n = 0; n < len; n += 48) { michael@0: T(addstr(leader, strlen(leader), &buf, &buflen)); michael@0: T(addstr(base64_key + n, (size_t)MIN(len - n, 48), michael@0: &buf, &buflen)); michael@0: } michael@0: if (len > 15) michael@0: T(addstr(" )", (size_t)2, &buf, &buflen)); michael@0: n = SPRINTF((tmp, " ; key_tag= %u", key_id)); michael@0: T(addstr(tmp, (size_t)n, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_sig: { michael@0: char base64_key[NS_MD5RSA_MAX_BASE64]; michael@0: u_int typ, algorithm, labels, footprint; michael@0: const char *leader; michael@0: u_long t; michael@0: int n; michael@0: michael@0: if (rdlen < 22U) michael@0: goto formerr; michael@0: michael@0: /* Type covered, Algorithm, Label count, Original TTL. */ michael@0: typ = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: algorithm = *rdata++; michael@0: labels = *rdata++; michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: len = SPRINTF((tmp, "%s %d %d %lu ", michael@0: p_type((int)typ), algorithm, labels, t)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: if (labels > (u_int)dn_count_labels(name)) michael@0: goto formerr; michael@0: michael@0: /* Signature expiry. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: len = SPRINTF((tmp, "%s ", p_secstodate(t))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Time signed. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: len = SPRINTF((tmp, "%s ", p_secstodate(t))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Signature Footprint. */ michael@0: footprint = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: len = SPRINTF((tmp, "%u ", footprint)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Signer's name. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: /* Signature. */ michael@0: len = b64_ntop(rdata, (size_t)(edata - rdata), michael@0: base64_key, sizeof base64_key); michael@0: if (len > 15) { michael@0: T(addstr(" (", (size_t)2, &buf, &buflen)); michael@0: leader = "\n\t\t"; michael@0: spaced = 0; michael@0: } else michael@0: leader = " "; michael@0: if (len < 0) michael@0: goto formerr; michael@0: for (n = 0; n < len; n += 48) { michael@0: T(addstr(leader, strlen(leader), &buf, &buflen)); michael@0: T(addstr(base64_key + n, (size_t)MIN(len - n, 48), michael@0: &buf, &buflen)); michael@0: } michael@0: if (len > 15) michael@0: T(addstr(" )", (size_t)2, &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_nxt: { michael@0: int n, c; michael@0: michael@0: /* Next domain name. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: /* Type bit map. */ michael@0: n = edata - rdata; michael@0: for (c = 0; c < n*8; c++) michael@0: if (NS_NXT_BIT_ISSET(c, rdata)) { michael@0: len = SPRINTF((tmp, " %s", p_type(c))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case ns_t_cert: { michael@0: u_int c_type, key_tag, alg; michael@0: int n; michael@0: unsigned int siz; michael@0: char base64_cert[8192], tmp1[40]; michael@0: const char *leader; michael@0: michael@0: c_type = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: key_tag = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: alg = (u_int) *rdata++; michael@0: michael@0: len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg)); michael@0: T(addstr(tmp1, (size_t)len, &buf, &buflen)); michael@0: siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ michael@0: if (siz > sizeof(base64_cert) * 3/4) { michael@0: const char *str = "record too long to print"; michael@0: T(addstr(str, strlen(str), &buf, &buflen)); michael@0: } michael@0: else { michael@0: len = b64_ntop(rdata, (size_t)(edata-rdata), michael@0: base64_cert, siz); michael@0: michael@0: if (len < 0) michael@0: goto formerr; michael@0: else if (len > 15) { michael@0: T(addstr(" (", (size_t)2, &buf, &buflen)); michael@0: leader = "\n\t\t"; michael@0: spaced = 0; michael@0: } michael@0: else michael@0: leader = " "; michael@0: michael@0: for (n = 0; n < len; n += 48) { michael@0: T(addstr(leader, strlen(leader), michael@0: &buf, &buflen)); michael@0: T(addstr(base64_cert + n, (size_t)MIN(len - n, 48), michael@0: &buf, &buflen)); michael@0: } michael@0: if (len > 15) michael@0: T(addstr(" )", (size_t)2, &buf, &buflen)); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case ns_t_tkey: { michael@0: /* KJD - need to complete this */ michael@0: u_long t; michael@0: int mode, err, keysize; michael@0: michael@0: /* Algorithm name. */ michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: michael@0: /* Inception. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: len = SPRINTF((tmp, "%s ", p_secstodate(t))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Experation. */ michael@0: t = ns_get32(rdata); rdata += NS_INT32SZ; michael@0: len = SPRINTF((tmp, "%s ", p_secstodate(t))); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* Mode , Error, Key Size. */ michael@0: /* Priority, Weight, Port. */ michael@0: mode = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: err = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: keysize = ns_get16(rdata); rdata += NS_INT16SZ; michael@0: len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: michael@0: /* XXX need to dump key, print otherdata length & other data */ michael@0: break; michael@0: } michael@0: michael@0: case ns_t_tsig: { michael@0: /* BEW - need to complete this */ michael@0: int n; michael@0: michael@0: T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: rdata += 8; /* time */ michael@0: n = ns_get16(rdata); rdata += INT16SZ; michael@0: rdata += n; /* sig */ michael@0: n = ns_get16(rdata); rdata += INT16SZ; /* original id */ michael@0: sprintf(buf, "%d", ns_get16(rdata)); michael@0: rdata += INT16SZ; michael@0: addlen(strlen(buf), &buf, &buflen); michael@0: break; michael@0: } michael@0: michael@0: case ns_t_a6: { michael@0: struct in6_addr a; michael@0: int pbyte, pbit; michael@0: michael@0: /* prefix length */ michael@0: if (rdlen == 0U) goto formerr; michael@0: len = SPRINTF((tmp, "%d ", *rdata)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: pbit = *rdata; michael@0: if (pbit > 128) goto formerr; michael@0: pbyte = (pbit & ~7) / 8; michael@0: rdata++; michael@0: michael@0: /* address suffix: provided only when prefix len != 128 */ michael@0: if (pbit < 128) { michael@0: if (rdata + pbyte >= edata) goto formerr; michael@0: memset(&a, 0, sizeof(a)); michael@0: memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); michael@0: (void) inet_ntop(AF_INET6, &a, buf, buflen); michael@0: addlen(strlen(buf), &buf, &buflen); michael@0: rdata += sizeof(a) - pbyte; michael@0: } michael@0: michael@0: /* prefix name: provided only when prefix len > 0 */ michael@0: if (pbit == 0) michael@0: break; michael@0: if (rdata >= edata) goto formerr; michael@0: T(addstr(" ", (size_t)1, &buf, &buflen)); michael@0: T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); michael@0: michael@0: break; michael@0: } michael@0: michael@0: case ns_t_opt: { michael@0: len = SPRINTF((tmp, "%u bytes", class)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: comment = "unknown RR type"; michael@0: goto hexify; michael@0: } michael@0: return (buf - obuf); michael@0: formerr: michael@0: comment = "RR format error"; michael@0: hexify: { michael@0: int n, m; michael@0: char *p; michael@0: michael@0: len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata, michael@0: rdlen != 0 ? " (" : "", comment)); michael@0: T(addstr(tmp, (size_t)len, &buf, &buflen)); michael@0: while (rdata < edata) { michael@0: p = tmp; michael@0: p += SPRINTF((p, "\n\t")); michael@0: spaced = 0; michael@0: n = MIN(16, edata - rdata); michael@0: for (m = 0; m < n; m++) michael@0: p += SPRINTF((p, "%02x ", rdata[m])); michael@0: T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); michael@0: if (n < 16) { michael@0: T(addstr(")", (size_t)1, &buf, &buflen)); michael@0: T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen)); michael@0: } michael@0: p = tmp; michael@0: p += SPRINTF((p, "; ")); michael@0: for (m = 0; m < n; m++) michael@0: *p++ = (isascii(rdata[m]) && isprint(rdata[m])) michael@0: ? rdata[m] michael@0: : '.'; michael@0: T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); michael@0: rdata += n; michael@0: } michael@0: return (buf - obuf); michael@0: } michael@0: } michael@0: michael@0: /* Private. */ michael@0: michael@0: /* michael@0: * size_t michael@0: * prune_origin(name, origin) michael@0: * Find out if the name is at or under the current origin. michael@0: * return: michael@0: * Number of characters in name before start of origin, michael@0: * or length of name if origin does not match. michael@0: * notes: michael@0: * This function should share code with samedomain(). michael@0: */ michael@0: static size_t michael@0: prune_origin(const char *name, const char *origin) { michael@0: const char *oname = name; michael@0: michael@0: while (*name != '\0') { michael@0: if (origin != NULL && ns_samename(name, origin) == 1) michael@0: return (name - oname - (name > oname)); michael@0: while (*name != '\0') { michael@0: if (*name == '\\') { michael@0: name++; michael@0: /* XXX need to handle \nnn form. */ michael@0: if (*name == '\0') michael@0: break; michael@0: } else if (*name == '.') { michael@0: name++; michael@0: break; michael@0: } michael@0: name++; michael@0: } michael@0: } michael@0: return (name - oname); michael@0: } michael@0: michael@0: /* michael@0: * int michael@0: * charstr(rdata, edata, buf, buflen) michael@0: * Format a into the presentation buffer. michael@0: * return: michael@0: * Number of rdata octets consumed michael@0: * 0 for protocol format error michael@0: * -1 for output buffer error michael@0: * side effects: michael@0: * buffer is advanced on success. michael@0: */ michael@0: static int michael@0: charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { michael@0: const u_char *odata = rdata; michael@0: size_t save_buflen = *buflen; michael@0: char *save_buf = *buf; michael@0: michael@0: if (addstr("\"", (size_t)1, buf, buflen) < 0) michael@0: goto enospc; michael@0: if (rdata < edata) { michael@0: int n = *rdata; michael@0: michael@0: if (rdata + 1 + n <= edata) { michael@0: rdata++; michael@0: while (n-- > 0) { michael@0: if (strchr("\n\"\\", *rdata) != NULL) michael@0: if (addstr("\\", (size_t)1, buf, buflen) < 0) michael@0: goto enospc; michael@0: if (addstr((const char *)rdata, (size_t)1, michael@0: buf, buflen) < 0) michael@0: goto enospc; michael@0: rdata++; michael@0: } michael@0: } michael@0: } michael@0: if (addstr("\"", (size_t)1, buf, buflen) < 0) michael@0: goto enospc; michael@0: return (rdata - odata); michael@0: enospc: michael@0: errno = ENOSPC; michael@0: *buf = save_buf; michael@0: *buflen = save_buflen; michael@0: return (-1); michael@0: } michael@0: michael@0: static int michael@0: addname(const u_char *msg, size_t msglen, michael@0: const u_char **pp, const char *origin, michael@0: char **buf, size_t *buflen) michael@0: { michael@0: size_t newlen, save_buflen = *buflen; michael@0: char *save_buf = *buf; michael@0: int n; michael@0: michael@0: n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen); michael@0: if (n < 0) michael@0: goto enospc; /* Guess. */ michael@0: newlen = prune_origin(*buf, origin); michael@0: if (**buf == '\0') { michael@0: goto root; michael@0: } else if (newlen == 0U) { michael@0: /* Use "@" instead of name. */ michael@0: if (newlen + 2 > *buflen) michael@0: goto enospc; /* No room for "@\0". */ michael@0: (*buf)[newlen++] = '@'; michael@0: (*buf)[newlen] = '\0'; michael@0: } else { michael@0: if (((origin == NULL || origin[0] == '\0') || michael@0: (origin[0] != '.' && origin[1] != '\0' && michael@0: (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { michael@0: /* No trailing dot. */ michael@0: root: michael@0: if (newlen + 2 > *buflen) michael@0: goto enospc; /* No room for ".\0". */ michael@0: (*buf)[newlen++] = '.'; michael@0: (*buf)[newlen] = '\0'; michael@0: } michael@0: } michael@0: *pp += n; michael@0: addlen(newlen, buf, buflen); michael@0: **buf = '\0'; michael@0: return (newlen); michael@0: enospc: michael@0: errno = ENOSPC; michael@0: *buf = save_buf; michael@0: *buflen = save_buflen; michael@0: return (-1); michael@0: } michael@0: michael@0: static void michael@0: addlen(size_t len, char **buf, size_t *buflen) { michael@0: assert(len <= *buflen); michael@0: *buf += len; michael@0: *buflen -= len; michael@0: } michael@0: michael@0: static int michael@0: addstr(const char *src, size_t len, char **buf, size_t *buflen) { michael@0: if (len >= *buflen) { michael@0: errno = ENOSPC; michael@0: return (-1); michael@0: } michael@0: memcpy(*buf, src, len); michael@0: addlen(len, buf, buflen); michael@0: **buf = '\0'; michael@0: return (0); michael@0: } michael@0: michael@0: static int michael@0: addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { michael@0: size_t save_buflen = *buflen; michael@0: char *save_buf = *buf; michael@0: int t; michael@0: michael@0: if (spaced || len >= target - 1) { michael@0: T(addstr(" ", (size_t)2, buf, buflen)); michael@0: spaced = 1; michael@0: } else { michael@0: for (t = (target - len - 1) / 8; t >= 0; t--) michael@0: if (addstr("\t", (size_t)1, buf, buflen) < 0) { michael@0: *buflen = save_buflen; michael@0: *buf = save_buf; michael@0: return (-1); michael@0: } michael@0: spaced = 0; michael@0: } michael@0: return (spaced); michael@0: }