Implementation of thread-safe resolver.
authordrepper <drepper>
Sat, 4 Dec 1999 18:03:12 +0000 (18:03 +0000)
committerdrepper <drepper>
Sat, 4 Dec 1999 18:03:12 +0000 (18:03 +0000)
resolv/ns_name.c [new file with mode: 0644]
resolv/ns_netint.c [new file with mode: 0644]
resolv/ns_parse.c [new file with mode: 0644]
resolv/ns_print.c [new file with mode: 0644]
resolv/ns_samedomain.c [new file with mode: 0644]
resolv/ns_ttl.c [new file with mode: 0644]
resolv/res_debug.h [new file with mode: 0644]
resolv/res_libc.c [new file with mode: 0644]

diff --git a/resolv/ns_name.c b/resolv/ns_name.c
new file mode 100644 (file)
index 0000000..b75f731
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Data. */
+
+static const char      digits[] = "0123456789";
+
+/* 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 *);
+
+/* 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;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       /* Some kind of compression pointer. */
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               if (dn != dst) {
+                       if (dn >= eom) {
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       *dn++ = '.';
+               }
+               if (dn + n >= eom) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               for ((void)NULL; n > 0; n--) {
+                       c = *cp++;
+                       if (special(c)) {
+                               if (dn + 1 >= eom) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = (char)c;
+                       } else if (!printable(c)) {
+                               if (dn + 3 >= eom) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = digits[c / 100];
+                               *dn++ = digits[(c % 100) / 10];
+                               *dn++ = digits[c % 10];
+                       } else {
+                               if (dn >= eom) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               *dn++ = (char)c;
+                       }
+               }
+       }
+       if (dn == dst) {
+               if (dn >= eom) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               *dn++ = '.';
+       }
+       if (dn >= eom) {
+               __set_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;
+       char *cp;
+
+       escaped = 0;
+       bp = dst;
+       eom = dst + dstsiz;
+       label = bp++;
+
+       while ((c = *src++) != 0) {
+               if (escaped) {
+                       if ((cp = strchr(digits, c)) != NULL) {
+                               n = (cp - digits) * 100;
+                               if ((c = *src++) == 0 ||
+                                   (cp = strchr(digits, c)) == NULL) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               n += (cp - digits) * 10;
+                               if ((c = *src++) == 0 ||
+                                   (cp = strchr(digits, c)) == NULL) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               n += (cp - digits);
+                               if (n > 255) {
+                                       __set_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. */
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       if (label >= eom) {
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       *label = c;
+                       /* Fully qualified ? */
+                       if (*src == '\0') {
+                               if (c != 0) {
+                                       if (bp >= eom) {
+                                               __set_errno (EMSGSIZE);
+                                               return (-1);
+                                       }
+                                       *bp++ = '\0';
+                               }
+                               if ((bp - dst) > MAXCDNAME) {
+                                       __set_errno (EMSGSIZE);
+                                       return (-1);
+                               }
+                               return (1);
+                       }
+                       if (c == 0 || *src == '.') {
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       label = bp++;
+                       continue;
+               }
+               if (bp >= eom) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               *bp++ = (u_char)c;
+       }
+       c = (bp - label - 1);
+       if ((c & NS_CMPRSFLGS) != 0) {          /* Label too big. */
+               __set_errno (EMSGSIZE);
+               return (-1);
+       }
+       if (label >= eom) {
+               __set_errno (EMSGSIZE);
+               return (-1);
+       }
+       *label = c;
+       if (c != 0) {
+               if (bp >= eom) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               *bp++ = 0;
+       }
+       if ((bp - dst) > MAXCDNAME) {   /* src too big */
+               __set_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;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       /* Some kind of compression pointer. */
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               *dn++ = n;
+               if (dn + n >= eom) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               for ((void)NULL; n > 0; n--) {
+                       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;
+
+       len = -1;
+       checked = 0;
+       dstp = dst;
+       srcp = src;
+       dstlim = dst + dstsiz;
+       if (srcp < msg || srcp >= eom) {
+               __set_errno (EMSGSIZE);
+               return (-1);
+       }
+       /* Fetch next label in domain name. */
+       while ((n = *srcp++) != 0) {
+               /* Check for indirection. */
+               switch (n & NS_CMPRSFLGS) {
+               case 0:
+                       /* Limit checks. */
+                       if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       checked += n + 1;
+                       *dstp++ = n;
+                       memcpy(dstp, srcp, n);
+                       dstp += n;
+                       srcp += n;
+                       break;
+
+               case NS_CMPRSFLGS:
+                       if (srcp >= eom) {
+                               __set_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. */
+                               __set_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) {
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+                       break;
+
+               default:
+                       __set_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;
+
+       srcp = src;
+       dstp = dst;
+       eob = dstp + dstsiz;
+       lpp = cpp = NULL;
+       if (dnptrs != NULL) {
+               if ((msg = *dnptrs++) != NULL) {
+                       for (cpp = dnptrs; *cpp != NULL; cpp++)
+                               (void)NULL;
+                       lpp = cpp;      /* end of list to search */
+               }
+       } else
+               msg = NULL;
+
+       /* make sure the domain we are about to add is legal */
+       l = 0;
+       do {
+               n = *srcp;
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               l += n + 1;
+               if (l > MAXCDNAME) {
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               srcp += n + 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++ = (l >> 8) | NS_CMPRSFLGS;
+                               *dstp++ = l % 256;
+                               return (dstp - dst);
+                       }
+                       /* Not found, save it. */
+                       if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+                           (dstp - msg) < 0x4000) {
+                               *cpp++ = dstp;
+                               *cpp = NULL;
+                       }
+               }
+               /* copy label to buffer */
+               if (n & NS_CMPRSFLGS) {         /* Should not happen. */
+                       goto cleanup;
+               }
+               if (dstp + 1 + n >= eob) {
+                       goto cleanup;
+               }
+               memcpy(dstp, srcp, n + 1);
+               srcp += n + 1;
+               dstp += n + 1;
+       } while (n != 0);
+
+       if (dstp > eob) {
+cleanup:
+               if (msg != NULL)
+                       *lpp = NULL;
+               __set_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, dstsiz, dnptrs, lastdnptr));
+}
+
+/*
+ * 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;
+
+       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_CMPRSFLGS:      /* indirection */
+                       cp++;
+                       break;
+               default:                /* illegal type */
+                       __set_errno (EMSGSIZE);
+                       return (-1);
+               }
+               break;
+       }
+       if (cp > eom) {
+               __set_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: /* '\\' */
+       /* 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++) {
+               dn = domain;
+               sp = cp = *cpp;
+               while ((n = *cp++) != 0) {
+                       /*
+                        * check for indirection
+                        */
+                       switch (n & NS_CMPRSFLGS) {
+                       case 0:                 /* normal case, n == len */
+                               if (n != *dn++)
+                                       goto next;
+                               for ((void)NULL; 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 */
+                               __set_errno (EMSGSIZE);
+                               return (-1);
+                       }
+               }
+ next: ;
+       }
+       __set_errno (ENOENT);
+       return (-1);
+}
diff --git a/resolv/ns_netint.c b/resolv/ns_netint.c
new file mode 100644 (file)
index 0000000..9dcf91c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/* Import. */
+
+#include <arpa/nameser.h>
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+       u_int dst;
+
+       NS_GET16(dst, src);
+       return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+       u_long dst;
+
+       NS_GET32(dst, src);
+       return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+       NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+       NS_PUT32(src, dst);
+}
diff --git a/resolv/ns_parse.c b/resolv/ns_parse.c
new file mode 100644 (file)
index 0000000..7bbdc41
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/* Import. */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+/* Forward. */
+
+static void    setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#define RETERR(err) do { __set_errno (err); return (-1); } while (0)
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+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_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+       const u_char *optr = ptr;
+
+       for ((void)NULL; 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 (section < 0 || section >= 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->_ptr, handle->_eom, section,
+                             rrnum - handle->_rrnum);
+
+               if (b < 0)
+                       return (-1);
+               handle->_ptr += b;
+               handle->_rrnum = rrnum;
+       }
+
+       /* Do the parse. */
+       b = dn_expand(handle->_msg, handle->_eom,
+                     handle->_ptr, rr->name, NS_MAXDNAME);
+       if (b < 0)
+               return (-1);
+       handle->_ptr += b;
+       if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+               RETERR(EMSGSIZE);
+       NS_GET16(rr->type, handle->_ptr);
+       NS_GET16(rr->rr_class, handle->_ptr);
+       if (section == ns_s_qd) {
+               rr->ttl = 0;
+               rr->rdlength = 0;
+               rr->rdata = NULL;
+       } else {
+               if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+                       RETERR(EMSGSIZE);
+               NS_GET32(rr->ttl, handle->_ptr);
+               NS_GET16(rr->rdlength, handle->_ptr);
+               if (handle->_ptr + rr->rdlength > handle->_eom)
+                       RETERR(EMSGSIZE);
+               rr->rdata = handle->_ptr;
+               handle->_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->_ptr = NULL;
+       } else {
+               msg->_rrnum = 0;
+               msg->_ptr = msg->_sections[(int)sect];
+       }
+}
diff --git a/resolv/ns_print.c b/resolv/ns_print.c
new file mode 100644 (file)
index 0000000..cce3fb6
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+/* Import. */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#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);
+
+/* Proto. */
+#ifndef _LIBC
+u_int16_t       dst_s_dns_key_id(const u_char *, const int);
+#endif
+
+/* Macros. */
+
+#define        T(x) \
+       do { \
+               if ((x) < 0) \
+                       return (-1); \
+       } while (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", 3, &buf, &buflen));
+       } else {
+               len = prune_origin(name, origin);
+               if (len == 0) {
+                       T(addstr("@\t\t\t", 4, &buf, &buflen));
+               } else {
+                       T(addstr(name, len, &buf, &buflen));
+                       /* Origin not used and no trailing dot? */
+                       if ((!origin || !origin[0] || name[len] == '\0') &&
+                           name[len - 1] != '.') {
+                               T(addstr(".", 1, &buf, &buflen));
+                               len++;
+                       }
+                       T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+               }
+       }
+
+       /*
+        * TTL, Class, Type.
+        */
+       T(x = ns_format_ttl(ttl, buf, buflen));
+       addlen(x, &buf, &buflen);
+       len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+       T(addstr(tmp, len, &buf, &buflen));
+       T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+       /*
+        * RData.
+        */
+       switch (type) {
+       case ns_t_a:
+               if (rdlen != 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:
+               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(" ", 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(" ", 1, &buf, &buflen));
+
+               /* Administrator name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" (\n", 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", 5, &buf, &buflen));
+               len = SPRINTF((tmp, "%lu", t));
+               T(addstr(tmp, len, &buf, &buflen));
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; serial\n", 9, &buf, &buflen));
+               spaced = 0;
+
+               /* Refresh interval. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; refresh\n", 10, &buf, &buflen));
+               spaced = 0;
+
+               /* Retry interval. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; retry\n", 8, &buf, &buflen));
+               spaced = 0;
+
+               /* Expiry. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; expiry\n", 9, &buf, &buflen));
+               spaced = 0;
+
+               /* Minimum TTL. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(addstr(" )", 2, &buf, &buflen));
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; minimum\n", 10, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_mx:
+       case ns_t_afsdb:
+       case ns_t_rt: {
+               u_int t;
+
+               if (rdlen < NS_INT16SZ)
+                       goto formerr;
+
+               /* Priority. */
+               t = ns_get16(rdata);
+               rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", t));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Target. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_px: {
+               u_int t;
+
+               if (rdlen < NS_INT16SZ)
+                       goto formerr;
+
+               /* Priority. */
+               t = ns_get16(rdata);
+               rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", t));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Name1. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 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(" ", 1, &buf, &buflen));
+               }
+               break;
+
+       case ns_t_nsap: {
+               char t[255*3];
+
+               (void) inet_nsap_ntoa(rdlen, rdata, t);
+               T(addstr(t, strlen(t), &buf, &buflen));
+               break;
+           }
+
+       case ns_t_aaaa:
+               if (rdlen != 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 < 2*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, len, &buf, &buflen));
+
+               /* Flags. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Service. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 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(" ", 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 < NS_INT16SZ*3)
+                       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, 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(" ", 1, &buf, &buflen));
+
+               /* Name2. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               break;
+
+       case ns_t_wks: {
+               int n, lcnt;
+
+               if (rdlen < NS_INT32SZ + 1)
+                       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, 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", 5,
+                                                        &buf, &buflen));
+                                               lcnt = 10;
+                                               spaced = 0;
+                                       }
+                                       len = SPRINTF((tmp, "%d ", n));
+                                       T(addstr(tmp, len, &buf, &buflen));
+                                       lcnt--;
+                               }
+                               c <<= 1;
+                       } while (++n & 07);
+               }
+               T(addstr(")", 1, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_key: {
+#ifndef _LIBC
+               char base64_key[NS_MD5RSA_MAX_BASE64];
+               u_int keyflags, protocol, algorithm, key_id;
+               const char *leader;
+               int n;
+
+               if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+                       goto formerr;
+
+               /* Key flags, Protocol, Algorithm. */
+               key_id = dst_s_dns_key_id(rdata, edata-rdata);
+               keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
+               protocol = *rdata++;
+               algorithm = *rdata++;
+               len = SPRINTF((tmp, "0x%04x %u %u",
+                              keyflags, protocol, algorithm));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Public key data. */
+               len = b64_ntop(rdata, edata - rdata,
+                              base64_key, sizeof base64_key);
+               if (len < 0)
+                       goto formerr;
+               if (len > 15) {
+                       T(addstr(" (", 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, MIN(len - n, 48),
+                                &buf, &buflen));
+               }
+               if (len > 15)
+                       T(addstr(" )", 2, &buf, &buflen));
+               n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+               T(addstr(tmp, n, &buf, &buflen));
+#endif /* !_LIBC */
+               break;
+           }
+
+       case ns_t_sig: {
+#ifndef _LIBC
+               char base64_key[NS_MD5RSA_MAX_BASE64];
+               u_int type, algorithm, labels, footprint;
+               const char *leader;
+               u_long t;
+               int n;
+
+               if (rdlen < 22)
+                       goto formerr;
+
+               /* Type covered, Algorithm, Label count, Original TTL. */
+               type = 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(type), algorithm, labels, t));
+               T(addstr(tmp, 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, len, &buf, &buflen));
+
+               /* Time signed. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Signature Footprint. */
+               footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", footprint));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Signer's name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               /* Signature. */
+               len = b64_ntop(rdata, edata - rdata,
+                              base64_key, sizeof base64_key);
+               if (len > 15) {
+                       T(addstr(" (", 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, MIN(len - n, 48),
+                                &buf, &buflen));
+               }
+               if (len > 15)
+                       T(addstr(" )", 2, &buf, &buflen));
+#endif /* !_LIBC */
+               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, len, &buf, &buflen));
+                       }
+               break;
+           }
+
+       case ns_t_cert: {
+               u_int c_type, key_tag, alg;
+               int n, siz;
+               char base64_cert[8192], *leader, tmp[40];
+
+               c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
+               key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+               alg = (u_int) *rdata++;
+
+               len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+               T(addstr(tmp, len, &buf, &buflen));
+               siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+               if (siz > sizeof(base64_cert) * 3/4) {
+                       char *str = "record too long to print";
+                       T(addstr(str, strlen(str), &buf, &buflen));
+               }
+               else {
+                       len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+                       if (len < 0)
+                               goto formerr;
+                       else if (len > 15) {
+                               T(addstr(" (", 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, MIN(len - n, 48),
+                                        &buf, &buflen));
+                       }
+                       if (len > 15)
+                               T(addstr(" )", 2, &buf, &buflen));
+               }
+               break;
+           }
+
+       case ns_t_tsig: {
+               /* BEW - need to complete this */
+               int n;
+
+               T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 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;
+           }
+
+       default:
+               comment = "unknown RR type";
+               goto hexify;
+       }
+       return (buf - obuf);
+ formerr:
+       comment = "RR format error";
+ hexify: {
+       int n, m;
+       char *p;
+
+       len = SPRINTF((tmp, "\\#(\t\t; %s", comment));
+       T(addstr(tmp, 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, p - tmp, &buf, &buflen));
+               if (n < 16) {
+                       T(addstr(")", 1, &buf, &buflen));
+                       T(addtab(p - tmp + 1, 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, 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("\"", 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("\\", 1, buf, buflen) < 0)
+                                               goto enospc;
+                               if (addstr((const char *)rdata, 1,
+                                          buf, buflen) < 0)
+                                       goto enospc;
+                               rdata++;
+                       }
+               }
+       }
+       if (addstr("\"", 1, buf, buflen) < 0)
+               goto enospc;
+       return (rdata - odata);
+ enospc:
+       __set_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, *buflen);
+       if (n < 0)
+               goto enospc;    /* Guess. */
+       newlen = prune_origin(*buf, origin);
+       if ((origin == NULL || origin[0] == '\0' || (*buf)[newlen] == '\0') &&
+           (newlen == 0 || (*buf)[newlen - 1] != '.')) {
+               /* No trailing dot. */
+               if (newlen + 2 > *buflen)
+                       goto enospc;    /* No room for ".\0". */
+               (*buf)[newlen++] = '.';
+               (*buf)[newlen] = '\0';
+       }
+       if (newlen == 0) {
+               /* Use "@" instead of name. */
+               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:
+       __set_errno (ENOSPC);
+       *buf = save_buf;
+       *buflen = save_buflen;
+       return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+#if 0
+       INSIST(len <= *buflen);
+#endif
+       *buf += len;
+       *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+       if (len >= *buflen) {
+               __set_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("  ", 2, buf, buflen));
+               spaced = 1;
+       } else {
+               for (t = (target - len - 1) / 8; t >= 0; t--)
+                       if (addstr("\t", 1, buf, buflen) < 0) {
+                               *buflen = save_buflen;
+                               *buf = save_buf;
+                               return (-1);
+                       }
+               spaced = 0;
+       }
+       return (spaced);
+}
diff --git a/resolv/ns_samedomain.c b/resolv/ns_samedomain.c
new file mode 100644 (file)
index 0000000..bac5a63
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+/*
+ * 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 != 0 && 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 != 0 && 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 == 0)
+               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));
+}
+
+/*
+ * 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) {
+               __set_errno (EMSGSIZE);
+               return (-1);
+       }
+       strcpy(dst, src);
+       while (n > 0 && dst[n - 1] == '.')              /* Ends in "." */
+               if (n > 1 && dst[n - 2] == '\\' &&      /* Ends in "\." */
+                   (n < 2 || 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/resolv/ns_ttl.c b/resolv/ns_ttl.c
new file mode 100644 (file)
index 0000000..6be2b0d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#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 (void)NULL
+
+/* 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);
+}
+
+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;
+               case 'D':  tmp *= 24;
+               case 'H':  tmp *= 60;
+               case 'M':  tmp *= 60;
+               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:
+       __set_errno (EINVAL);
+       return (-1);
+}
+
+/* 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);
+}
diff --git a/resolv/res_debug.h b/resolv/res_debug.h
new file mode 100644 (file)
index 0000000..4a0aa99
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+#ifndef _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+#   define Dprint(cond, args) /*empty*/
+#   define DprintQ(cond, args, query, size) /*empty*/
+#   define Aerror(statp, file, string, error, address) /*empty*/
+#   define Perror(statp, file, string, error) /*empty*/
+#else
+#   define Dprint(cond, args) if (cond) {fprintf args;} else {}
+#   define DprintQ(cond, args, query, size) if (cond) {\
+                       fprintf args;\
+                       res_pquery(statp, query, size, stdout);\
+               } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */ 
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
new file mode 100644 (file)
index 0000000..14d565d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/* Define some functions that go int libc.so.  */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef _res
+
+struct __res_state _res;
+
+/* This is the old res_init function.  It has been moved from
+   res_data.c to this file since res_init should go into libc.so but
+   the rest of res_data not.  */
+
+
+int
+res_init(void) {
+       extern int __res_vinit(res_state, int);
+
+       /*
+        * These three fields used to be statically initialized.  This made
+        * it hard to use this code in a shared library.  It is necessary,
+        * now that we're doing dynamic initialization here, that we preserve
+        * the old semantics: if an application modifies one of these three
+        * fields of _res before res_init() is called, res_init() will not
+        * alter them.  Of course, if an application is setting them to
+        * _zero_ before calling res_init(), hoping to override what used
+        * to be the static default, we can't detect it and unexpected results
+        * will follow.  Zero for any of these fields would make no sense,
+        * so one can safely assume that the applications were already getting
+        * unexpected results.
+        *
+        * _res.options is tricky since some apps were known to diddle the bits
+        * before res_init() was first called. We can't replicate that semantic
+        * with dynamic initialization (they may have turned bits off that are
+        * set in RES_DEFAULT).  Our solution is to declare such applications
+        * "broken".  They could fool us by setting RES_INIT but none do (yet).
+        */
+       if (!_res.retrans)
+               _res.retrans = RES_TIMEOUT;
+       if (!_res.retry)
+               _res.retry = 4;
+       if (!(_res.options & RES_INIT))
+               _res.options = RES_DEFAULT;
+
+       /*
+        * This one used to initialize implicitly to zero, so unless the app
+        * has set it to something in particular, we can randomize it now.
+        */
+       if (!_res.id)
+               _res.id = res_randomid();
+
+       return (__res_vinit(&_res, 1));
+}
+
+/* We need a resolver context - in unthreaded apps, this weak function
+   provides it.  */
+
+struct __res_state *
+weak_const_function
+__res_state(void)
+{
+  return &_res;
+}