2N/A/*
2N/A * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
2N/A * Copyright (c) 1996-1999 by Internet Software Consortium.
2N/A *
2N/A * Permission to use, copy, modify, and distribute this software for any
2N/A * purpose with or without fee is hereby granted, provided that the above
2N/A * copyright notice and this permission notice appear in all copies.
2N/A *
2N/A * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
2N/A * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2N/A * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
2N/A * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2N/A * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2N/A * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
2N/A * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A#ifndef lint
2N/Astatic const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
2N/A#endif
2N/A
2N/A/* Import. */
2N/A
2N/A#include "port_before.h"
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/socket.h>
2N/A
2N/A#include <netinet/in.h>
2N/A#include <arpa/nameser.h>
2N/A#include <arpa/inet.h>
2N/A
2N/A#include <isc/assertions.h>
2N/A#include <isc/dst.h>
2N/A#include <errno.h>
2N/A#include <resolv.h>
2N/A#include <string.h>
2N/A#include <ctype.h>
2N/A
2N/A#include "port_after.h"
2N/A
2N/A#ifdef SPRINTF_CHAR
2N/A# define SPRINTF(x) strlen(sprintf/**/x)
2N/A#else
2N/A# define SPRINTF(x) ((size_t)sprintf x)
2N/A#endif
2N/A
2N/A/* Forward. */
2N/A
2N/Astatic size_t prune_origin(const char *name, const char *origin);
2N/Astatic int charstr(const u_char *rdata, const u_char *edata,
2N/A char **buf, size_t *buflen);
2N/Astatic int addname(const u_char *msg, size_t msglen,
2N/A const u_char **p, const char *origin,
2N/A char **buf, size_t *buflen);
2N/Astatic void addlen(size_t len, char **buf, size_t *buflen);
2N/Astatic int addstr(const char *src, size_t len,
2N/A char **buf, size_t *buflen);
2N/Astatic int addtab(size_t len, size_t target, int spaced,
2N/A char **buf, size_t *buflen);
2N/A
2N/A/* Macros. */
2N/A
2N/A#define T(x) \
2N/A do { \
2N/A if ((x) < 0) \
2N/A return (-1); \
2N/A } while (0)
2N/A
2N/Astatic const char base32hex[] =
2N/A "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
2N/A
2N/A/* Public. */
2N/A
2N/A/*%
2N/A * Convert an RR to presentation format.
2N/A *
2N/A * return:
2N/A *\li Number of characters written to buf, or -1 (check errno).
2N/A */
2N/Aint
2N/Ans_sprintrr(const ns_msg *handle, const ns_rr *rr,
2N/A const char *name_ctx, const char *origin,
2N/A char *buf, size_t buflen)
2N/A{
2N/A int n;
2N/A
2N/A n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
2N/A ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
2N/A ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
2N/A name_ctx, origin, buf, buflen);
2N/A return (n);
2N/A}
2N/A
2N/A/*%
2N/A * Convert the fields of an RR into presentation format.
2N/A *
2N/A * return:
2N/A *\li Number of characters written to buf, or -1 (check errno).
2N/A */
2N/Aint
2N/Ans_sprintrrf(const u_char *msg, size_t msglen,
2N/A const char *name, ns_class class, ns_type type,
2N/A u_long ttl, const u_char *rdata, size_t rdlen,
2N/A const char *name_ctx, const char *origin,
2N/A char *buf, size_t buflen)
2N/A{
2N/A const char *obuf = buf;
2N/A const u_char *edata = rdata + rdlen;
2N/A int spaced = 0;
2N/A
2N/A const char *comment;
2N/A char tmp[100];
2N/A int len, x;
2N/A
2N/A /*
2N/A * Owner.
2N/A */
2N/A if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
2N/A T(addstr("\t\t\t", 3, &buf, &buflen));
2N/A } else {
2N/A len = prune_origin(name, origin);
2N/A if (*name == '\0') {
2N/A goto root;
2N/A } else if (len == 0) {
2N/A T(addstr("@\t\t\t", 4, &buf, &buflen));
2N/A } else {
2N/A T(addstr(name, len, &buf, &buflen));
2N/A /* Origin not used or not root, and no trailing dot? */
2N/A if (((origin == NULL || origin[0] == '\0') ||
2N/A (origin[0] != '.' && origin[1] != '\0' &&
2N/A name[len] == '\0')) && name[len - 1] != '.') {
2N/A root:
2N/A T(addstr(".", 1, &buf, &buflen));
2N/A len++;
2N/A }
2N/A T(spaced = addtab(len, 24, spaced, &buf, &buflen));
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * TTL, Class, Type.
2N/A */
2N/A T(x = ns_format_ttl(ttl, buf, buflen));
2N/A addlen(x, &buf, &buflen);
2N/A len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
2N/A
2N/A /*
2N/A * RData.
2N/A */
2N/A switch (type) {
2N/A case ns_t_a:
2N/A if (rdlen != (size_t)NS_INADDRSZ)
2N/A goto formerr;
2N/A (void) inet_ntop(AF_INET, rdata, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A break;
2N/A
2N/A case ns_t_cname:
2N/A case ns_t_mb:
2N/A case ns_t_mg:
2N/A case ns_t_mr:
2N/A case ns_t_ns:
2N/A case ns_t_ptr:
2N/A case ns_t_dname:
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A break;
2N/A
2N/A case ns_t_hinfo:
2N/A case ns_t_isdn:
2N/A /* First word. */
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A
2N/A /* Second word, optional in ISDN records. */
2N/A if (type == ns_t_isdn && rdata == edata)
2N/A break;
2N/A
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A break;
2N/A
2N/A case ns_t_soa: {
2N/A u_long t;
2N/A
2N/A /* Server name. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Administrator name. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" (\n", 3, &buf, &buflen));
2N/A spaced = 0;
2N/A
2N/A if ((edata - rdata) != 5*NS_INT32SZ)
2N/A goto formerr;
2N/A
2N/A /* Serial number. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
2N/A len = SPRINTF((tmp, "%lu", t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A T(spaced = addtab(len, 16, spaced, &buf, &buflen));
2N/A T(addstr("; serial\n", 9, &buf, &buflen));
2N/A spaced = 0;
2N/A
2N/A /* Refresh interval. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
2N/A T(len = ns_format_ttl(t, buf, buflen));
2N/A addlen(len, &buf, &buflen);
2N/A T(spaced = addtab(len, 16, spaced, &buf, &buflen));
2N/A T(addstr("; refresh\n", 10, &buf, &buflen));
2N/A spaced = 0;
2N/A
2N/A /* Retry interval. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
2N/A T(len = ns_format_ttl(t, buf, buflen));
2N/A addlen(len, &buf, &buflen);
2N/A T(spaced = addtab(len, 16, spaced, &buf, &buflen));
2N/A T(addstr("; retry\n", 8, &buf, &buflen));
2N/A spaced = 0;
2N/A
2N/A /* Expiry. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
2N/A T(len = ns_format_ttl(t, buf, buflen));
2N/A addlen(len, &buf, &buflen);
2N/A T(spaced = addtab(len, 16, spaced, &buf, &buflen));
2N/A T(addstr("; expiry\n", 9, &buf, &buflen));
2N/A spaced = 0;
2N/A
2N/A /* Minimum TTL. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
2N/A T(len = ns_format_ttl(t, buf, buflen));
2N/A addlen(len, &buf, &buflen);
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A T(spaced = addtab(len, 16, spaced, &buf, &buflen));
2N/A T(addstr("; minimum\n", 10, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_mx:
2N/A case ns_t_afsdb:
2N/A case ns_t_rt:
2N/A case ns_t_kx: {
2N/A u_int t;
2N/A
2N/A if (rdlen < (size_t)NS_INT16SZ)
2N/A goto formerr;
2N/A
2N/A /* Priority. */
2N/A t = ns_get16(rdata);
2N/A rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u ", t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Target. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_px: {
2N/A u_int t;
2N/A
2N/A if (rdlen < (size_t)NS_INT16SZ)
2N/A goto formerr;
2N/A
2N/A /* Priority. */
2N/A t = ns_get16(rdata);
2N/A rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u ", t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Name1. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Name2. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_x25:
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A break;
2N/A
2N/A case ns_t_txt:
2N/A case ns_t_spf:
2N/A while (rdata < edata) {
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A if (rdata < edata)
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A }
2N/A break;
2N/A
2N/A case ns_t_nsap: {
2N/A char t[2+255*3];
2N/A
2N/A (void) inet_nsap_ntoa(rdlen, rdata, t);
2N/A T(addstr(t, strlen(t), &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_aaaa:
2N/A if (rdlen != (size_t)NS_IN6ADDRSZ)
2N/A goto formerr;
2N/A (void) inet_ntop(AF_INET6, rdata, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A break;
2N/A
2N/A case ns_t_loc: {
2N/A char t[255];
2N/A
2N/A /* XXX protocol format checking? */
2N/A (void) loc_ntoa(rdata, t);
2N/A T(addstr(t, strlen(t), &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_naptr: {
2N/A u_int order, preference;
2N/A char t[50];
2N/A
2N/A if (rdlen < 2U*NS_INT16SZ)
2N/A goto formerr;
2N/A
2N/A /* Order, Precedence. */
2N/A order = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A preference = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A len = SPRINTF((t, "%u %u ", order, preference));
2N/A T(addstr(t, len, &buf, &buflen));
2N/A
2N/A /* Flags. */
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Service. */
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Regexp. */
2N/A T(len = charstr(rdata, edata, &buf, &buflen));
2N/A if (len < 0)
2N/A return (-1);
2N/A if (len == 0)
2N/A goto formerr;
2N/A rdata += len;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Server. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_srv: {
2N/A u_int priority, weight, port;
2N/A char t[50];
2N/A
2N/A if (rdlen < 3U*NS_INT16SZ)
2N/A goto formerr;
2N/A
2N/A /* Priority, Weight, Port. */
2N/A priority = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A weight = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A port = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A len = SPRINTF((t, "%u %u %u ", priority, weight, port));
2N/A T(addstr(t, len, &buf, &buflen));
2N/A
2N/A /* Server. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_minfo:
2N/A case ns_t_rp:
2N/A /* Name1. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Name2. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A break;
2N/A
2N/A case ns_t_wks: {
2N/A int n, lcnt;
2N/A
2N/A if (rdlen < 1U + NS_INT32SZ)
2N/A goto formerr;
2N/A
2N/A /* Address. */
2N/A (void) inet_ntop(AF_INET, rdata, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A rdata += NS_INADDRSZ;
2N/A
2N/A /* Protocol. */
2N/A len = SPRINTF((tmp, " %u ( ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata += NS_INT8SZ;
2N/A
2N/A /* Bit map. */
2N/A n = 0;
2N/A lcnt = 0;
2N/A while (rdata < edata) {
2N/A u_int c = *rdata++;
2N/A do {
2N/A if (c & 0200) {
2N/A if (lcnt == 0) {
2N/A T(addstr("\n\t\t\t\t", 5,
2N/A &buf, &buflen));
2N/A lcnt = 10;
2N/A spaced = 0;
2N/A }
2N/A len = SPRINTF((tmp, "%d ", n));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A lcnt--;
2N/A }
2N/A c <<= 1;
2N/A } while (++n & 07);
2N/A }
2N/A T(addstr(")", 1, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_key:
2N/A case ns_t_dnskey: {
2N/A char base64_key[NS_MD5RSA_MAX_BASE64];
2N/A u_int keyflags, protocol, algorithm, key_id;
2N/A const char *leader;
2N/A int n;
2N/A
2N/A if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
2N/A goto formerr;
2N/A
2N/A /* Key flags, Protocol, Algorithm. */
2N/A key_id = dst_s_dns_key_id(rdata, edata-rdata);
2N/A keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A protocol = *rdata++;
2N/A algorithm = *rdata++;
2N/A len = SPRINTF((tmp, "0x%04x %u %u",
2N/A keyflags, protocol, algorithm));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Public key data. */
2N/A len = b64_ntop(rdata, edata - rdata,
2N/A base64_key, sizeof base64_key);
2N/A if (len < 0)
2N/A goto formerr;
2N/A if (len > 15) {
2N/A T(addstr(" (", 2, &buf, &buflen));
2N/A leader = "\n\t\t";
2N/A spaced = 0;
2N/A } else
2N/A leader = " ";
2N/A for (n = 0; n < len; n += 48) {
2N/A T(addstr(leader, strlen(leader), &buf, &buflen));
2N/A T(addstr(base64_key + n, MIN(len - n, 48),
2N/A &buf, &buflen));
2N/A }
2N/A if (len > 15)
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A n = SPRINTF((tmp, " ; key_tag= %u", key_id));
2N/A T(addstr(tmp, n, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_sig:
2N/A case ns_t_rrsig: {
2N/A char base64_key[NS_MD5RSA_MAX_BASE64];
2N/A u_int type, algorithm, labels, footprint;
2N/A const char *leader;
2N/A u_long t;
2N/A int n;
2N/A
2N/A if (rdlen < 22U)
2N/A goto formerr;
2N/A
2N/A /* Type covered, Algorithm, Label count, Original TTL. */
2N/A type = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A algorithm = *rdata++;
2N/A labels = *rdata++;
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A len = SPRINTF((tmp, "%s %d %d %lu ",
2N/A p_type(type), algorithm, labels, t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A if (labels > (u_int)dn_count_labels(name))
2N/A goto formerr;
2N/A
2N/A /* Signature expiry. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A len = SPRINTF((tmp, "%s ", p_secstodate(t)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Time signed. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A len = SPRINTF((tmp, "%s ", p_secstodate(t)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Signature Footprint. */
2N/A footprint = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u ", footprint));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Signer's name. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A /* Signature. */
2N/A len = b64_ntop(rdata, edata - rdata,
2N/A base64_key, sizeof base64_key);
2N/A if (len > 15) {
2N/A T(addstr(" (", 2, &buf, &buflen));
2N/A leader = "\n\t\t";
2N/A spaced = 0;
2N/A } else
2N/A leader = " ";
2N/A if (len < 0)
2N/A goto formerr;
2N/A for (n = 0; n < len; n += 48) {
2N/A T(addstr(leader, strlen(leader), &buf, &buflen));
2N/A T(addstr(base64_key + n, MIN(len - n, 48),
2N/A &buf, &buflen));
2N/A }
2N/A if (len > 15)
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_nxt: {
2N/A int n, c;
2N/A
2N/A /* Next domain name. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A /* Type bit map. */
2N/A n = edata - rdata;
2N/A for (c = 0; c < n*8; c++)
2N/A if (NS_NXT_BIT_ISSET(c, rdata)) {
2N/A len = SPRINTF((tmp, " %s", p_type(c)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A }
2N/A break;
2N/A }
2N/A
2N/A case ns_t_cert: {
2N/A u_int c_type, key_tag, alg;
2N/A int n;
2N/A unsigned int siz;
2N/A char base64_cert[8192], tmp[40];
2N/A const char *leader;
2N/A
2N/A c_type = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A alg = (u_int) *rdata++;
2N/A
2N/A len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
2N/A if (siz > sizeof(base64_cert) * 3/4) {
2N/A const char *str = "record too long to print";
2N/A T(addstr(str, strlen(str), &buf, &buflen));
2N/A }
2N/A else {
2N/A len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
2N/A
2N/A if (len < 0)
2N/A goto formerr;
2N/A else if (len > 15) {
2N/A T(addstr(" (", 2, &buf, &buflen));
2N/A leader = "\n\t\t";
2N/A spaced = 0;
2N/A }
2N/A else
2N/A leader = " ";
2N/A
2N/A for (n = 0; n < len; n += 48) {
2N/A T(addstr(leader, strlen(leader),
2N/A &buf, &buflen));
2N/A T(addstr(base64_cert + n, MIN(len - n, 48),
2N/A &buf, &buflen));
2N/A }
2N/A if (len > 15)
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A }
2N/A break;
2N/A }
2N/A
2N/A case ns_t_tkey: {
2N/A /* KJD - need to complete this */
2N/A u_long t;
2N/A int mode, err, keysize;
2N/A
2N/A /* Algorithm name. */
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A /* Inception. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A len = SPRINTF((tmp, "%s ", p_secstodate(t)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Experation. */
2N/A t = ns_get32(rdata); rdata += NS_INT32SZ;
2N/A len = SPRINTF((tmp, "%s ", p_secstodate(t)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* Mode , Error, Key Size. */
2N/A /* Priority, Weight, Port. */
2N/A mode = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A err = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A keysize = ns_get16(rdata); rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A /* XXX need to dump key, print otherdata length & other data */
2N/A break;
2N/A }
2N/A
2N/A case ns_t_tsig: {
2N/A /* BEW - need to complete this */
2N/A int n;
2N/A
2N/A T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A rdata += 8; /*%< time */
2N/A n = ns_get16(rdata); rdata += INT16SZ;
2N/A rdata += n; /*%< sig */
2N/A n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
2N/A sprintf(buf, "%d", ns_get16(rdata));
2N/A rdata += INT16SZ;
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A break;
2N/A }
2N/A
2N/A case ns_t_a6: {
2N/A struct in6_addr a;
2N/A int pbyte, pbit;
2N/A
2N/A /* prefix length */
2N/A if (rdlen == 0U) goto formerr;
2N/A len = SPRINTF((tmp, "%d ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A pbit = *rdata;
2N/A if (pbit > 128) goto formerr;
2N/A pbyte = (pbit & ~7) / 8;
2N/A rdata++;
2N/A
2N/A /* address suffix: provided only when prefix len != 128 */
2N/A if (pbit < 128) {
2N/A if (rdata + pbyte >= edata) goto formerr;
2N/A memset(&a, 0, sizeof(a));
2N/A memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
2N/A (void) inet_ntop(AF_INET6, &a, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A rdata += sizeof(a) - pbyte;
2N/A }
2N/A
2N/A /* prefix name: provided only when prefix len > 0 */
2N/A if (pbit == 0)
2N/A break;
2N/A if (rdata >= edata) goto formerr;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A break;
2N/A }
2N/A
2N/A case ns_t_opt: {
2N/A len = SPRINTF((tmp, "%u bytes", class));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A case ns_t_ds:
2N/A case ns_t_dlv:
2N/A case ns_t_sshfp: {
2N/A u_int t;
2N/A
2N/A if (type == ns_t_ds || type == ns_t_dlv) {
2N/A if (rdlen < 4U) goto formerr;
2N/A t = ns_get16(rdata);
2N/A rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u ", t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A } else
2N/A if (rdlen < 2U) goto formerr;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A while (rdata < edata) {
2N/A len = SPRINTF((tmp, "%02X", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A case ns_t_nsec3:
2N/A case ns_t_nsec3param: {
2N/A u_int t, w, l, j, k, c;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A t = ns_get16(rdata);
2N/A rdata += NS_INT16SZ;
2N/A len = SPRINTF((tmp, "%u ", t));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A t = *rdata++;
2N/A if (t == 0) {
2N/A T(addstr("-", 1, &buf, &buflen));
2N/A } else {
2N/A while (t-- > 0) {
2N/A len = SPRINTF((tmp, "%02X", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A }
2N/A }
2N/A if (type == ns_t_nsec3param)
2N/A break;
2N/A T(addstr(" ", 1, &buf, &buflen));
2N/A
2N/A t = *rdata++;
2N/A while (t > 0) {
2N/A switch (t) {
2N/A case 1:
2N/A tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
2N/A tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
2N/A tmp[2] = tmp[3] = tmp[4] = '=';
2N/A tmp[5] = tmp[6] = tmp[7] = '=';
2N/A break;
2N/A case 2:
2N/A tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
2N/A tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
2N/A ((rdata[1]>>6)&0x03)];
2N/A tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
2N/A tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
2N/A tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
2N/A break;
2N/A case 3:
2N/A tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
2N/A tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
2N/A ((rdata[1]>>6)&0x03)];
2N/A tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
2N/A tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
2N/A ((rdata[2]>>4)&0x0f)];
2N/A tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
2N/A tmp[5] = tmp[6] = tmp[7] = '=';
2N/A break;
2N/A case 4:
2N/A tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
2N/A tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
2N/A ((rdata[1]>>6)&0x03)];
2N/A tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
2N/A tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
2N/A ((rdata[2]>>4)&0x0f)];
2N/A tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
2N/A ((rdata[3]>>7)&0x01)];
2N/A tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
2N/A tmp[6] = base32hex[(rdata[3]<<3)&0x18];
2N/A tmp[7] = '=';
2N/A break;
2N/A default:
2N/A tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
2N/A tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
2N/A ((rdata[1]>>6)&0x03)];
2N/A tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
2N/A tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
2N/A ((rdata[2]>>4)&0x0f)];
2N/A tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
2N/A ((rdata[3]>>7)&0x01)];
2N/A tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
2N/A tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
2N/A ((rdata[4]>>5)&0x07)];
2N/A tmp[7] = base32hex[(rdata[4]&0x1f)];
2N/A break;
2N/A }
2N/A T(addstr(tmp, 8, &buf, &buflen));
2N/A if (t >= 5) {
2N/A rdata += 5;
2N/A t -= 5;
2N/A } else {
2N/A rdata += t;
2N/A t -= t;
2N/A }
2N/A }
2N/A
2N/A while (rdata < edata) {
2N/A w = *rdata++;
2N/A l = *rdata++;
2N/A for (j = 0; j < l; j++) {
2N/A if (rdata[j] == 0)
2N/A continue;
2N/A for (k = 0; k < 8; k++) {
2N/A if ((rdata[j] & (0x80 >> k)) == 0)
2N/A continue;
2N/A c = w * 256 + j * 8 + k;
2N/A len = SPRINTF((tmp, " %s", p_type(c)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A }
2N/A }
2N/A rdata += l;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A case ns_t_nsec: {
2N/A u_int w, l, j, k, c;
2N/A
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A
2N/A while (rdata < edata) {
2N/A w = *rdata++;
2N/A l = *rdata++;
2N/A for (j = 0; j < l; j++) {
2N/A if (rdata[j] == 0)
2N/A continue;
2N/A for (k = 0; k < 8; k++) {
2N/A if ((rdata[j] & (0x80 >> k)) == 0)
2N/A continue;
2N/A c = w * 256 + j * 8 + k;
2N/A len = SPRINTF((tmp, " %s", p_type(c)));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A }
2N/A }
2N/A rdata += l;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A case ns_t_dhcid: {
2N/A int n;
2N/A unsigned int siz;
2N/A char base64_dhcid[8192];
2N/A const char *leader;
2N/A
2N/A siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
2N/A if (siz > sizeof(base64_dhcid) * 3/4) {
2N/A const char *str = "record too long to print";
2N/A T(addstr(str, strlen(str), &buf, &buflen));
2N/A } else {
2N/A len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
2N/A
2N/A if (len < 0)
2N/A goto formerr;
2N/A
2N/A else if (len > 15) {
2N/A T(addstr(" (", 2, &buf, &buflen));
2N/A leader = "\n\t\t";
2N/A spaced = 0;
2N/A }
2N/A else
2N/A leader = " ";
2N/A
2N/A for (n = 0; n < len; n += 48) {
2N/A T(addstr(leader, strlen(leader),
2N/A &buf, &buflen));
2N/A T(addstr(base64_dhcid + n, MIN(len - n, 48),
2N/A &buf, &buflen));
2N/A }
2N/A if (len > 15)
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A }
2N/A }
2N/A
2N/A case ns_t_ipseckey: {
2N/A int n;
2N/A unsigned int siz;
2N/A char base64_key[8192];
2N/A const char *leader;
2N/A
2N/A if (rdlen < 2)
2N/A goto formerr;
2N/A
2N/A switch (rdata[1]) {
2N/A case 0:
2N/A case 3:
2N/A if (rdlen < 3)
2N/A goto formerr;
2N/A break;
2N/A case 1:
2N/A if (rdlen < 7)
2N/A goto formerr;
2N/A break;
2N/A case 2:
2N/A if (rdlen < 19)
2N/A goto formerr;
2N/A break;
2N/A default:
2N/A comment = "unknown IPSECKEY gateway type";
2N/A goto hexify;
2N/A }
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A len = SPRINTF((tmp, "%u ", *rdata));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A
2N/A switch (rdata[-2]) {
2N/A case 0:
2N/A T(addstr(".", 1, &buf, &buflen));
2N/A break;
2N/A case 1:
2N/A (void) inet_ntop(AF_INET, rdata, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A rdata += 4;
2N/A break;
2N/A case 2:
2N/A (void) inet_ntop(AF_INET6, rdata, buf, buflen);
2N/A addlen(strlen(buf), &buf, &buflen);
2N/A rdata += 16;
2N/A break;
2N/A case 3:
2N/A T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
2N/A break;
2N/A }
2N/A
2N/A if (rdata >= edata)
2N/A break;
2N/A
2N/A siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
2N/A if (siz > sizeof(base64_key) * 3/4) {
2N/A const char *str = "record too long to print";
2N/A T(addstr(str, strlen(str), &buf, &buflen));
2N/A } else {
2N/A len = b64_ntop(rdata, edata-rdata, base64_key, siz);
2N/A
2N/A if (len < 0)
2N/A goto formerr;
2N/A
2N/A else if (len > 15) {
2N/A T(addstr(" (", 2, &buf, &buflen));
2N/A leader = "\n\t\t";
2N/A spaced = 0;
2N/A }
2N/A else
2N/A leader = " ";
2N/A
2N/A for (n = 0; n < len; n += 48) {
2N/A T(addstr(leader, strlen(leader),
2N/A &buf, &buflen));
2N/A T(addstr(base64_key + n, MIN(len - n, 48),
2N/A &buf, &buflen));
2N/A }
2N/A if (len > 15)
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A }
2N/A }
2N/A
2N/A case ns_t_hip: {
2N/A unsigned int i, hip_len, algorithm, key_len;
2N/A char base64_key[NS_MD5RSA_MAX_BASE64];
2N/A unsigned int siz;
2N/A const char *leader = "\n\t\t\t\t\t";
2N/A
2N/A hip_len = *rdata++;
2N/A algorithm = *rdata++;
2N/A key_len = ns_get16(rdata);
2N/A rdata += NS_INT16SZ;
2N/A
2N/A siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
2N/A if (siz > sizeof(base64_key) * 3/4) {
2N/A const char *str = "record too long to print";
2N/A T(addstr(str, strlen(str), &buf, &buflen));
2N/A } else {
2N/A len = sprintf(tmp, "( %u ", algorithm);
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A
2N/A for (i = 0; i < hip_len; i++) {
2N/A len = sprintf(tmp, "%02X", *rdata);
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A rdata++;
2N/A }
2N/A T(addstr(leader, strlen(leader), &buf, &buflen));
2N/A
2N/A len = b64_ntop(rdata, key_len, base64_key, siz);
2N/A if (len < 0)
2N/A goto formerr;
2N/A
2N/A T(addstr(base64_key, len, &buf, &buflen));
2N/A
2N/A rdata += key_len;
2N/A while (rdata < edata) {
2N/A T(addstr(leader, strlen(leader), &buf, &buflen));
2N/A T(addname(msg, msglen, &rdata, origin,
2N/A &buf, &buflen));
2N/A }
2N/A T(addstr(" )", 2, &buf, &buflen));
2N/A }
2N/A break;
2N/A }
2N/A
2N/A default:
2N/A comment = "unknown RR type";
2N/A goto hexify;
2N/A }
2N/A return (buf - obuf);
2N/A formerr:
2N/A comment = "RR format error";
2N/A hexify: {
2N/A int n, m;
2N/A char *p;
2N/A
2N/A len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
2N/A rdlen != 0U ? " (" : "", comment));
2N/A T(addstr(tmp, len, &buf, &buflen));
2N/A while (rdata < edata) {
2N/A p = tmp;
2N/A p += SPRINTF((p, "\n\t"));
2N/A spaced = 0;
2N/A n = MIN(16, edata - rdata);
2N/A for (m = 0; m < n; m++)
2N/A p += SPRINTF((p, "%02x ", rdata[m]));
2N/A T(addstr(tmp, p - tmp, &buf, &buflen));
2N/A if (n < 16) {
2N/A T(addstr(")", 1, &buf, &buflen));
2N/A T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
2N/A }
2N/A p = tmp;
2N/A p += SPRINTF((p, "; "));
2N/A for (m = 0; m < n; m++)
2N/A *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
2N/A ? rdata[m]
2N/A : '.';
2N/A T(addstr(tmp, p - tmp, &buf, &buflen));
2N/A rdata += n;
2N/A }
2N/A return (buf - obuf);
2N/A }
2N/A}
2N/A
2N/A/* Private. */
2N/A
2N/A/*%
2N/A * size_t
2N/A * prune_origin(name, origin)
2N/A * Find out if the name is at or under the current origin.
2N/A * return:
2N/A * Number of characters in name before start of origin,
2N/A * or length of name if origin does not match.
2N/A * notes:
2N/A * This function should share code with samedomain().
2N/A */
2N/Astatic size_t
2N/Aprune_origin(const char *name, const char *origin) {
2N/A const char *oname = name;
2N/A
2N/A while (*name != '\0') {
2N/A if (origin != NULL && ns_samename(name, origin) == 1)
2N/A return (name - oname - (name > oname));
2N/A while (*name != '\0') {
2N/A if (*name == '\\') {
2N/A name++;
2N/A /* XXX need to handle \nnn form. */
2N/A if (*name == '\0')
2N/A break;
2N/A } else if (*name == '.') {
2N/A name++;
2N/A break;
2N/A }
2N/A name++;
2N/A }
2N/A }
2N/A return (name - oname);
2N/A}
2N/A
2N/A/*%
2N/A * int
2N/A * charstr(rdata, edata, buf, buflen)
2N/A * Format a <character-string> into the presentation buffer.
2N/A * return:
2N/A * Number of rdata octets consumed
2N/A * 0 for protocol format error
2N/A * -1 for output buffer error
2N/A * side effects:
2N/A * buffer is advanced on success.
2N/A */
2N/Astatic int
2N/Acharstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
2N/A const u_char *odata = rdata;
2N/A size_t save_buflen = *buflen;
2N/A char *save_buf = *buf;
2N/A
2N/A if (addstr("\"", 1, buf, buflen) < 0)
2N/A goto enospc;
2N/A if (rdata < edata) {
2N/A int n = *rdata;
2N/A
2N/A if (rdata + 1 + n <= edata) {
2N/A rdata++;
2N/A while (n-- > 0) {
2N/A if (strchr("\n\"\\", *rdata) != NULL)
2N/A if (addstr("\\", 1, buf, buflen) < 0)
2N/A goto enospc;
2N/A if (addstr((const char *)rdata, 1,
2N/A buf, buflen) < 0)
2N/A goto enospc;
2N/A rdata++;
2N/A }
2N/A }
2N/A }
2N/A if (addstr("\"", 1, buf, buflen) < 0)
2N/A goto enospc;
2N/A return (rdata - odata);
2N/A enospc:
2N/A errno = ENOSPC;
2N/A *buf = save_buf;
2N/A *buflen = save_buflen;
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Aaddname(const u_char *msg, size_t msglen,
2N/A const u_char **pp, const char *origin,
2N/A char **buf, size_t *buflen)
2N/A{
2N/A size_t newlen, save_buflen = *buflen;
2N/A char *save_buf = *buf;
2N/A int n;
2N/A
2N/A n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
2N/A if (n < 0)
2N/A goto enospc; /*%< Guess. */
2N/A newlen = prune_origin(*buf, origin);
2N/A if (**buf == '\0') {
2N/A goto root;
2N/A } else if (newlen == 0U) {
2N/A /* Use "@" instead of name. */
2N/A if (newlen + 2 > *buflen)
2N/A goto enospc; /* No room for "@\0". */
2N/A (*buf)[newlen++] = '@';
2N/A (*buf)[newlen] = '\0';
2N/A } else {
2N/A if (((origin == NULL || origin[0] == '\0') ||
2N/A (origin[0] != '.' && origin[1] != '\0' &&
2N/A (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
2N/A /* No trailing dot. */
2N/A root:
2N/A if (newlen + 2 > *buflen)
2N/A goto enospc; /* No room for ".\0". */
2N/A (*buf)[newlen++] = '.';
2N/A (*buf)[newlen] = '\0';
2N/A }
2N/A }
2N/A *pp += n;
2N/A addlen(newlen, buf, buflen);
2N/A **buf = '\0';
2N/A return (newlen);
2N/A enospc:
2N/A errno = ENOSPC;
2N/A *buf = save_buf;
2N/A *buflen = save_buflen;
2N/A return (-1);
2N/A}
2N/A
2N/Astatic void
2N/Aaddlen(size_t len, char **buf, size_t *buflen) {
2N/A INSIST(len <= *buflen);
2N/A *buf += len;
2N/A *buflen -= len;
2N/A}
2N/A
2N/Astatic int
2N/Aaddstr(const char *src, size_t len, char **buf, size_t *buflen) {
2N/A if (len >= *buflen) {
2N/A errno = ENOSPC;
2N/A return (-1);
2N/A }
2N/A memcpy(*buf, src, len);
2N/A addlen(len, buf, buflen);
2N/A **buf = '\0';
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aaddtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
2N/A size_t save_buflen = *buflen;
2N/A char *save_buf = *buf;
2N/A int t;
2N/A
2N/A if (spaced || len >= target - 1) {
2N/A T(addstr(" ", 2, buf, buflen));
2N/A spaced = 1;
2N/A } else {
2N/A for (t = (target - len - 1) / 8; t >= 0; t--)
2N/A if (addstr("\t", 1, buf, buflen) < 0) {
2N/A *buflen = save_buflen;
2N/A *buf = save_buf;
2N/A return (-1);
2N/A }
2N/A spaced = 0;
2N/A }
2N/A return (spaced);
2N/A}
2N/A
2N/A/*! \file */