1999-03-07 Mark Kettenis <kettenis@gnu.org>
[kopensolaris-gnu/glibc.git] / resolv / res_debug.c
index 602042e..eadb020 100644 (file)
@@ -3,7 +3,7 @@
  * -
  * Copyright (c) 1985, 1990, 1993
  *    The Regents of the University of California.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -19,7 +19,7 @@
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * SUCH DAMAGE.
  * -
  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- * 
+ *
  * 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, and that
  * the name of Digital Equipment Corporation not be used in advertising or
  * publicity pertaining to distribution of the document or software without
  * specific, written prior permission.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
  * -
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
  * --Copyright--
  */
 
@@ -59,14 +81,20 @@ static char rcsid[] = "$Id$";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
 
-#include <stdio.h>
+#include <ctype.h>
 #include <netdb.h>
 #include <resolv.h>
-#if defined(BSD) && (BSD >= 199103)
+#include <stdio.h>
+#include <time.h>
+
+#if defined(BSD) && (BSD >= 199103) && defined(AF_INET6)
+# include <stdlib.h>
 # include <string.h>
 #else
 # include "../conf/portability.h"
@@ -76,43 +104,8 @@ static char rcsid[] = "$Id$";
 # include "../conf/options.h"
 #endif
 
-const char *_res_opcodes[] = {
-       "QUERY",
-       "IQUERY",
-       "CQUERYM",
-       "CQUERYU",      /* experimental */
-       "NOTIFY",       /* experimental */
-       "5",
-       "6",
-       "7",
-       "8",
-       "UPDATEA",
-       "UPDATED",
-       "UPDATEDA",
-       "UPDATEM",
-       "UPDATEMA",
-       "ZONEINIT",
-       "ZONEREF",
-};
-
-const char *_res_resultcodes[] = {
-       "NOERROR",
-       "FORMERR",
-       "SERVFAIL",
-       "NXDOMAIN",
-       "NOTIMP",
-       "REFUSED",
-       "6",
-       "7",
-       "8",
-       "9",
-       "10",
-       "11",
-       "12",
-       "13",
-       "14",
-       "NOCHANGE",
-};
+extern const char *_res_opcodes[];
+extern const char *_res_resultcodes[];
 
 /* XXX: we should use getservbyport() instead. */
 static const char *
@@ -210,7 +203,7 @@ do_rrset(msg, len, cp, cnt, pflag, file, hs)
         * Print answer records.
         */
        sflag = (_res.pfcode & pflag);
-       if (n = ntohs(cnt)) {
+       if ((n = ntohs(cnt))) {
                if ((!_res.pfcode) ||
                    ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
                        fprintf(file, hs);
@@ -245,6 +238,7 @@ __p_query(msg)
 }
 
 #ifdef ultrix
+#undef p_query
 /* ultrix 4.0's packaging has some icky packaging.  alias for it here.
  * there is more junk of this kind over in res_comp.c.
  */
@@ -293,7 +287,7 @@ __fp_nquery(msg, len, file)
        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
                return;
 
-#define TruncTest(x) if (x >= endMark) goto trunc
+#define TruncTest(x) if (x > endMark) goto trunc
 #define        ErrorTest(x) if (x == NULL) goto error
 
        /*
@@ -301,7 +295,7 @@ __fp_nquery(msg, len, file)
         */
        hp = (HEADER *)msg;
        cp = msg + HFIXEDSZ;
-       endMark = cp + len;
+       endMark = msg + len;
        if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
                fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d",
                        _res_opcodes[hp->opcode],
@@ -309,7 +303,8 @@ __fp_nquery(msg, len, file)
                        ntohs(hp->id));
                putc('\n', file);
        }
-       putc(';', file);
+       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX))
+               putc(';', file);
        if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) {
                fprintf(file, "; flags:");
                if (hp->qr)
@@ -322,6 +317,12 @@ __fp_nquery(msg, len, file)
                        fprintf(file, " rd");
                if (hp->ra)
                        fprintf(file, " ra");
+               if (hp->unused)
+                       fprintf(file, " UNUSED-BIT-ON");
+               if (hp->ad)
+                       fprintf(file, " ad");
+               if (hp->cd)
+                       fprintf(file, " cd");
        }
        if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) {
                fprintf(file, "; Ques: %d", ntohs(hp->qdcount));
@@ -329,20 +330,32 @@ __fp_nquery(msg, len, file)
                fprintf(file, ", Auth: %d", ntohs(hp->nscount));
                fprintf(file, ", Addit: %d", ntohs(hp->arcount));
        }
