summaryrefslogtreecommitdiffstats
path: root/libc/netbsd/nameser
diff options
context:
space:
mode:
Diffstat (limited to 'libc/netbsd/nameser')
-rw-r--r--libc/netbsd/nameser/ns_name.c970
-rw-r--r--libc/netbsd/nameser/ns_netint.c59
-rw-r--r--libc/netbsd/nameser/ns_parse.c209
-rw-r--r--libc/netbsd/nameser/ns_print.c915
-rw-r--r--libc/netbsd/nameser/ns_samedomain.c211
-rw-r--r--libc/netbsd/nameser/ns_ttl.c164
6 files changed, 2528 insertions, 0 deletions
diff --git a/libc/netbsd/nameser/ns_name.c b/libc/netbsd/nameser/ns_name.c
new file mode 100644
index 0000000..85d2f60
--- /dev/null
+++ b/libc/netbsd/nameser/ns_name.c
@@ -0,0 +1,970 @@
+/* $NetBSD: ns_name.c,v 1.3 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_name.c,v 1.3.2.4.4.2 2004/05/04 03:27:47 marka Exp";
+#else
+__RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $");
+#endif
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include "arpa_nameser.h"
+
+#include <errno.h>
+#ifdef ANDROID_CHANGES
+#include "resolv_private.h"
+#else
+#include <resolv.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+
+/* Data. */
+
+static const char digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* Forward. */
+
+static int special(int);
+static int printable(int);
+static int dn_find(const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *);
+static int encode_bitsring(const char **, const char *,
+ unsigned char **, unsigned char **,
+ unsigned const char *);
+static int labellen(const u_char *);
+static int decode_bitstring(const unsigned char **,
+ char *, const char *);
+
+/* Public. */
+
+/*
+ * ns_name_ntop(src, dst, dstsiz)
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+ * return:
+ * Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ * The root is returned as "."
+ * All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /* XXX */
+ return(-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ int m;
+
+ if (n != DNS_LABELTYPE_BITSTRING) {
+ /* XXX: labellen should reject this case */
+ errno = EINVAL;
+ return(-1);
+ }
+ if ((m = decode_bitstring(&cp, dn, eom)) < 0)
+ {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ dn += m;
+ continue;
+ }
+ for (; l > 0; l--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*
+ * ns_name_pton(src, dst, dstsiz)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * notes:
+ * Enforces label and domain length limits.
+ */
+
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
+{
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /* start a bit string label */
+ if ((cp = strchr(src, ']')) == NULL) {
+ errno = EINVAL; /* ??? */
+ return(-1);
+ }
+ if ((e = encode_bitsring(&src, cp + 2,
+ &label, &bp, eom))
+ != 0) {
+ errno = e;
+ return(-1);
+ }
+ escaped = 0;
+ label = bp++;
+ if ((c = *src++) == 0)
+ goto done;
+ else if (c != '.') {
+ errno = EINVAL;
+ return(-1);
+ }
+ continue;
+ }
+ else if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (1);
+ }
+ if (c == 0 || *src == '.') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ done:
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /* src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * ns_name_ntol(src, dst, dstsiz)
+ * Convert a network strings labels into all lowercase.
+ * return:
+ * Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ * Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ u_char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = n;
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for (; l > 0; l--) {
+ c = *cp++;
+ if (isupper(c))
+ *dn++ = tolower(c);
+ else
+ *dn++ = c;
+ }
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*
+ * ns_name_unpack(msg, eom, src, dst, dstsiz)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz)
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, len, checked, l;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ case NS_TYPE_ELT:
+ /* Limit checks. */
+ if ((l = labellen(srcp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return(-1);
+ }
+ if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += l + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, (size_t)l);
+ dstp += l;
+ srcp += l;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+ if (srcp < msg || srcp >= eom) { /* Out of range. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /* flag error */
+ }
+ }
+ *dstp = '\0';
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*
+ * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Pack domain name 'domain' into 'comp_dn'.
+ * return:
+ * Size of the compressed name, or -1.
+ * notes:
+ * 'dnptrs' is an array of pointers to previous compressed names.
+ * dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ * Side effects:
+ * The list of pointers in dnptrs is updated for labels inserted into
+ * the message as we compress the name. If 'dnptr' is NULL, we don't
+ * try to compress names. If 'lastdnptr' is NULL, we don't update the
+ * list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ ;
+ lpp = cpp; /* end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((l0 = labellen(srcp)) < 0) {
+ errno = EINVAL;
+ return(-1);
+ }
+ l += l0 + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+ *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+ memcpy(dstp, srcp, (size_t)(n + 1));
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*
+ * ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ * Expand compressed domain name to presentation format.
+ * return:
+ * Number of bytes read out of `src', or -1 (with errno set).
+ * note:
+ * Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, size_t dstsiz)
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*
+ * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Compress a domain name into wire format, using compression pointers.
+ * return:
+ * Number of bytes consumed in `dst' or -1 (with errno set).
+ * notes:
+ * 'dnptrs' is an array of pointers to previous compressed names.
+ * dnptrs[0] is a pointer to the beginning of the message.
+ * The list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * array pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the name.
+ * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr));
+}
+
+/*
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+ const u_char **lastdnptr)
+{
+ while (dnptrs < lastdnptr && *dnptrs != NULL) {
+ if (*dnptrs >= src) {
+ *dnptrs = NULL;
+ break;
+ }
+ dnptrs++;
+ }
+}
+
+/*
+ * ns_name_skip(ptrptr, eom)
+ * Advance *ptrptr to skip over the compressed name it points at.
+ * return:
+ * 0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom)
+{
+ const u_char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /* EDNS0 extended label */
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /* XXX */
+ return(-1);
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /* indirection */
+ cp++;
+ break;
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Private. */
+
+/*
+ * special(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ * return:
+ * boolean.
+ */
+static int
+special(int ch) {
+ switch (ch) {
+ case 0x22: /* '"' */
+ case 0x2E: /* '.' */
+ case 0x3B: /* ';' */
+ case 0x5C: /* '\\' */
+ case 0x28: /* '(' */
+ case 0x29: /* ')' */
+ /* Special modifiers in zone files. */
+ case 0x40: /* '@' */
+ case 0x24: /* '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * printable(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ * return:
+ * boolean.
+ */
+static int
+printable(int ch) {
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*
+ * dn_find(domain, msg, dnptrs, lastdnptr)
+ * Search for the counted-label name in an array of compressed names.
+ * return:
+ * offset from msg if found, or -1.
+ * notes:
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+ const u_char * const *dnptrs,
+ const u_char * const *lastdnptr)
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ n = labellen(cp - 1); /* XXX */
+
+ if (n != *dn++)
+ goto next;
+
+ for (; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /* indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ sp += *sp + 1;
+ }
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
+{
+ const unsigned char *cp = *cpp;
+ char *beg = dn, tc;
+ int b, blen, plen, i;
+
+ if ((blen = (*cp & 0xff)) == 0)
+ blen = 256;
+ plen = (blen + 3) / 4;
+ plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+ if (dn + plen >= eom)
+ return(-1);
+
+ cp++;
+ i = SPRINTF((dn, "\\[x"));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ for (b = blen; b > 7; b -= 8, cp++) {
+ i = SPRINTF((dn, "%02x", *cp & 0xff));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ if (b > 4) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ } else if (b > 0) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%1x",
+ (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ i = SPRINTF((dn, "/%d]", blen));
+ if (i < 0)
+ return (-1);
+ dn += i;
+
+ *cpp = cp;
+ return(dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
+ unsigned char ** dst, unsigned const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ char c;
+ const char *beg_blen;
+ char *end_blen = NULL;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = end_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return(EINVAL);
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return(EINVAL);
+ if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
+ return(EINVAL);
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ switch((c = *cp)) {
+ case ']': /* end of the bitstring */
+ if (afterslash) {
+ if (beg_blen == NULL)
+ return(EINVAL);
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return(EINVAL);
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /* skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!isdigit(c&0xff))
+ return(EINVAL);
+ if (beg_blen == NULL) {
+
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return(EINVAL);
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!isxdigit(c&0xff))
+ return(EINVAL);
+ value <<= 4;
+ value += digitvalue[(int)c];
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return(EINVAL);
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return(EMSGSIZE);
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC 2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return(EINVAL);
+ traillen = tbcount - blen; /* between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return(EINVAL);
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return(0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+ int bitlen;
+ u_char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return(-1);
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ if ((bitlen = *(lp + 1)) == 0)
+ bitlen = 256;
+ return((bitlen + 7 ) / 8 + 1);
+ }
+ return(-1); /* unknwon ELT */
+ }
+ return(l);
+}
diff --git a/libc/netbsd/nameser/ns_netint.c b/libc/netbsd/nameser/ns_netint.c
new file mode 100644
index 0000000..1b2964f
--- /dev/null
+++ b/libc/netbsd/nameser/ns_netint.c
@@ -0,0 +1,59 @@
+/* $NetBSD: ns_netint.c,v 1.2 2004/05/20 20:19:00 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_netint.c,v 1.1.206.1 2004/03/09 08:33:44 marka Exp";
+#else
+__RCSID("$NetBSD: ns_netint.c,v 1.2 2004/05/20 20:19:00 christos Exp $");
+#endif
+#endif
+
+/* Import. */
+
+#include "arpa_nameser.h"
+
+/* Public. */
+
+u_int16_t
+ns_get16(const u_char *src) {
+ u_int dst;
+
+ NS_GET16(dst, src);
+ return (dst);
+}
+
+u_int32_t
+ns_get32(const u_char *src) {
+ u_long dst;
+
+ NS_GET32(dst, src);
+ return (dst);
+}
+
+void
+ns_put16(u_int16_t src, u_char *dst) {
+ NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_int32_t src, u_char *dst) {
+ NS_PUT32(src, dst);
+}
diff --git a/libc/netbsd/nameser/ns_parse.c b/libc/netbsd/nameser/ns_parse.c
new file mode 100644
index 0000000..fd94860
--- /dev/null
+++ b/libc/netbsd/nameser/ns_parse.c
@@ -0,0 +1,209 @@
+/* $NetBSD: ns_parse.c,v 1.2 2004/05/20 20:35:05 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_parse.c,v 1.3.2.1.4.1 2004/03/09 08:33:44 marka Exp";
+#else
+__RCSID("$NetBSD: ns_parse.c,v 1.2 2004/05/20 20:35:05 christos Exp $");
+#endif
+#endif
+
+/* Import. */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include "arpa_nameser.h"
+
+#include <errno.h>
+#ifdef ANDROID_CHANGES
+#include "resolv_private.h"
+#else
+#include <resolv.h>
+#endif
+#include <string.h>
+
+/* Forward. */
+
+static void setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#define RETERR(err) do { errno = (err); return (-1); } while (/*NOTREACHED*//*CONSTCOND*/0)
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+const struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /* qr. */
+ { 0x7800, 11 }, /* opcode. */
+ { 0x0400, 10 }, /* aa. */
+ { 0x0200, 9 }, /* tc. */
+ { 0x0100, 8 }, /* rd. */
+ { 0x0080, 7 }, /* ra. */
+ { 0x0040, 6 }, /* z. */
+ { 0x0020, 5 }, /* ad. */
+ { 0x0010, 4 }, /* cd. */
+ { 0x000f, 0 }, /* rcode. */
+ { 0x0000, 0 }, /* expansion (1/6). */
+ { 0x0000, 0 }, /* expansion (2/6). */
+ { 0x0000, 0 }, /* expansion (3/6). */
+ { 0x0000, 0 }, /* expansion (4/6). */
+ { 0x0000, 0 }, /* expansion (5/6). */
+ { 0x0000, 0 }, /* expansion (6/6). */
+};
+
+int ns_msg_getflag(ns_msg handle, int flag) {
+ return((u_int32_t)((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+ const u_char *optr = ptr;
+
+ for (; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0)
+ RETERR(EMSGSIZE);
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+ if (ptr > eom)
+ RETERR(EMSGSIZE);
+ return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
+ const u_char *eom = msg + msglen;
+ int i;
+
+ memset(handle, 0x5e, sizeof *handle);
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return (-1);
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+ if (msg != eom)
+ RETERR(EMSGSIZE);
+ setsection(handle, ns_s_max);
+ return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+ int b;
+
+ /* Make section right. */
+ if ((unsigned)section >= (unsigned)ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_msg_ptr = msg->_sections[(int)sect];
+ }
+}
diff --git a/libc/netbsd/nameser/ns_print.c b/libc/netbsd/nameser/ns_print.c
new file mode 100644
index 0000000..7465e62
--- /dev/null
+++ b/libc/netbsd/nameser/ns_print.c
@@ -0,0 +1,915 @@
+/* $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);
+}
diff --git a/libc/netbsd/nameser/ns_samedomain.c b/libc/netbsd/nameser/ns_samedomain.c
new file mode 100644
index 0000000..04fdb61
--- /dev/null
+++ b/libc/netbsd/nameser/ns_samedomain.c
@@ -0,0 +1,211 @@
+/* $NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995,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_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34:17 marka Exp";
+#else
+__RCSID("$NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $");
+#endif
+#endif
+
+#include <sys/types.h>
+#include "arpa_nameser.h"
+#include <errno.h>
+#include <string.h>
+
+#ifndef _LIBC
+/*
+ * int
+ * ns_samedomain(a, b)
+ * Check whether a name belongs to a domain.
+ * Inputs:
+ * a - the domain whose ancestory is being verified
+ * b - the potential ancestor we're checking against
+ * Return:
+ * boolean - is a at or below b?
+ * Notes:
+ * Trailing dots are first removed from name and domain.
+ * Always compare complete subdomains, not only whether the
+ * domain name is the trailing string of the given name.
+ *
+ * "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ * but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+ if (la != 0U && a[la - 1] == '.') {
+ escaped = 0;
+ /* Note this loop doesn't get executed if la==1. */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ la--;
+ }
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+ if (lb != 0U && b[lb - 1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ lb--;
+ }
+
+ /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+ if (lb == 0U)
+ return (1);
+
+ /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+ if (lb > la)
+ return (0);
+
+ /* 'a' and 'b' being equal at this point indicates sameness. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /*
+ * If 'a' is only 1 character longer than 'b', then it can't be
+ * a subdomain of 'b' (because of the need for the '.' label
+ * separator).
+ */
+ if (diff < 2)
+ return (0);
+
+ /*
+ * If the character before the last 'lb' characters of 'b'
+ * isn't '.', then it can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com").
+ */
+ if (a[diff - 1] != '.')
+ return (0);
+
+ /*
+ * We're not sure about that '.', however. It could be escaped
+ * and thus not a really a label separator.
+ */
+ escaped = 0;
+ for (i = diff - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (escaped)
+ return (0);
+
+ /* Now compare aligned trailing substring. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+/*
+ * int
+ * ns_subdomain(a, b)
+ * is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+ return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+#endif
+
+/*
+ * int
+ * ns_makecanon(src, dst, dstsize)
+ * make a canonical copy of domain name "src"
+ * notes:
+ * foo -> foo.
+ * foo. -> foo.
+ * foo.. -> foo.
+ * foo\. -> foo\..
+ * foo\\. -> foo\\.
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+ size_t n = strlen(src);
+
+ if (n + sizeof "." > dstsize) { /* Note: sizeof == 2 */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(dst, src);
+ while (n >= 1U && dst[n - 1] == '.') /* Ends in "." */
+ if (n >= 2U && dst[n - 2] == '\\' && /* Ends in "\." */
+ (n < 3U || dst[n - 3] != '\\')) /* But not "\\." */
+ break;
+ else
+ dst[--n] = '\0';
+ dst[n++] = '.';
+ dst[n] = '\0';
+ return (0);
+}
+
+/*
+ * int
+ * ns_samename(a, b)
+ * determine whether domain name "a" is the same as domain name "b"
+ * return:
+ * -1 on error
+ * 0 if names differ
+ * 1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+ ns_makecanon(b, tb, sizeof tb) < 0)
+ return (-1);
+ if (strcasecmp(ta, tb) == 0)
+ return (1);
+ else
+ return (0);
+}
diff --git a/libc/netbsd/nameser/ns_ttl.c b/libc/netbsd/nameser/ns_ttl.c
new file mode 100644
index 0000000..0878194
--- /dev/null
+++ b/libc/netbsd/nameser/ns_ttl.c
@@ -0,0 +1,164 @@
+/* $NetBSD: ns_ttl.c,v 1.2 2004/05/20 20:35:05 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_ttl.c,v 1.1.206.1 2004/03/09 08:33:45 marka Exp";
+#else
+__RCSID("$NetBSD: ns_ttl.c,v 1.2 2004/05/20 20:35:05 christos Exp $");
+#endif
+#endif
+
+/* Import. */
+
+#include "arpa_nameser.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+ char *odst = dst;
+ int secs, mins, hours, days, weeks, x;
+ char *p;
+
+ secs = src % 60; src /= 60;
+ mins = src % 60; src /= 60;
+ hours = src % 24; src /= 24;
+ days = src % 7; src /= 7;
+ weeks = src; src = 0;
+
+ x = 0;
+ if (weeks) {
+ T(fmt1(weeks, 'W', &dst, &dstlen));
+ x++;
+ }
+ if (days) {
+ T(fmt1(days, 'D', &dst, &dstlen));
+ x++;
+ }
+ if (hours) {
+ T(fmt1(hours, 'H', &dst, &dstlen));
+ x++;
+ }
+ if (mins) {
+ T(fmt1(mins, 'M', &dst, &dstlen));
+ x++;
+ }
+ if (secs || !(weeks || days || hours || mins)) {
+ T(fmt1(secs, 'S', &dst, &dstlen));
+ x++;
+ }
+
+ if (x > 1) {
+ int ch;
+
+ for (p = odst; (ch = *p) != '\0'; p++)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+ }
+
+ return (dst - odst);
+}
+
+#ifndef _LIBC
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+ u_long ttl, tmp;
+ int ch, digits, dirty;
+
+ ttl = 0;
+ tmp = 0;
+ digits = 0;
+ dirty = 0;
+ while ((ch = *src++) != '\0') {
+ if (!isascii(ch) || !isprint(ch))
+ goto einval;
+ if (isdigit(ch)) {
+ tmp *= 10;
+ tmp += (ch - '0');
+ digits++;
+ continue;
+ }
+ if (digits == 0)
+ goto einval;
+ if (islower(ch))
+ ch = toupper(ch);
+ switch (ch) {
+ case 'W': tmp *= 7; /*FALLTHROUGH*/
+ case 'D': tmp *= 24; /*FALLTHROUGH*/
+ case 'H': tmp *= 60; /*FALLTHROUGH*/
+ case 'M': tmp *= 60; /*FALLTHROUGH*/
+ case 'S': break;
+ default: goto einval;
+ }
+ ttl += tmp;
+ tmp = 0;
+ digits = 0;
+ dirty = 1;
+ }
+ if (digits > 0) {
+ if (dirty)
+ goto einval;
+ else
+ ttl += tmp;
+ }
+ *dst = ttl;
+ return (0);
+
+ einval:
+ errno = EINVAL;
+ return (-1);
+}
+#endif
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+ char tmp[50];
+ size_t len;
+
+ len = SPRINTF((tmp, "%d%c", t, s));
+ if (len + 1 > *buflen)
+ return (-1);
+ strcpy(*buf, tmp);
+ *buf += len;
+ *buflen -= len;
+ return (0);
+}