-       if ((!_res.pfcode) || (_res.pfcode & 
+       if ((!_res.pfcode) || (_res.pfcode &
                (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
                putc('\n',file);
        }
        /*
         * Print question records.
         */
-       if (n = ntohs(hp->qdcount)) {
+       if ((n = ntohs(hp->qdcount))) {
                if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
                        fprintf(file, ";; QUESTIONS:\n");
                while (--n >= 0) {
-                       fprintf(file, ";;\t");
+                       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+                               fprintf(file, ";;\t");
                        TruncTest(cp);
-                       cp = p_cdnname(cp, msg, len, file);
+                       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+                               cp = p_cdnname(cp, msg, len, file);
+                       else {
+                               int n;
+                               char name[MAXDNAME];
+
+                               if ((n = dn_expand(msg, msg+len, cp, name,
+                                               sizeof name)) < 0)
+                                       cp = NULL;
+                               else
+                                       cp += n;
+                       }
                        ErrorTest(cp);
                        TruncTest(cp);
                        if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
@@ -354,7 +367,8 @@ __fp_nquery(msg, len, file)
                                fprintf(file, ", class = %s\n",
                                        __p_class(_getshort((u_char*)cp)));
                        cp += INT16SZ;
-                       putc('\n', file);
+                       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+                               putc('\n', file);
                }
        }
        /*
@@ -422,6 +436,31 @@ __p_cdname(cp, msg, file)
        return (p_cdnname(cp, msg, PACKETSZ, file));
 }
 
+
+/* Return a fully-qualified domain name from a compressed name (with
+   length supplied).  */
+
+const u_char *
+__p_fqnname(cp, msg, msglen, name, namelen)
+       const u_char *cp, *msg;
+       int msglen;
+       char *name;
+       int namelen;
+{
+       int n, newlen;
+
+       if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+               return (NULL);
+       newlen = strlen (name);
+       if (newlen == 0 || name[newlen - 1] != '.') {
+               if (newlen+1 >= namelen)        /* Lack space for final dot */
+                       return (NULL);
+               else
+                       strcpy(name + newlen, ".");
+       }
+       return (cp + n);
+}
+
 /* XXX:        the rest of these functions need to become length-limited, too. (vix)
  */
 
@@ -431,18 +470,13 @@ __p_fqname(cp, msg, file)
        FILE *file;
 {
        char name[MAXDNAME];
-       int n;
+       const u_char *n;
 
-       if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0)
+       n = __p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+       if (n == NULL)
                return (NULL);
-       if (name[0] == '\0') {
-               putc('.', file);
-       } else {
-               fputs(name, file);
-               if (name[strlen(name) - 1] != '.')
-                       putc('.', file);
-       }
-       return (cp + n);
+       fputs(name, file);
+       return (n);
 }
 
 /*
@@ -458,13 +492,19 @@ __p_rr(cp, msg, file)
        const u_char *cp1, *cp2;
        u_int32_t tmpttl, t;
        int lcnt;
+       u_int16_t keyflags;
+       char rrname[MAXDNAME];          /* The fqdn of this RR */
+       char base64_key[MAX_KEY_BASE64];
 
        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
+               __set_h_errno (NETDB_INTERNAL);
                return (NULL);
        }
-       if ((cp = p_fqname(cp, msg, file)) == NULL)
+       cp = __p_fqnname(cp, msg, MAXCDNAME, rrname, sizeof rrname);
+       if (!cp)
                return (NULL);                  /* compression error */
+       fputs(rrname, file);
+
        type = _getshort((u_char*)cp);
        cp += INT16SZ;
        class = _getshort((u_char*)cp);
@@ -499,7 +539,7 @@ __p_rr(cp, msg, file)
                                address = inet_ntoa(inaddr);
                                cp += INADDRSZ;
                                protocol = *(u_char*)cp;
-                               cp += sizeof(u_char);
+                               cp += sizeof (u_char);
                                port = _getshort((u_char*)cp);
                                cp += INT16SZ;
                                fprintf(file, "\t%s\t; proto %d, port %d",
@@ -524,15 +564,27 @@ __p_rr(cp, msg, file)
        case T_HINFO:
        case T_ISDN:
                cp2 = cp + dlen;
-               if (n = *cp++) {
-                       fprintf(file, "\t%.*s", n, cp);
-                       cp += n;
+               (void) fputs("\t\"", file);
+               if ((n = (unsigned char) *cp++) != 0) {
+                       for (c = n; c > 0 && cp < cp2; c--) {
+                               if (strchr("\n\"\\", *cp))
+                                       (void) putc('\\', file);
+                               (void) putc(*cp++, file);
+                       }
                }
-               if ((cp < cp2) && (n = *cp++)) {
-                       fprintf(file, "\t%.*s", n, cp);
-                       cp += n;
-               } else if (type == T_HINFO)
+               putc('"', file);
+               if (cp < cp2 && (n = (unsigned char) *cp++) != 0) {
+                       (void) fputs ("\t\"", file);
+                       for (c = n; c > 0 && cp < cp2; c--) {
+                               if (strchr("\n\"\\", *cp))
+                                       (void) putc('\\', file);
+                               (void) putc(*cp++, file);
+                       }
+                       putc('"', file);
+               } else if (type == T_HINFO) {
+                       (void) fputs("\"?\"", file);
                        fprintf(file, "\n;; *** Warning *** OS-type missing");
+               }
                break;
 
        case T_SOA:
@@ -578,21 +630,35 @@ __p_rr(cp, msg, file)
                        return (NULL);
                break;
 
-       case T_TXT:
        case T_X25:
+               cp2 = cp + dlen;
                (void) fputs("\t\"", file);
+               if ((n = (unsigned char) *cp++) != 0) {
+                       for (c = n; c > 0 && cp < cp2; c--) {
+                               if (strchr("\n\"\\", *cp))
+                                       (void) putc('\\', file);
+                               (void) putc(*cp++, file);
+                       }
+               }
+               putc('"', file);
+               break;
+
+       case T_TXT:
+               (void) putc('\t', file);
                cp2 = cp1 + dlen;
                while (cp < cp2) {
-                       if (n = (unsigned char) *cp++) {
-                               for (c = n; c > 0 && cp < cp2; c--)
-                                       if ((*cp == '\n') || (*cp == '"')) {
-                                           (void) putc('\\', file);
-                                           (void) putc(*cp++, file);
-                                       } else
-                                           (void) putc(*cp++, file);
+                       putc('"', file);
+                       if ((n = (unsigned char) *cp++)) {
+                               for (c = n; c > 0 && cp < cp2; c--) {
+                                       if (strchr("\n\"\\", *cp))
+                                               (void) putc('\\', file);
+                                       (void) putc(*cp++, file);
+                               }
                        }
+                       putc('"', file);
+                       if (cp < cp2)
+                               putc(' ', file);
                }
-               putc('"', file);
                break;
 
        case T_NSAP:
@@ -600,6 +666,57 @@ __p_rr(cp, msg, file)
                cp += dlen;
                break;
 
+       case T_AAAA: {
+               char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+               fprintf(file, "\t%s", inet_ntop(AF_INET6, cp, t, sizeof t));
+               cp += dlen;
+               break;
+           }
+
+       case T_LOC: {
+               char t[255];
+
+               (void) fprintf(file, "\t%s", loc_ntoa(cp, t));
+               cp += dlen;
+               break;
+           }
+
+       case T_NAPTR: {
+               u_int order, preference;
+
+               order = _getshort(cp);  cp += INT16SZ;
+               preference   = _getshort(cp);  cp += INT16SZ;
+               fprintf(file, "\t%u %u ",order, preference);
+               /* Flags */
+               n = *cp++;
+               fprintf(file,"\"%.*s\" ", (int)n, cp);
+               cp += n;
+               /* Service */
+               n = *cp++;
+               fprintf(file,"\"%.*s\" ", (int)n, cp);
+               cp += n;
+               /* Regexp */
+               n = *cp++;
+               fprintf(file,"\"%.*s\" ", (int)n, cp);
+               cp += n;
+               if ((cp = p_fqname(cp, msg, file)) == NULL)
+                       return (NULL);
+               break;
+           }
+
+       case T_SRV: {
+               u_int priority, weight, port;
+
+               priority = _getshort(cp);  cp += INT16SZ;
+               weight   = _getshort(cp);  cp += INT16SZ;
+               port     = _getshort(cp);  cp += INT16SZ;
+               fprintf(file, "\t%u %u %u ", priority, weight, port);
+               if ((cp = p_fqname(cp, msg, file)) == NULL)
+                       return (NULL);
+               break;
+           }
+
        case T_MINFO:
        case T_RP:
                putc('\t', file);
@@ -632,7 +749,7 @@ __p_rr(cp, msg, file)
                fprintf(file, "\t%s %s ( ",
                        inet_ntoa(inaddr),
                        deproto((int) *cp));
-               cp += sizeof(u_char);
+               cp += sizeof (u_char);
                n = 0;
                lcnt = 0;
                while (cp < cp1 + dlen) {
@@ -653,6 +770,72 @@ __p_rr(cp, msg, file)
                putc(')', file);
                break;
 
+       case T_KEY:
+               putc('\t', file);
+               keyflags = _getshort(cp);
+               cp += 2;
+               fprintf(file,"0x%04x", keyflags );      /* flags */
+               fprintf(file," %u", *cp++);     /* protocol */
+               fprintf(file," %u (", *cp++);   /* algorithm */
+
+               n = b64_ntop(cp, (cp1 + dlen) - cp,
+                            base64_key, sizeof base64_key);
+               for (c = 0; c < n; ++c) {
+                       if (0 == (c & 0x3F))
+                               fprintf(file, "\n\t");
+                       putc(base64_key[c], file);  /* public key data */
+               }
+
+               fprintf(file, " )");
+               if (n < 0)
+                       fprintf(file, "\t; BAD BASE64");
+               fflush(file);
+               cp = cp1 + dlen;
+               break;
+
+       case T_SIG:
+               type = _getshort((u_char*)cp);
+               cp += INT16SZ;
+               fprintf(file, " %s", p_type(type));
+               fprintf(file, "\t%d", *cp++);   /* algorithm */
+               /* Check label value and print error if wrong. */
+               n = *cp++;
+               c = dn_count_labels (rrname);
+               if (n != c)
+                       fprintf(file, "\t; LABELS WRONG (%d should be %d)\n\t",
+                               n, c);
+               /* orig ttl */
+               n = _getlong((u_char*)cp);
+               if ((u_int32_t) n != tmpttl)
+                       fprintf(file, " %u", n);
+               cp += INT32SZ;
+               /* sig expire */
+               fprintf(file, " (\n\t%s",
+                       __p_secstodate(_getlong((u_char*)cp)));
+               cp += INT32SZ;
+               /* time signed */
+               fprintf(file, " %s", __p_secstodate(_getlong((u_char*)cp)));
+               cp += INT32SZ;
+               /* sig footprint */
+               fprintf(file," %u ", _getshort((u_char*)cp));
+               cp += INT16SZ;
+               /* signer's name */
+               cp = p_fqname(cp, msg, file);
+               n = b64_ntop(cp, (cp1 + dlen) - cp,
+                            base64_key, sizeof base64_key);
+               for (c = 0; c < n; c++) {
+                       if (0 == (c & 0x3F))
+                               fprintf (file, "\n\t");
+                       putc(base64_key[c], file);              /* signature */
+               }
+               /* Clean up... */
+               fprintf(file, " )");
+               if (n < 0)
+                       fprintf(file, "\t; BAD BASE64");
+               fflush(file);
+               cp = cp1+dlen;
+               break;
+
 #ifdef ALLOW_T_UNSPEC
        case T_UNSPEC:
                {
@@ -680,62 +863,168 @@ __p_rr(cp, msg, file)
        putc('\n', file);
 #endif
        if (cp - cp1 != dlen) {
-               fprintf(file, ";; packet size error (found %d, dlen was %d)\n",
-                       cp - cp1, dlen);
+               fprintf(file,
+                       ";; packet size error (found %lu, dlen was %d)\n",
+                       (unsigned long) (cp - cp1), dlen);
                cp = NULL;
        }
        return (cp);
 }
 
 /*
+ * Names of RR classes and qclasses.  Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class.  (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+       {C_IN,          "IN"},
+       {C_CHAOS,       "CHAOS"},
+       {C_HS,          "HS"},
+       {C_HS,          "HESIOD"},
+       {C_ANY,         "ANY"},
+       {C_IN,          (char *)0}
+};
+
+/*
+ * Names of RR types and qtypes.  Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type.  (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+       {T_A,           "A",            "address"},
+       {T_NS,          "NS",           "name server"},
+       {T_MD,          "MD",           "mail destination (deprecated)"},
+       {T_MF,          "MF",           "mail forwarder (deprecated)"},
+       {T_CNAME,       "CNAME",        "canonical name"},
+       {T_SOA,         "SOA",          "start of authority"},
+       {T_MB,          "MB",           "mailbox"},
+       {T_MG,          "MG",           "mail group member"},
+       {T_MR,          "MR",           "mail rename"},
+       {T_NULL,        "NULL",         "null"},
+       {T_WKS,         "WKS",          "well-known service (deprecated)"},
+       {T_PTR,         "PTR",          "domain name pointer"},
+       {T_HINFO,       "HINFO",        "host information"},
+       {T_MINFO,       "MINFO",        "mailbox information"},
+       {T_MX,          "MX",           "mail exchanger"},
+       {T_TXT,         "TXT",          "text"},
+       {T_RP,          "RP",           "responsible person"},
+       {T_AFSDB,       "AFSDB",        "DCE or AFS server"},
+       {T_X25,         "X25",          "X25 address"},
+       {T_ISDN,        "ISDN",         "ISDN address"},
+       {T_RT,          "RT",           "router"},
+       {T_NSAP,        "NSAP",         "nsap address"},
+       {T_NSAP_PTR,    "NSAP_PTR",     "domain name pointer"},
+       {T_SIG,         "SIG",          "signature"},
+       {T_KEY,         "KEY",          "key"},
+       {T_PX,          "PX",           "mapping information"},
+       {T_GPOS,        "GPOS",         "geographical position (withdrawn)"},
+       {T_AAAA,        "AAAA",         "IPv6 address"},
+       {T_LOC,         "LOC",          "location"},
+       {T_NXT,         "NXT",          "next valid name (unimplemented)"},
+       {T_EID,         "EID",          "endpoint identifier (unimplemented)"},
+       {T_NIMLOC,      "NIMLOC",       "NIMROD locator (unimplemented)"},
+       {T_SRV,         "SRV",          "server selection"},
+       {T_ATMA,        "ATMA",         "ATM address (unimplemented)"},
+       {T_IXFR,        "IXFR",         "incremental zone transfer"},
+       {T_AXFR,        "AXFR",         "zone transfer"},
+       {T_MAILB,       "MAILB",        "mailbox-related data (deprecated)"},
+       {T_MAILA,       "MAILA",        "mail agent (deprecated)"},
+       {T_UINFO,       "UINFO",        "user information (nonstandard)"},
+       {T_UID,         "UID",          "user ID (nonstandard)"},
+       {T_GID,         "GID",          "group ID (nonstandard)"},
+       {T_NAPTR,       "NAPTR",        "URN Naming Authority"},
+#ifdef ALLOW_T_UNSPEC
+       {T_UNSPEC,      "UNSPEC",       "unspecified data (nonstandard)"},
+#endif /* ALLOW_T_UNSPEC */
+       {T_ANY,         "ANY",          "\"any\""},
+       {0,             NULL,           NULL}
+};
+
+int
+__sym_ston(syms, name, success)
+       const struct res_sym *syms;
+       char *name;
+       int *success;
+{
+#ifdef _LIBC
+       /* Changed to prevent warning. --drepper@gnu  */
+       for (; syms->name != 0; syms++) {
+#else
+       for (NULL; syms->name != 0; syms++) {
+#endif
+               if (strcasecmp (name, syms->name) == 0) {
+                       if (success)
+                               *success = 1;
+                       return (syms->number);
+               }
+       }
+       if (success)
+               *success = 0;
+       return (syms->number);          /* The default value. */
+}
+
+const char *
+__sym_ntos(syms, number, success)
+       const struct res_sym *syms;
+       int number;
+       int *success;
+{
+       static char unname[20];
+
+#ifdef _LIBC
+       /* Changed to prevent warning. --drepper@gnu  */
+       for (; syms->name != 0; syms++) {
+#else
+       for (NULL; syms->name != 0; syms++) {
+#endif
+               if (number == syms->number) {
+                       if (success)
+                               *success = 1;
+                       return (syms->name);
+               }
+       }
+
+       sprintf (unname, "%d", number);
+       if (success)
+               *success = 0;
+       return (unname);
+}
+
+
+const char *
+__sym_ntop(syms, number, success)
+       const struct res_sym *syms;
+       int number;
+       int *success;
+{
+       static char unname[20];
+
+#ifdef _LIBC
+       /* Changed to prevent warning. --drepper@gnu  */
+       for (; syms->name != 0; syms++) {
+#else
+       for (NULL; syms->name != 0; syms++) {
+#endif
+               if (number == syms->number) {
+                       if (success)
+                               *success = 1;
+                       return (syms->humanname);
+               }
+       }
+       sprintf(unname, "%d", number);
+       if (success)
+               *success = 0;
+       return (unname);
+}
+
+/*
  * Return a string for the type
  */
 const char *
 __p_type(type)
        int type;
 {
-       static char nbuf[20];
-
-       switch (type) {
-       case T_A:       return "A";
-       case T_NS:      return "NS";
-       case T_CNAME:   return "CNAME";
-       case T_SOA:     return "SOA";
-       case T_MB:      return "MB";
-       case T_MG:      return "MG";
-       case T_MR:      return "MR";
-       case T_NULL:    return "NULL";
-       case T_WKS:     return "WKS";
-       case T_PTR:     return "PTR";
-       case T_HINFO:   return "HINFO";
-       case T_MINFO:   return "MINFO";
-       case T_MX:      return "MX";
-       case T_TXT:     return "TXT";
-       case T_RP:      return "RP";
-       case T_AFSDB:   return "AFSDB";
-       case T_X25:     return "X25";
-       case T_ISDN:    return "ISDN";
-       case T_RT:      return "RT";
-       case T_NSAP:    return "NSAP";
-       case T_NSAP_PTR: return "NSAP_PTR";
-       case T_SIG:     return "SIG";
-       case T_KEY:     return "KEY";
-       case T_PX:      return "PX";
-       case T_GPOS:    return "GPOS";
-       case T_AAAA:    return "AAAA";
-       case T_LOC:     return "LOC";
-       case T_AXFR:    return "AXFR";
-       case T_MAILB:   return "MAILB";
-       case T_MAILA:   return "MAILA";
-       case T_ANY:     return "ANY";
-       case T_UINFO:   return "UINFO";
-       case T_UID:     return "UID";
-       case T_GID:     return "GID";
-#ifdef ALLOW_T_UNSPEC
-       case T_UNSPEC:  return "UNSPEC";
-#endif /* ALLOW_T_UNSPEC */
-       default:        (void)sprintf(nbuf, "%d", type); return (nbuf);
-       }
+       return (__sym_ntos (__p_type_syms, type, (int *)0));
 }
 
 /*
@@ -745,14 +1034,7 @@ const char *
 __p_class(class)
        int class;
 {
-       static char nbuf[20];
-
-       switch (class) {
-       case C_IN:      return "IN";
-       case C_HS:      return "HS";
-       case C_ANY:     return "ANY";
-       default:        (void)sprintf(nbuf, "%d", class); return (nbuf);
-       }
+       return (__sym_ntos (__p_class_syms, class, (int *)0));
 }
 
 /*
@@ -785,11 +1067,11 @@ __p_option(option)
 /*
  * Return a mnemonic for a time to live
  */
-char *
-__p_time(value)
+const char *
+p_time(value)
        u_int32_t value;
 {
-       static char nbuf[40];
+       static char nbuf[60];
        int secs, mins, hours, days;
        register char *p;
 
@@ -832,3 +1114,442 @@ __p_time(value)
        }
        return (nbuf);
 }
+
+/*
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+                                     1000000,10000000,100000000,1000000000};
+
+/* takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+       u_int8_t prec;
+{
+       static char retbuf[sizeof "90000000.00"];
+       unsigned long val;
+       int mantissa, exponent;
+
+       mantissa = (int)((prec >> 4) & 0x0f) % 10;
+       exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+       val = mantissa * poweroften[exponent];
+
+       (void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
+       return (retbuf);
+}
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
+static u_int8_t
+precsize_aton(strptr)
+       char **strptr;
+{
+       u_int8_t retval = 0;
+       char *cp;
+       int exponent = 0;
+       int mantissa = 0;
+
+       cp = *strptr;
+       while (isdigit(*cp)) {
+               if (mantissa == 0)
+                       mantissa = *cp - '0';
+               else
+                       exponent++;
+               cp++;
+       }
+
+       if (*cp == '.') {
+               cp++;
+               if (isdigit(*cp)) {
+                       if (mantissa == 0)
+                               mantissa = *cp - '0';
+                       else
+                               exponent++;
+                       cp++;
+
+                       if (isdigit(*cp)) {
+                               if (mantissa == 0)
+                                       mantissa = *cp - '0';
+                               else
+                                       exponent++;
+                               cp++;
+                       }
+                       else
+                               exponent++;
+               }
+       }
+       else
+               exponent += 2;
+
+       if (mantissa == 0)
+               exponent = 0;
+       retval = (mantissa << 4) | exponent;
+       *strptr = cp;
+       return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
+static u_int32_t
+latlon2ul(latlonstrptr,which)
+       char **latlonstrptr;
+       int *which;
+{
+       register char *cp;
+       u_int32_t retval;
+       int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+       cp = *latlonstrptr;
+
+       while (isdigit(*cp))
+               deg = deg * 10 + (*cp++ - '0');
+
+       while (isspace(*cp))
+               cp++;
+
+       if (!(isdigit(*cp)))
+               goto fndhemi;
+
+       while (isdigit(*cp))
+               min = min * 10 + (*cp++ - '0');
+
+       while (isspace(*cp))
+               cp++;
+
+       if (!(isdigit(*cp)))
+               goto fndhemi;
+
+       while (isdigit(*cp))
+               secs = secs * 10 + (*cp++ - '0');
+
+       if (*cp == '.') {               /* decimal seconds */
+               cp++;
+               if (isdigit(*cp)) {
+                       secsfrac = (*cp++ - '0') * 100;
+                       if (isdigit(*cp)) {
+                               secsfrac += (*cp++ - '0') * 10;
+                               if (isdigit(*cp)) {
+                                       secsfrac += (*cp++ - '0');
+                               }
+                       }
+               }
+       }
+
+       while (!isspace(*cp))   /* if any trailing garbage */
+               cp++;
+
+       while (isspace(*cp))
+               cp++;
+
+ fndhemi:
+       switch (*cp) {
+       case 'N': case 'n':
+       case 'E': case 'e':
+               retval = ((unsigned)1<<31)
+                       + (((((deg * 60) + min) * 60) + secs) * 1000)
+                       + secsfrac;
+               break;
+       case 'S': case 's':
+       case 'W': case 'w':
+               retval = ((unsigned)1<<31)
+                       - (((((deg * 60) + min) * 60) + secs) * 1000)
+                       - secsfrac;
+               break;
+       default:
+               retval = 0;     /* invalid value -- indicates error */
+               break;
+       }
+
+       switch (*cp) {
+       case 'N': case 'n':
+       case 'S': case 's':
+               *which = 1;     /* latitude */
+               break;
+       case 'E': case 'e':
+       case 'W': case 'w':
+               *which = 2;     /* longitude */
+               break;
+       default:
+               *which = 0;     /* error */
+               break;
+       }
+
+       cp++;                   /* skip the hemisphere */
+
+       while (!isspace(*cp))   /* if any trailing garbage */
+               cp++;
+
+       while (isspace(*cp))    /* move to next field */
+               cp++;
+
+       *latlonstrptr = cp;
+
+       return (retval);
+}
+
+/* converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(ascii, binary)
+       const char *ascii;
+       u_char *binary;
+{
+       const char *cp, *maxcp;
+       u_char *bcp;
+
+       u_int32_t latit = 0, longit = 0, alt = 0;
+       u_int32_t lltemp1 = 0, lltemp2 = 0;
+       int altmeters = 0, altfrac = 0, altsign = 1;
+       u_int8_t hp = 0x16;     /* default = 1e6 cm = 10000.00m = 10km */
+       u_int8_t vp = 0x13;     /* default = 1e3 cm = 10.00m */
+       u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
+       int which1 = 0, which2 = 0;
+
+       cp = ascii;
+       maxcp = cp + strlen(ascii);
+
+       lltemp1 = latlon2ul(&cp, &which1);
+
+       lltemp2 = latlon2ul(&cp, &which2);
+
+       switch (which1 + which2) {
+       case 3:                 /* 1 + 2, the only valid combination */
+               if ((which1 == 1) && (which2 == 2)) { /* normal case */
+                       latit = lltemp1;
+                       longit = lltemp2;
+               } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
+                       longit = lltemp1;
+                       latit = lltemp2;
+               } else {        /* some kind of brokenness */
+                       return (0);
+               }
+               break;
+       default:                /* we didn't get one of each */
+               return (0);
+       }
+
+       /* altitude */
+       if (*cp == '-') {
+               altsign = -1;
+               cp++;
+       }
+
+       if (*cp == '+')
+               cp++;
+
+       while (isdigit(*cp))
+               altmeters = altmeters * 10 + (*cp++ - '0');
+
+       if (*cp == '.') {               /* decimal meters */
+               cp++;
+               if (isdigit(*cp)) {
+                       altfrac = (*cp++ - '0') * 10;
+                       if (isdigit(*cp)) {
+                               altfrac += (*cp++ - '0');
+                       }
+               }
+       }
+
+       alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+       while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       siz = precsize_aton(&cp);
+
+       while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       hp = precsize_aton(&cp);
+
+       while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       vp = precsize_aton(&cp);
+
+ defaults:
+
+       bcp = binary;
+       *bcp++ = (u_int8_t) 0;  /* version byte */
+       *bcp++ = siz;
+       *bcp++ = hp;
+       *bcp++ = vp;
+       PUTLONG(latit,bcp);
+       PUTLONG(longit,bcp);
+       PUTLONG(alt,bcp);
+
+       return (16);            /* size of RR in octets */
+}
+
+/* takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(binary, ascii)
+       const u_char *binary;
+       char *ascii;
+{
+       static char *error = "?";
+       register const u_char *cp = binary;
+
+       int latdeg, latmin, latsec, latsecfrac;
+       int longdeg, longmin, longsec, longsecfrac;
+       char northsouth, eastwest;
+       int altmeters, altfrac, altsign;
+
+       const int referencealt = 100000 * 100;
+
+       int32_t latval, longval, altval;
+       u_int32_t templ;
+       u_int8_t sizeval, hpval, vpval, versionval;
+
+       char *sizestr, *hpstr, *vpstr;
+
+       versionval = *cp++;
+
+       if (versionval) {
+               sprintf(ascii, "; error: unknown LOC RR version");
+               return (ascii);
+       }
+
+       sizeval = *cp++;
+
+       hpval = *cp++;
+       vpval = *cp++;
+
+       GETLONG(templ, cp);
+       latval = (templ - ((unsigned)1<<31));
+
+       GETLONG(templ, cp);
+       longval = (templ - ((unsigned)1<<31));
+
+       GETLONG(templ, cp);
+       if (templ < (u_int32_t) referencealt) { /* below WGS 84 spheroid */
+               altval = referencealt - templ;
+               altsign = -1;
+       } else {
+               altval = templ - referencealt;
+               altsign = 1;
+       }
+
+       if (latval < 0) {
+               northsouth = 'S';
+               latval = -latval;
+       } else
+               northsouth = 'N';
+
+       latsecfrac = latval % 1000;
+       latval = latval / 1000;
+       latsec = latval % 60;
+       latval = latval / 60;
+       latmin = latval % 60;
+       latval = latval / 60;
+       latdeg = latval;
+
+       if (longval < 0) {
+               eastwest = 'W';
+               longval = -longval;
+       } else
+               eastwest = 'E';
+
+       longsecfrac = longval % 1000;
+       longval = longval / 1000;
+       longsec = longval % 60;
+       longval = longval / 60;
+       longmin = longval % 60;
+       longval = longval / 60;
+       longdeg = longval;
+
+       altfrac = altval % 100;
+       altmeters = (altval / 100) * altsign;
+
+       if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
+               sizestr = error;
+       if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
+               hpstr = error;
+       if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
+               vpstr = error;
+
+       sprintf(ascii,
+             "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
+               latdeg, latmin, latsec, latsecfrac, northsouth,
+               longdeg, longmin, longsec, longsecfrac, eastwest,
+               altmeters, altfrac, sizestr, hpstr, vpstr);
+
+       if (sizestr != error)
+               free(sizestr);
+       if (hpstr != error)
+               free(hpstr);
+       if (vpstr != error)
+               free(vpstr);
+
+       return (ascii);
+}
+
+
+/* Return the number of DNS hierarchy levels in the name. */
+int
+__dn_count_labels(name)
+       char *name;
+{
+       int i, len, count;
+
+       len = strlen(name);
+
+       for(i = 0, count = 0; i < len; i++) {
+               if (name[i] == '.')
+                       count++;
+       }
+
+       /* don't count initial wildcard */
+       if (name[0] == '*')
+               if (count)
+                       count--;
+
+       /* don't count the null label for root. */
+       /* if terminating '.' not found, must adjust */
+       /* count to include last label */
+       if (len > 0 && name[len-1] != '.')
+               count++;
+       return (count);
+}
+
+
+/*
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+__p_secstodate (secs)
+       unsigned long secs;
+{
+       static char output[15];         /* YYYYMMDDHHMMSS and null */
+       time_t clock = secs;
+       struct tm time;
+
+       __gmtime_r(&clock, &time);
+       time.tm_year += 1900;
+       time.tm_mon += 1;
+       sprintf(output, "%04d%02d%02d%02d%02d%02d",
+               time.tm_year, time.tm_mon, time.tm_mday,
+               time.tm_hour, time.tm_min, time.tm_sec);
+       return (output);
+}