Use BIND's resolver in libc.
authorPeter Avalos <pavalos@theshell.com>
Sun, 21 Dec 2008 08:36:37 +0000 (03:36 -0500)
committerPeter Avalos <pavalos@theshell.com>
Sun, 28 Dec 2008 04:17:07 +0000 (23:17 -0500)
This also syncs some code from FreeBSD bringing along bug fixes and more
thread-safe routines.

Obtained-from: FreeBSD

87 files changed:
contrib/bind-9.3/lib/bind/include/isc/list.h
contrib/bind-9.3/lib/bind/inet/inet_addr.c
contrib/bind-9.3/lib/bind/inet/inet_cidr_pton.c
contrib/bind-9.3/lib/bind/inet/inet_lnaof.c
contrib/bind-9.3/lib/bind/inet/inet_makeaddr.c
contrib/bind-9.3/lib/bind/inet/inet_net_pton.c
contrib/bind-9.3/lib/bind/inet/inet_neta.c
contrib/bind-9.3/lib/bind/inet/inet_netof.c
contrib/bind-9.3/lib/bind/inet/inet_network.c
contrib/bind-9.3/lib/bind/inet/inet_ntoa.c
contrib/bind-9.3/lib/bind/inet/inet_ntop.c
contrib/bind-9.3/lib/bind/inet/inet_pton.c
contrib/bind-9.3/lib/bind/inet/nsap_addr.c
contrib/bind-9.3/lib/bind/isc/ev_streams.c
contrib/bind-9.3/lib/bind/isc/ev_timers.c
contrib/bind-9.3/lib/bind/isc/eventlib_p.h
contrib/bind-9.3/lib/bind/nameser/ns_print.c
contrib/bind-9.3/lib/bind/nameser/ns_samedomain.c
contrib/bind-9.3/lib/bind/resolv/herror.c
contrib/bind-9.3/lib/bind/resolv/mtctxres.c
contrib/bind-9.3/lib/bind/resolv/res_comp.c
contrib/bind-9.3/lib/bind/resolv/res_data.c
contrib/bind-9.3/lib/bind/resolv/res_debug.c
contrib/bind-9.3/lib/bind/resolv/res_findzonecut.c
contrib/bind-9.3/lib/bind/resolv/res_init.c
contrib/bind-9.3/lib/bind/resolv/res_mkquery.c
contrib/bind-9.3/lib/bind/resolv/res_mkupdate.c
contrib/bind-9.3/lib/bind/resolv/res_query.c
contrib/bind-9.3/lib/bind/resolv/res_send.c
contrib/bind-9.3/lib/bind/resolv/res_update.c
include/Makefile
include/arpa/inet.h
include/arpa/nameser.h
include/arpa/nameser_compat.h
include/netdb.h
include/res_update.h [new file with mode: 0644]
include/resolv.h
lib/libc/Makefile.inc
lib/libc/include/isc/platform.h [new file with mode: 0644]
lib/libc/include/port_after.h [new file with mode: 0644]
lib/libc/include/port_before.h [new file with mode: 0644]
lib/libc/net/Makefile.inc
lib/libc/net/gai_strerror.c [new file with mode: 0644]
lib/libc/net/getaddrinfo.3
lib/libc/net/getaddrinfo.c
lib/libc/net/gethostbydns.c
lib/libc/net/gethostbyht.c
lib/libc/net/gethostbyname.3
lib/libc/net/gethostbynis.c
lib/libc/net/gethostnamadr.c
lib/libc/net/getnameinfo.3
lib/libc/net/getnameinfo.c
lib/libc/net/getnetbydns.c
lib/libc/net/getnetbyht.c
lib/libc/net/getnetbynis.c
lib/libc/net/getnetnamadr.c
lib/libc/net/herror.c [deleted file]
lib/libc/net/inet_addr.c [deleted file]
lib/libc/net/inet_lnaof.c [deleted file]
lib/libc/net/inet_makeaddr.c [deleted file]
lib/libc/net/inet_net_ntop.c [deleted file]
lib/libc/net/inet_net_pton.c [deleted file]
lib/libc/net/inet_neta.c [deleted file]
lib/libc/net/inet_netof.c [deleted file]
lib/libc/net/inet_network.c [deleted file]
lib/libc/net/inet_ntop.c [deleted file]
lib/libc/net/inet_pton.c [deleted file]
lib/libc/net/name6.c
lib/libc/net/netdb_private.h
lib/libc/net/ns_name.c [deleted file]
lib/libc/net/ns_netint.c [deleted file]
lib/libc/net/ns_parse.c [deleted file]
lib/libc/net/ns_print.c [deleted file]
lib/libc/net/ns_ttl.c [deleted file]
lib/libc/net/res_comp.c [deleted file]
lib/libc/net/res_config.h
lib/libc/net/res_data.c [deleted file]
lib/libc/net/res_debug.c [deleted file]
lib/libc/net/res_init.c [deleted file]
lib/libc/net/res_mkquery.c [deleted file]
lib/libc/net/res_mkupdate.c [deleted file]
lib/libc/net/res_query.c [deleted file]
lib/libc/net/res_send.c [deleted file]
lib/libc/net/res_update.c [deleted file]
lib/libc/resolv/Makefile.inc [new file with mode: 0644]
lib/libc/resolv/h_errno.c [moved from lib/libc/net/inet_ntoa.c with 52% similarity]
lib/libc/resolv/res_state.c [new file with mode: 0644]

index 4e27eb1..f79617a 100644 (file)
 
 #ifndef LIST_H
 #define LIST_H 1
+#ifdef _LIBC
+#include <assert.h>
+#define INSIST(cond)   assert(cond)
+#else
 #include <isc/assertions.h>
+#endif
 
 #define LIST(type) struct { type *head, *tail; }
 #define INIT_LIST(list) \
index b967dc2..82bbe7e 100644 (file)
@@ -89,7 +89,7 @@ static const char rcsid[] = "$Id: inet_addr.c,v 1.2.206.2 2004/03/17 00:29:45 ma
  * Ascii internet address interpretation routine.
  * The value returned is in network order.
  */
-u_long
+in_addr_t
 inet_addr(const char *cp) {
        struct in_addr val;
 
@@ -204,3 +204,14 @@ inet_aton(const char *cp, struct in_addr *addr) {
                addr->s_addr = htonl(val);
        return (1);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_addr
+__weak_reference(__inet_addr, inet_addr);
+#undef inet_aton
+__weak_reference(__inet_aton, inet_aton);
+#endif
index 5bfef71..0341c38 100644 (file)
@@ -27,7 +27,12 @@ static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.2.2.1.8.2 2004/03/17 00:2
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 
+#ifdef _LIBC
+#include <assert.h>
+#define        INSIST(x)       assert(x)
+#else
 #include <isc/assertions.h>
+#endif
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
index 97b80cf..5666be3 100644 (file)
@@ -48,11 +48,11 @@ static const char sccsid[] = "@(#)inet_lnaof.c      8.1 (Berkeley) 6/4/93";
  * internet address; handles class a/b/c network
  * number formats.
  */
-u_long
+in_addr_t
 inet_lnaof(in)
        struct in_addr in;
 {
-       register u_long i = ntohl(in.s_addr);
+       in_addr_t i = ntohl(in.s_addr);
 
        if (IN_CLASSA(i))
                return ((i)&IN_CLASSA_HOST);
@@ -61,3 +61,12 @@ inet_lnaof(in)
        else
                return ((i)&IN_CLASSC_HOST);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_lnaof
+__weak_reference(__inet_lnaof, inet_lnaof);
+#endif
index 6e4ecc3..1b013a8 100644 (file)
@@ -49,7 +49,7 @@ static const char sccsid[] = "@(#)inet_makeaddr.c     8.1 (Berkeley) 6/4/93";
  */
 struct in_addr
 inet_makeaddr(net, host)
-       u_long net, host;
+       in_addr_t net, host;
 {
        struct in_addr a;
 
@@ -64,3 +64,12 @@ inet_makeaddr(net, host)
        a.s_addr = htonl(a.s_addr);
        return (a);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_makeaddr
+__weak_reference(__inet_makeaddr, inet_makeaddr);
+#endif
index abecfc7..06eb476 100644 (file)
@@ -27,7 +27,12 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.4.2.1.8.2 2004/03/17 00:29
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 
+#ifdef _LIBC
+#include <assert.h>
+#define INSIST(cond)   assert(cond)
+#else
 #include <isc/assertions.h>
+#endif
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
@@ -403,3 +408,12 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) {
                return (-1);
        }
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_net_pton
+__weak_reference(__inet_net_pton, inet_net_pton);
+#endif
index 325b7ce..f394122 100644 (file)
@@ -41,7 +41,7 @@ static const char rcsid[] = "$Id: inet_neta.c,v 1.1.206.1 2004/03/09 08:33:33 ma
 /*
  * char *
  * inet_neta(src, dst, size)
- *     format a u_long network number into presentation format.
+ *     format a in_addr_t network number into presentation format.
  * return:
  *     pointer to dst, or NULL if an error occurred (check errno).
  * note:
@@ -51,7 +51,7 @@ static const char rcsid[] = "$Id: inet_neta.c,v 1.1.206.1 2004/03/09 08:33:33 ma
  */
 char *
 inet_neta(src, dst, size)
-       u_long src;
+       in_addr_t src;
        char *dst;
        size_t size;
 {
@@ -85,3 +85,12 @@ inet_neta(src, dst, size)
        errno = EMSGSIZE;
        return (NULL);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_neta
+__weak_reference(__inet_neta, inet_neta);
+#endif
index e887530..faf4524 100644 (file)
@@ -47,11 +47,11 @@ static const char sccsid[] = "@(#)inet_netof.c      8.1 (Berkeley) 6/4/93";
  * Return the network number from an internet
  * address; handles class a/b/c network #'s.
  */
-u_long
+in_addr_t
 inet_netof(in)
        struct in_addr in;
 {
-       register u_long i = ntohl(in.s_addr);
+       in_addr_t i = ntohl(in.s_addr);
 
        if (IN_CLASSA(i))
                return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
@@ -60,3 +60,12 @@ inet_netof(in)
        else
                return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_netof
+__weak_reference(__inet_netof, inet_netof);
+#endif
index aaa50c8..f10558c 100644 (file)
@@ -49,14 +49,14 @@ static const char sccsid[] = "@(#)inet_network.c    8.1 (Berkeley) 6/4/93";
  * The library routines call this routine to interpret
  * network numbers.
  */
-u_long
+in_addr_t
 inet_network(cp)
-       register const char *cp;
+       const char *cp;
 {
-       register u_long val, base, n, i;
-       register char c;
-       u_long parts[4], *pp = parts;
-       int digit;
+       in_addr_t val, base, n;
+       char c;
+       in_addr_t parts[4], *pp = parts;
+       int i, digit;
 
 again:
        val = 0; base = 10; digit = 0;
@@ -102,3 +102,12 @@ again:
        }
        return (val);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_network
+__weak_reference(__inet_network, inet_network);
+#endif
index 7fad4b8..31d32a5 100644 (file)
@@ -60,3 +60,21 @@ inet_ntoa(struct in_addr in) {
        (void) inet_ntop(AF_INET, &in, ret, sizeof ret);
        return (ret);
 }
+
+#ifdef _LIBC
+char *
+inet_ntoa_r(struct in_addr in, char *buf, socklen_t size)
+{
+
+       inet_ntop(AF_INET, &in, buf, size);
+       return (buf);
+}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_ntoa
+__weak_reference(__inet_ntoa, inet_ntoa);
+__weak_reference(__inet_ntoa_r, inet_ntoa_r);
+#endif
index cd502ab..eefc521 100644 (file)
@@ -35,19 +35,13 @@ static const char rcsid[] = "$Id: inet_ntop.c,v 1.1.2.1.8.2 2005/11/03 23:08:40
 
 #include "port_after.h"
 
-#ifdef SPRINTF_CHAR
-# define SPRINTF(x) strlen(sprintf/**/x)
-#else
-# define SPRINTF(x) ((size_t)sprintf x)
-#endif
-
 /*
  * WARNING: Don't even consider trying to compile this on a system where
  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  */
 
-static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
-static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+static const char *inet_ntop4 __P((const u_char *src, char *dst, socklen_t size));
+static const char *inet_ntop6 __P((const u_char *src, char *dst, socklen_t size));
 
 /* char *
  * inet_ntop(af, src, dst, size)
@@ -60,9 +54,9 @@ static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
 const char *
 inet_ntop(af, src, dst, size)
        int af;
-       const void *src;
-       char *dst;
-       size_t size;
+       const void * __restrict src;
+       char * __restrict dst;
+       socklen_t size;
 {
        switch (af) {
        case AF_INET:
@@ -91,16 +85,18 @@ static const char *
 inet_ntop4(src, dst, size)
        const u_char *src;
        char *dst;
-       size_t size;
+       socklen_t size;
 {
        static const char fmt[] = "%u.%u.%u.%u";
        char tmp[sizeof "255.255.255.255"];
+       int l;
 
-       if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+       l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+       if (l <= 0 || (socklen_t) l >= size) {
                errno = ENOSPC;
                return (NULL);
        }
-       strcpy(dst, tmp);
+       strlcpy(dst, tmp, size);
        return (dst);
 }
 
@@ -114,7 +110,7 @@ static const char *
 inet_ntop6(src, dst, size)
        const u_char *src;
        char *dst;
-       size_t size;
+       socklen_t size;
 {
        /*
         * Note that int32_t and int16_t need only be "at least" large enough
@@ -185,7 +181,7 @@ inet_ntop6(src, dst, size)
                        tp += strlen(tp);
                        break;
                }
-               tp += SPRINTF((tp, "%x", words[i]));
+               tp += sprintf(tp, "%x", words[i]);
        }
        /* Was it a trailing run of 0x00's? */
        if (best.base != -1 && (best.base + best.len) == 
@@ -196,10 +192,19 @@ inet_ntop6(src, dst, size)
        /*
         * Check for overflow, copy, and we're done.
         */
-       if ((size_t)(tp - tmp) > size) {
+       if ((socklen_t)(tp - tmp) > size) {
                errno = ENOSPC;
                return (NULL);
        }
        strcpy(dst, tmp);
        return (dst);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_net_ntop
+__weak_reference(__inet_net_ntop, inet_net_ntop);
+#endif
index f18a7b6..c1aa9b2 100644 (file)
@@ -52,8 +52,8 @@ static int    inet_pton6 __P((const char *src, u_char *dst));
 int
 inet_pton(af, src, dst)
        int af;
-       const char *src;
-       void *dst;
+       const char * __restrict src;
+       void * __restrict dst;
 {
        switch (af) {
        case AF_INET:
@@ -219,3 +219,12 @@ inet_pton6(src, dst)
        memcpy(dst, tmp, NS_IN6ADDRSZ);
        return (1);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_pton
+__weak_reference(__inet_pton, inet_pton);
+#endif
index a4b98e7..eacd733 100644 (file)
@@ -107,3 +107,14 @@ inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
        *ascii = '\0';
        return (start);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <arpa/inet.h>.
+ */
+#undef inet_nsap_addr
+__weak_reference(__inet_nsap_addr, inet_nsap_addr);
+#undef inet_nsap_ntoa
+__weak_reference(__inet_nsap_ntoa, inet_nsap_ntoa);
+#endif
index 64e88b0..fdac9b8 100644 (file)
@@ -24,24 +24,30 @@ static const char rcsid[] = "$Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 m
 #endif
 
 #include "port_before.h"
+#ifndef _LIBC
 #include "fd_setsize.h"
+#endif
 
 #include <sys/types.h>
 #include <sys/uio.h>
 
 #include <errno.h>
 
-#include <isc/eventlib.h>
+#include "isc/eventlib.h"
+#ifndef _LIBC
 #include <isc/assertions.h>
+#endif
 #include "eventlib_p.h"
 
 #include "port_after.h"
 
+#ifndef _LIBC
 static int     copyvec(evStream *str, const struct iovec *iov, int iocnt);
 static void    consume(evStream *str, size_t bytes);
 static void    done(evContext opaqueCtx, evStream *str);
 static void    writable(evContext opaqueCtx, void *uap, int fd, int evmask);
 static void    readable(evContext opaqueCtx, void *uap, int fd, int evmask);
+#endif
 
 struct iovec
 evConsIovec(void *buf, size_t cnt) {
@@ -53,6 +59,7 @@ evConsIovec(void *buf, size_t cnt) {
        return (ret);
 }
 
+#ifndef _LIBC
 int
 evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
        evStreamFunc func, void *uap, evStreamID *id)
@@ -304,3 +311,4 @@ readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
        if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
                done(opaqueCtx, str);
 }
+#endif /* !_LIBC */
index 11433fb..b6df4e3 100644 (file)
@@ -26,12 +26,16 @@ static const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13
 /* Import. */
 
 #include "port_before.h"
+#ifndef _LIBC
 #include "fd_setsize.h"
+#endif
 
 #include <errno.h>
 
+#ifndef _LIBC
 #include <isc/assertions.h>
-#include <isc/eventlib.h>
+#endif
+#include "isc/eventlib.h"
 #include "eventlib_p.h"
 
 #include "port_after.h"
@@ -43,6 +47,9 @@ static const char rcsid[] = "$Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13
 
 /* Forward. */
 
+#ifdef _LIBC
+static int     __evOptMonoTime;
+#else
 static int due_sooner(void *, void *);
 static void set_index(void *, int);
 static void free_timer(void *, void *);
@@ -58,7 +65,7 @@ typedef struct {
        struct timespec max_idle;
        evTimer *       timer;
 } idle_timer;
-
+#endif
 /* Public. */
 
 struct timespec
@@ -138,12 +145,14 @@ evUTCTime() {
        return (evTimeSpec(now));
 }
 
+#ifndef _LIBC
 struct timespec
 evLastEventTime(evContext opaqueCtx) {
        evContext_p *ctx = opaqueCtx.opaque;
 
        return (ctx->lastEventTime);
 }
+#endif
 
 struct timespec
 evTimeSpec(struct timeval tv) {
@@ -154,6 +163,7 @@ evTimeSpec(struct timeval tv) {
        return (ts);
 }
 
+#if !defined(USE_KQUEUE) || !defined(_LIBC)
 struct timeval
 evTimeVal(struct timespec ts) {
        struct timeval tv;
@@ -162,7 +172,9 @@ evTimeVal(struct timespec ts) {
        tv.tv_usec = ts.tv_nsec / 1000;
        return (tv);
 }
+#endif
 
+#ifndef _LIBC
 int
 evSetTimer(evContext opaqueCtx,
           evTimerFunc func,
@@ -495,3 +507,4 @@ idle_timeout(evContext opaqueCtx,
                this->timer->inter = evSubTime(this->max_idle, idle);
        }
 }
+#endif /* !_LIBC */
index 5c45ab8..bf47784 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#ifndef _LIBC
 #include <isc/heap.h>
 #include <isc/list.h>
 #include <isc/memcluster.h>
+#endif
 
 #define        EV_MASK_ALL     (EV_READ | EV_WRITE | EV_EXCEPT)
 #define EV_ERR(e)              return (errno = (e), -1)
@@ -85,6 +87,7 @@ typedef struct evConn {
        struct evConn * next;
 } evConn;
 
+#ifndef _LIBC
 typedef struct evAccept {
        int             fd;
        union {
@@ -174,6 +177,7 @@ typedef struct evEvent_p {
                struct {  const void *placeholder;  }           null;
        } u;
 } evEvent_p;
+#endif /* !_LIBC */
 
 #ifdef USE_POLL
 typedef struct { 
@@ -209,6 +213,7 @@ extern void         __fd_set(int fd, __evEmulMask *maskp);
 
 #endif /* USE_POLL */
 
+#ifndef _LIBC
 typedef struct {
        /* Global. */
        const evEvent_p *cur;
@@ -273,8 +278,11 @@ void evDestroyTimers(const evContext_p *);
 /* ev_waits.c */
 #define evFreeWait __evFreeWait
 evWait *evFreeWait(evContext_p *ctx, evWait *old);
+#endif /* !_LIBC */
 
 /* Global options */
+#ifndef _LIBC
 extern int     __evOptMonoTime;
+#endif /* !_LIBC */
 
 #endif /*_EVENTLIB_P_H*/
index cb61cb1..0ee3a2d 100644 (file)
@@ -30,8 +30,13 @@ static const char rcsid[] = "$Id: ns_print.c,v 1.3.2.1.4.7 2004/09/16 07:01:12 m
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 
+#ifdef _LIBC
+#include <assert.h>
+#define INSIST(cond)   assert(cond)
+#else
 #include <isc/assertions.h>
 #include <isc/dst.h>
+#endif
 #include <errno.h>
 #include <resolv.h>
 #include <string.h>
@@ -457,7 +462,11 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
                        goto formerr;
 
                /* Key flags, Protocol, Algorithm. */
+#ifndef _LIBC
                key_id = dst_s_dns_key_id(rdata, edata-rdata);
+#else
+               key_id = 0;
+#endif
                keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
                protocol = *rdata++;
                algorithm = *rdata++;
index d4ca550..a5d039e 100644 (file)
@@ -140,6 +140,7 @@ ns_samedomain(const char *a, const char *b) {
        return (strncasecmp(cp, b, lb) == 0);
 }
 
+#ifndef _LIBC
 /*
  * int
  * ns_subdomain(a, b)
@@ -149,6 +150,7 @@ int
 ns_subdomain(const char *a, const char *b) {
        return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
 }
+#endif
 
 /*
  * int
index 58807e9..c5266b0 100644 (file)
@@ -55,6 +55,10 @@ static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka
 
 #include "port_before.h"
 
+#ifdef _LIBC
+#include "namespace.h"
+#endif
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/uio.h>
@@ -66,7 +70,11 @@ static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka
 #include <resolv.h>
 #include <string.h>
 #include <unistd.h>
+#ifndef _LIBC
 #include <irs.h>
+#else
+#include "un-namespace.h"
+#endif
 
 #include "port_after.h"
 
@@ -110,7 +118,11 @@ herror(const char *s) {
        DE_CONST("\n", t);
        v->iov_base = t;
        v->iov_len = 1;
+#ifndef _LIBC
        writev(STDERR_FILENO, iov, (v - iov) + 1);
+#else
+       _writev(STDERR_FILENO, iov, (v - iov) + 1);
+#endif
 }
 
 /*
index 635bbd4..e9dd65d 100644 (file)
@@ -1,13 +1,18 @@
 #include <port_before.h>
 #ifdef DO_PTHREADS
 #include <pthread.h>
+#ifdef _LIBC
+#include <pthread_np.h>
+#endif
 #endif
 #include <errno.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <string.h>
-#include <resolv_mt.h>
+#include "resolv_mt.h"
+#ifndef _LIBC
 #include <irs.h>
+#endif
 #include <port_after.h>
 
 #ifdef DO_PTHREADS
@@ -40,6 +45,7 @@ _mtctxres_init(void) {
 }
 #endif
 
+#ifndef _LIBC
 /*
  * To support binaries that used the private MT-safe interface in
  * Solaris 8, we still need to provide the __res_enable_mt()
@@ -49,6 +55,7 @@ int
 __res_enable_mt(void) {
        return (-1);
 }
+#endif
 
 int
 __res_disable_mt(void) {
@@ -99,6 +106,11 @@ ___mtctxres(void) {
 #ifdef DO_PTHREADS
        mtctxres_t      *mt;
 
+#ifdef _LIBC
+       if (pthread_main_np() != 0)
+               return (&sharedctx);
+#endif
+
        /*
         * This if clause should only be executed if we are linking
         * statically.  When linked dynamically _mtctxres_init() should
index 8cc99a7..9daed6f 100644 (file)
@@ -261,3 +261,14 @@ u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
 u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
 #endif /*__ultrix__*/
 #endif /*BIND_4_COMPAT*/
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef dn_comp
+__weak_reference(__dn_comp, dn_comp);
+#undef dn_expand
+__weak_reference(__dn_expand, dn_expand);
+#endif
index 204e03d..1917dd0 100644 (file)
@@ -40,7 +40,9 @@ static const char rcsid[] = "$Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 mar
 #include <unistd.h>
 
 #include "port_after.h"
+#ifndef _LIBC
 #undef _res
+#endif
 
 const char *_res_opcodes[] = {
        "QUERY",
@@ -71,11 +73,13 @@ const char *_res_sectioncodes[] = {
 #endif
 
 #ifndef __BIND_NOSTATIC
+#ifndef _LIBC
 struct __res_state _res
 # if defined(__BIND_RES_TEXT)
        = { RES_TIMEOUT, }      /* Motorola, et al. */
 # endif
         ;
+#endif /* !_LIBC */
 
 /* Proto. */
 
@@ -107,7 +111,11 @@ res_init(void) {
        if (!_res.retrans)
                _res.retrans = RES_TIMEOUT;
        if (!_res.retry)
+#ifndef _LIBC
                _res.retry = 4;
+#else
+               _res.retry = RES_DFLRETRY;
+#endif
        if (!(_res.options & RES_INIT))
                _res.options = RES_DEFAULT;
 
@@ -181,6 +189,7 @@ res_query(const char *name, /* domain name */
        return (res_nquery(&_res, name, class, type, answer, anslen));
 }
 
+#ifndef _LIBC
 void
 res_send_setqhook(res_send_qhook hook) {
        _res.qhook = hook;
@@ -190,6 +199,7 @@ void
 res_send_setrhook(res_send_rhook hook) {
        _res.rhook = hook;
 }
+#endif
 
 int
 res_isourserver(const struct sockaddr_in *inp) {
@@ -206,6 +216,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
        return (res_nsend(&_res, buf, buflen, ans, anssiz));
 }
 
+#ifndef _LIBC
 int
 res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
               u_char *ans, int anssiz)
@@ -217,6 +228,7 @@ res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
 
        return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
 }
+#endif
 
 void
 res_close(void) {
@@ -264,6 +276,14 @@ res_querydomain(const char *name,
                                 answer, anslen));
 }
 
+#ifdef _LIBC
+int
+res_opt(int n0, u_char *buf, int buflen, int anslen)
+{
+       return (res_nopt(&_res, n0, buf, buflen, anslen));
+}
+#endif
+
 const char *
 hostalias(const char *name) {
        static char abuf[MAXDNAME];
@@ -288,4 +308,27 @@ local_hostname_length(const char *hostname) {
 }
 #endif /*ultrix*/
 
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef res_init
+__weak_reference(__res_init, res_init);
+#undef p_query
+__weak_reference(__p_query, p_query);
+#undef res_mkquery
+__weak_reference(__res_mkquery, res_mkquery);
+#undef res_query
+__weak_reference(__res_query, res_query);
+#undef res_send
+__weak_reference(__res_send, res_send);
+#undef res_close
+__weak_reference(__res_close, _res_close);
+#undef res_search
+__weak_reference(__res_search, res_search);
+#undef res_querydomain
+__weak_reference(__res_querydomain, res_querydomain);
+#endif
+
 #endif
index 8dda12c..eaae7a2 100644 (file)
@@ -113,7 +113,7 @@ static const char rcsid[] = "$Id: res_debug.c,v 1.3.2.5.4.6 2005/07/28 07:43:22
 #include <math.h>
 #include <netdb.h>
 #include <resolv.h>
-#include <resolv_mt.h>
+#include "resolv_mt.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -375,7 +375,7 @@ const struct res_sym __p_class_syms[] = {
 /*
  * Names of message sections.
  */
-const struct res_sym __p_default_section_syms[] = {
+static const struct res_sym __p_default_section_syms[] = {
        {ns_s_qd,       "QUERY",        (char *)0},
        {ns_s_an,       "ANSWER",       (char *)0},
        {ns_s_ns,       "AUTHORITY",    (char *)0},
@@ -383,7 +383,7 @@ const struct res_sym __p_default_section_syms[] = {
        {0,             (char *)0,      (char *)0}
 };
 
-const struct res_sym __p_update_section_syms[] = {
+static const struct res_sym __p_update_section_syms[] = {
        {S_ZONE,        "ZONE",         (char *)0},
        {S_PREREQ,      "PREREQUISITE", (char *)0},
        {S_UPDATE,      "UPDATE",       (char *)0},
@@ -1161,3 +1161,24 @@ res_nametotype(const char *buf, int *successp) {
                *successp = success;
        return (result);
 }
+
+#ifdef _LIBC
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef fp_resstat
+__weak_reference(__fp_resstat, fp_resstat);
+#undef p_fqnname
+__weak_reference(__p_fqnname, p_fqnname);
+#undef sym_ston
+__weak_reference(__sym_ston, sym_ston);
+#undef sym_ntos
+__weak_reference(__sym_ntos, sym_ntos);
+#undef sym_ntop
+__weak_reference(__sym_ntop, sym_ntop);
+#undef dn_count_labels
+__weak_reference(__dn_count_labels, dn_count_labels);
+#undef p_secstodate
+__weak_reference(__p_secstodate, p_secstodate);
+#endif
index 804beb6..e8c18f9 100644 (file)
@@ -39,7 +39,7 @@ static const char rcsid[] = "$Id: res_findzonecut.c,v 1.2.2.3.4.4 2005/10/11 00:
 #include <stdlib.h>
 #include <string.h>
 
-#include <isc/list.h>
+#include "isc/list.h"
 
 #include "port_after.h"
 
@@ -149,6 +149,7 @@ static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
  *     keep going.  for the NS and A queries this means we just give up.
  */
 
+#ifndef _LIBC
 int
 res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
                char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
@@ -173,6 +174,7 @@ res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
        free(u);
        return (result);
 }
+#endif
 
 int
 res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
index fd82e87..004d459 100644 (file)
@@ -75,6 +75,9 @@ static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.6 2006/08/30 23:23:01 m
 
 #include "port_before.h"
 
+#ifdef _LIBC
+#include "namespace.h"
+#endif
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -90,7 +93,9 @@ static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.6 2006/08/30 23:23:01 m
 #include <string.h>
 #include <unistd.h>
 #include <netdb.h>
-
+#ifdef _LIBC
+#include "un-namespace.h"
+#endif
 #include "port_after.h"
 
 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
@@ -246,7 +251,7 @@ __res_vinit(res_state statp, int preinit) {
 #endif /* SOLARIS2 */
 
        /* Allow user to override the local domain definition */
-       if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+       if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
                (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
                statp->defdname[sizeof(statp->defdname) - 1] = '\0';
                haveenv++;
@@ -383,6 +388,10 @@ __res_vinit(res_state statp, int preinit) {
 #ifdef RESOLVSORT
                if (MATCH(buf, "sortlist")) {
                    struct in_addr a;
+                   struct in6_addr a6;
+                   int m, i;
+                   u_char *u;
+                   struct __res_state_ext *ext = statp->_u._ext.ext;
 
                    cp = buf + sizeof("sortlist") - 1;
                    while (nsort < MAXRESOLVSORT) {
@@ -417,6 +426,57 @@ __res_vinit(res_state statp, int preinit) {
                                statp->sort_list[nsort].mask = 
                                    net_mask(statp->sort_list[nsort].addr);
                            }
+                           ext->sort_list[nsort].af = AF_INET;
+                           ext->sort_list[nsort].addr.ina =
+                               statp->sort_list[nsort].addr;
+                           ext->sort_list[nsort].mask.ina.s_addr =
+                               statp->sort_list[nsort].mask;
+                           nsort++;
+                       }
+                       else if (inet_pton(AF_INET6, net, &a6) == 1) {
+
+                           ext->sort_list[nsort].af = AF_INET6;
+                           ext->sort_list[nsort].addr.in6a = a6;
+                           u = (u_char *)&ext->sort_list[nsort].mask.in6a;
+                           *cp++ = n;
+                           net = cp;
+                           while (*cp && *cp != ';' &&
+                                   isascii(*cp) && !isspace(*cp))
+                               cp++;
+                           m = n;
+                           n = *cp;
+                           *cp = 0;
+                           switch (m) {
+                           case '/':
+                               m = atoi(net);
+                               break;
+                           case '&':
+                               if (inet_pton(AF_INET6, net, u) == 1) {
+                                   m = -1;
+                                   break;
+                               }
+                               /*FALLTHROUGH*/
+                           default:
+                               m = sizeof(struct in6_addr) * CHAR_BIT;
+                               break;
+                           }
+                           if (m >= 0) {
+                               for (i = 0; i < sizeof(struct in6_addr); i++) {
+                                   if (m <= 0) {
+                                       *u = 0;
+                                   } else {
+                                       m -= CHAR_BIT;
+                                       *u = (u_char)~0;
+                                       if (m < 0)
+                                           *u <<= -m;
+                                   }
+                                   u++;
+                               }
+                           }
+                           statp->sort_list[nsort].addr.s_addr =
+                               (u_int32_t)0xffffffff;
+                           statp->sort_list[nsort].mask =
+                               (u_int32_t)0xffffffff;
                            nsort++;
                        }
                        *cp = n;
@@ -479,7 +539,9 @@ __res_vinit(res_state statp, int preinit) {
 #endif
        }
 
-       if ((cp = getenv("RES_OPTIONS")) != NULL)
+       if (issetugid())
+               statp->options |= RES_NOALIASES;
+       else if ((cp = getenv("RES_OPTIONS")) != NULL)
                res_setoptions(statp, cp, "env");
        statp->options |= RES_INIT;
        return (0);
@@ -499,7 +561,9 @@ res_setoptions(res_state statp, const char *options, const char *source)
 {
        const char *cp = options;
        int i;
+#ifndef _LIBC
        struct __res_state_ext *ext = statp->_u._ext.ext;
+#endif
 
 #ifdef DEBUG
        if (statp->options & RES_DEBUG)
@@ -573,6 +637,10 @@ res_setoptions(res_state statp, const char *options, const char *source)
                        statp->options |= RES_NOTLDQUERY;
                } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
                        statp->options |= RES_USE_INET6;
+               } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
+                      statp->options |= RES_INSECURE1;
+               } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
+                      statp->options |= RES_INSECURE2;
                } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
                        statp->options |= RES_ROTATE;
                } else if (!strncmp(cp, "no-check-names",
@@ -584,6 +652,7 @@ res_setoptions(res_state statp, const char *options, const char *source)
                        statp->options |= RES_USE_EDNS0;
                }
 #endif
+#ifndef _LIBC
                else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
                        statp->options |= RES_USE_DNAME;
                }
@@ -613,10 +682,13 @@ res_setoptions(res_state statp, const char *options, const char *source)
                                         ~RES_NO_NIBBLE2;
                        }
                }
+#endif
                else {
                        /* XXX - print a warning here? */
                }
+#ifndef _LIBC
    skip:
+#endif
                /* skip to next run of spaces */
                while (*cp && *cp != ' ' && *cp != '\t')
                        cp++;
@@ -659,13 +731,21 @@ res_nclose(res_state statp) {
        int ns;
 
        if (statp->_vcsock >= 0) { 
+#ifndef _LIBC
                (void) close(statp->_vcsock);
+#else
+               _close(statp->_vcsock);
+#endif
                statp->_vcsock = -1;
                statp->_flags &= ~(RES_F_VC | RES_F_CONN);
        }
        for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
                if (statp->_u._ext.nssocks[ns] != -1) {
+#ifndef _LIBC
                        (void) close(statp->_u._ext.nssocks[ns]);
+#else
+                       _close(statp->_u._ext.nssocks[ns]);
+#endif
                        statp->_u._ext.nssocks[ns] = -1;
                }
        }
@@ -680,6 +760,7 @@ res_ndestroy(res_state statp) {
        statp->_u._ext.ext = NULL;
 }
 
+#ifndef _LIBC
 const char *
 res_get_nibblesuffix(res_state statp) {
        if (statp->_u._ext.ext)
@@ -693,6 +774,7 @@ res_get_nibblesuffix2(res_state statp) {
                return (statp->_u._ext.ext->nsuffix2);
        return ("ip6.int");
 }
+#endif
 
 void
 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
index 89000ed..8d888e7 100644 (file)
@@ -234,6 +234,8 @@ res_nopt(res_state statp,
 
        ns_put16(T_OPT, cp);    /* TYPE */
        cp += INT16SZ;
+       if (anslen > 0xffff)
+               anslen = 0xffff;                /* limit to 16bit value */
        ns_put16(anslen & 0xffff, cp);  /* CLASS = UDP payload size */
        cp += INT16SZ;
        *cp++ = NOERROR;        /* extended RCODE */
index 01078f1..a135bf0 100644 (file)
@@ -44,6 +44,9 @@ static const char rcsid[] = "$Id: res_mkupdate.c,v 1.1.2.1.4.5 2005/10/14 05:43:
 #include <unistd.h>
 #include <ctype.h>
 
+#ifdef _LIBC
+#include "isc/list.h"
+#endif
 #include "port_after.h"
 
 /* Options.  Leave them on. */
@@ -58,8 +61,13 @@ static int getstr_str(char *, int, u_char **, u_char *);
 #define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
 
 /* Forward. */
-
+#ifdef _LIBC
+static
+#endif
 int res_protocolnumber(const char *);
+#ifdef _LIBC
+static
+#endif
 int res_servicenumber(const char *);
 
 /*
@@ -89,7 +97,10 @@ res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
        u_int16_t rtype, rclass;
        u_int32_t n1, rttl;
        u_char *dnptrs[20], **dpp, **lastdnptr;
-       int siglen, keylen, certlen;
+#ifndef _LIBC
+       int siglen;
+#endif
+       int keylen, certlen;
 
        /*
         * Initialize header fields.
@@ -445,6 +456,9 @@ res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
                                return (-1);
                        break;
                case ns_t_sig:
+#ifdef _LIBC
+                       return (-1);
+#else
                    {
                        int sig_type, success, dateerror;
                        u_int32_t exptime, timesigned;
@@ -535,6 +549,7 @@ res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
                        cp += siglen;
                        break;
                    }
+#endif
                case ns_t_key:
                        /* flags */
                        n = gethexnum_str(&startp, endp);
@@ -980,6 +995,7 @@ res_buildservicelist() {
        endservent();
 }
 
+#ifndef _LIBC
 void
 res_destroyservicelist() {
        struct valuelist *slp, *slp_next;
@@ -992,6 +1008,7 @@ res_destroyservicelist() {
        }
        servicelist = (struct valuelist *)0;
 }
+#endif
 
 void
 res_buildprotolist(void) {
@@ -1022,6 +1039,7 @@ res_buildprotolist(void) {
        endprotoent();
 }
 
+#ifndef _LIBC
 void
 res_destroyprotolist(void) {
        struct valuelist *plp, *plp_next;
@@ -1033,6 +1051,7 @@ res_destroyprotolist(void) {
        }
        protolist = (struct valuelist *)0;
 }
+#endif
 
 static int
 findservice(const char *s, struct valuelist **list) {
@@ -1059,6 +1078,9 @@ findservice(const char *s, struct valuelist **list) {
 /*
  * Convert service name or (ascii) number to int.
  */
+#ifdef _LIBC
+static
+#endif
 int
 res_servicenumber(const char *p) {
        if (servicelist == (struct valuelist *)0)
@@ -1069,6 +1091,9 @@ res_servicenumber(const char *p) {
 /*
  * Convert protocol name or (ascii) number to int.
  */
+#ifdef _LIBC
+static
+#endif
 int
 res_protocolnumber(const char *p) {
        if (protolist == (struct valuelist *)0)
@@ -1076,6 +1101,7 @@ res_protocolnumber(const char *p) {
        return (findservice(p, &protolist));
 }
 
+#ifndef _LIBC
 static struct servent *
 cgetservbyport(u_int16_t port, const char *proto) {    /* Host byte order. */
        struct valuelist **list = &servicelist;
@@ -1156,3 +1182,4 @@ res_servicename(u_int16_t port, const char *proto) {      /* Host byte order. */
        }
        return (ss->s_name);
 }
+#endif
index 5156ce8..62e953e 100644 (file)
@@ -86,6 +86,7 @@ static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include "port_after.h"
 
 /* Options.  Leave them on. */
@@ -242,6 +243,21 @@ res_nsearch(res_state statp,
                                         answer, anslen);
                if (ret > 0 || trailing_dot)
                        return (ret);
+               if (errno == ECONNREFUSED) {
+                       RES_SET_H_ERRNO(statp, TRY_AGAIN);
+                       return (-1);
+               }
+               switch (statp->res_h_errno) {
+               case NO_DATA:
+               case HOST_NOT_FOUND:
+                       break;
+               case TRY_AGAIN:
+                       if (hp->rcode == SERVFAIL)
+                               break;
+                       /* FALLTHROUGH */
+               default:
+                       return (-1);
+               }
                saved_herrno = statp->res_h_errno;
                tried_as_is++;
        }
@@ -265,6 +281,9 @@ res_nsearch(res_state statp,
                            (domain[0][0] == '.' && domain[0][1] == '\0'))
                                root_on_list++;
 
+                       if (root_on_list && tried_as_is)
+                               continue;
+
                        ret = res_nquerydomain(statp, name, *domain,
                                               class, type,
                                               answer, anslen);
@@ -297,9 +316,26 @@ res_nsearch(res_state statp,
                                /* keep trying */
                                break;
                        case TRY_AGAIN:
+                               /*
+                                * This can occur due to a server failure
+                                * (that is, all listed servers have failed),
+                                * or all listed servers have timed out.
+                                * ((HEADER *)answer)->rcode may not be set
+                                * to SERVFAIL in the case of a timeout.
+                                *
+                                * Either way we must return TRY_AGAIN in
+                                * order to avoid non-deterministic
+                                * return codes.
+                                * For example, loaded name servers or races
+                                * against network startup/validation (dhcp,
+                                * ppp, etc) can cause the search to timeout
+                                * on one search element, e.g. 'fu.bar.com',
+                                * and return a definitive failure on the
+                                * next search element, e.g. 'fu.'.
+                                */
+                               got_servfail++;
                                if (hp->rcode == SERVFAIL) {
                                        /* try next search element, if any */
-                                       got_servfail++;
                                        break;
                                }
                                /* FALLTHROUGH */
@@ -316,6 +352,18 @@ res_nsearch(res_state statp,
                }
        }
 
+       switch (statp->res_h_errno) {
+       case NO_DATA:
+       case HOST_NOT_FOUND:
+               break;
+       case TRY_AGAIN:
+               if (hp->rcode == SERVFAIL)
+                       break;
+               /* FALLTHROUGH */
+       default:
+               goto giveup;
+       }
+
        /*
         * If the query has not already been tried as is then try it
         * unless RES_NOTLDQUERY is set and there were no dots.
@@ -335,6 +383,7 @@ res_nsearch(res_state statp,
         * else send back meaningless H_ERRNO, that being the one from
         * the last DNSRCH we did.
         */
+giveup:
        if (saved_herrno != -1)
                RES_SET_H_ERRNO(statp, saved_herrno);
        else if (got_nodata)
@@ -401,6 +450,8 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
 
        if (statp->options & RES_NOALIASES)
                return (NULL);
+       if (issetugid())
+               return (NULL);
        file = getenv("HOSTALIASES");
        if (file == NULL || (fp = fopen(file, "r")) == NULL)
                return (NULL);
index c47dd49..08abfe0 100644 (file)
@@ -78,8 +78,13 @@ static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 m
  */
 
 #include "port_before.h"
+#ifndef USE_KQUEUE
 #include "fd_setsize.h"
+#endif
 
+#ifdef _LIBC
+#include "namespace.h"
+#endif
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
@@ -99,16 +104,23 @@ static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 m
 #include <string.h>
 #include <unistd.h>
 
-#include <isc/eventlib.h>
+#include "isc/eventlib.h"
 
 #include "port_after.h"
-
+#ifdef USE_KQUEUE
+#include <sys/event.h>
+#else
 #ifdef USE_POLL
 #ifdef HAVE_STROPTS_H
 #include <stropts.h>
 #endif
 #include <poll.h>
 #endif /* USE_POLL */
+#endif
+
+#ifdef _LIBC
+#include "un-namespace.h"
+#endif
 
 /* Options.  Leave them on. */
 #define DEBUG
@@ -117,10 +129,8 @@ static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 m
 
 #define EXT(res) ((res)->_u._ext)
 
-#ifndef USE_POLL
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
 static const int highestFD = FD_SETSIZE - 1;
-#else
-static int highestFD = 0;
 #endif
 
 /* Forward. */
@@ -129,14 +139,18 @@ static int                get_salen __P((const struct sockaddr *));
 static struct sockaddr * get_nsaddr __P((res_state, size_t));
 static int             send_vc(res_state, const u_char *, int,
                                u_char *, int, int *, int);
-static int             send_dg(res_state, const u_char *, int,
+static int             send_dg(res_state,
+#ifdef USE_KQUEUE
+                               int,
+#endif
+                               const u_char *, int,
                                u_char *, int, int *, int, int,
                                int *, int *);
 static void            Aerror(const res_state, FILE *, const char *, int,
                               const struct sockaddr *, int);
 static void            Perror(const res_state, FILE *, const char *, int);
 static int             sock_eq(struct sockaddr *, struct sockaddr *);
-#if defined(NEED_PSELECT) && !defined(USE_POLL)
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
 static int             pselect(int, void *, void *, void *,
                                struct timespec *,
                                const sigset_t *);
@@ -289,11 +303,10 @@ res_nsend(res_state statp,
          const u_char *buf, int buflen, u_char *ans, int anssiz)
 {
        int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
-       char abuf[NI_MAXHOST];
-
-#ifdef USE_POLL
-       highestFD = sysconf(_SC_OPEN_MAX) - 1;
+#ifdef USE_KQUEUE
+       int kq;
 #endif
+       char abuf[NI_MAXHOST];
 
        /* No name servers or res_init() failure */
        if (statp->nscount == 0 || EXT(statp).ext == NULL) {
@@ -310,6 +323,13 @@ res_nsend(res_state statp,
        gotsomewhere = 0;
        terrno = ETIMEDOUT;
 
+#ifdef USE_KQUEUE
+       if ((kq = kqueue()) < 0) {
+               Perror(statp, stderr, "kqueue", errno);
+               return (-1);
+       }
+#endif
+
        /*
         * If the ns_addr_list in the resolver context has changed, then
         * invalidate our cached copy and the associated timing data.
@@ -333,7 +353,11 @@ res_nsend(res_state statp,
                                if (EXT(statp).nssocks[ns] == -1)
                                        continue;
                                peerlen = sizeof(peer);
+#ifndef _LIBC
                                if (getsockname(EXT(statp).nssocks[ns],
+#else
+                               if (_getsockname(EXT(statp).nssocks[ns],
+#endif
                                    (struct sockaddr *)&peer, &peerlen) < 0) {
                                        needclose++;
                                        break;
@@ -425,6 +449,9 @@ res_nsend(res_state statp,
                                        res_nclose(statp);
                                        goto next_ns;
                                case res_done:
+#ifdef USE_KQUEUE
+                                       _close(kq);
+#endif
                                        return (resplen);
                                case res_modified:
                                        /* give the hook another try */
@@ -458,7 +485,11 @@ res_nsend(res_state statp,
                        resplen = n;
                } else {
                        /* Use datagrams. */
-                       n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+                       n = send_dg(statp,
+#ifdef USE_KQUEUE
+                                   kq,
+#endif
+                                   buf, buflen, ans, anssiz, &terrno,
                                    ns, try, &v_circuit, &gotsomewhere);
                        if (n < 0)
                                goto fail;
@@ -517,11 +548,17 @@ res_nsend(res_state statp,
                        } while (!done);
 
                }
+#ifdef USE_KQUEUE
+               _close(kq);
+#endif
                return (resplen);
  next_ns: ;
           } /*foreach ns*/
        } /*foreach retry*/
        res_nclose(statp);
+#ifdef USE_KQUEUE
+       _close(kq);
+#endif
        if (!v_circuit) {
                if (!gotsomewhere)
                        errno = ECONNREFUSED;   /* no nameservers found */
@@ -609,7 +646,11 @@ send_vc(res_state statp,
                struct sockaddr_storage peer;
                ISC_SOCKLEN_T size = sizeof peer;
 
+#ifndef _LIBC
                if (getpeername(statp->_vcsock,
+#else
+               if (_getpeername(statp->_vcsock,
+#endif
                                (struct sockaddr *)&peer, &size) < 0 ||
                    !sock_eq((struct sockaddr *)&peer, nsap)) {
                        res_nclose(statp);
@@ -621,11 +662,17 @@ send_vc(res_state statp,
                if (statp->_vcsock >= 0)
                        res_nclose(statp);
 
+#ifndef _LIBC
                statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+#else
+               statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0);
+#endif
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
                if (statp->_vcsock > highestFD) {
                        res_nclose(statp);
                        errno = ENOTSOCK;
                }
+#endif
                if (statp->_vcsock < 0) {
                        switch (errno) {
                        case EPROTONOSUPPORT:
@@ -642,7 +689,11 @@ send_vc(res_state statp,
                        }
                }
                errno = 0;
+#ifndef _LIBC
                if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+#else
+               if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
+#endif
                        *terrno = errno;
                        Aerror(statp, stderr, "connect/vc", errno, nsap,
                            nsaplen);
@@ -659,7 +710,11 @@ send_vc(res_state statp,
        iov[0] = evConsIovec(&len, INT16SZ);
        DE_CONST(buf, tmp);
        iov[1] = evConsIovec(tmp, buflen);
+#ifndef _LIBC
        if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+#else
+       if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+#endif
                *terrno = errno;
                Perror(statp, stderr, "write failed", errno);
                res_nclose(statp);
@@ -671,7 +726,11 @@ send_vc(res_state statp,
  read_len:
        cp = ans;
        len = INT16SZ;
+#ifndef _LIBC
        while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+#else
+       while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+#endif
                cp += n;
                if ((len -= n) == 0)
                        break;
@@ -717,7 +776,11 @@ send_vc(res_state statp,
                return (0);
        }
        cp = ans;
+#ifndef _LIBC
        while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+#else
+       while (len != 0 && (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+#endif
                cp += n;
                len -= n;
        }
@@ -736,7 +799,11 @@ send_vc(res_state statp,
                while (len != 0) {
                        char junk[PACKETSZ];
 
+#ifndef _LIBC
                        n = read(statp->_vcsock, junk,
+#else
+                       n = _read(statp->_vcsock, junk,
+#endif
                                 (len > sizeof junk) ? sizeof junk : len);
                        if (n > 0)
                                len -= n;
@@ -767,7 +834,11 @@ send_vc(res_state statp,
 }
 
 static int
-send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
+send_dg(res_state statp,
+#ifdef USE_KQUEUE
+       int kq,
+#endif
+       const u_char *buf, int buflen, u_char *ans,
        int anssiz, int *terrno, int ns, int try, int *v_circuit,
        int *gotsomewhere)
 {
@@ -779,21 +850,31 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
        struct sockaddr_storage from;
        ISC_SOCKLEN_T fromlen;
        int resplen, seconds, n, s;
+#ifdef USE_KQUEUE
+       struct kevent kv;
+#else
 #ifdef USE_POLL
        int     polltimeout;
        struct pollfd   pollfd;
 #else
        fd_set dsmask;
+#endif
 #endif
 
        nsap = get_nsaddr(statp, ns);
        nsaplen = get_salen(nsap);
        if (EXT(statp).nssocks[ns] == -1) {
+#ifndef _LIBC
                EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+#else
+               EXT(statp).nssocks[ns] = _socket(nsap->sa_family, SOCK_DGRAM, 0);
+#endif
+#if !defined(USE_POLL) && !defined(USE_KQUEUE)
                if (EXT(statp).nssocks[ns] > highestFD) {
                        res_nclose(statp);
                        errno = ENOTSOCK;
                }
+#endif
                if (EXT(statp).nssocks[ns] < 0) {
                        switch (errno) {
                        case EPROTONOSUPPORT:
@@ -820,8 +901,21 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
                 * socket operation, and select returns if the
                 * error message is received.  We can thus detect
                 * the absence of a nameserver without timing out.
+                *
+                *
+                * When the option "insecure1" is specified, we'd
+                * rather expect to see responses from an "unknown"
+                * address.  In order to let the kernel accept such
+                * responses, do not connect the socket here.
+                * XXX: or do we need an explicit option to disable
+                * connecting?
                 */
-               if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+               if (!(statp->options & RES_INSECURE1) &&
+#ifndef _LIBC
+                   connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+#else
+                   _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+#endif
                        Aerror(statp, stderr, "connect(dg)", errno, nsap,
                            nsaplen);
                        res_nclose(statp);
@@ -833,13 +927,28 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
        }
        s = EXT(statp).nssocks[ns];
 #ifndef CANNOT_CONNECT_DGRAM
-       if (send(s, (const char*)buf, buflen, 0) != buflen) {
+       if (statp->options & RES_INSECURE1) {
+#ifndef _LIBC
+               if (sendto(s,
+#else
+               if (_sendto(s,
+#endif
+                   (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
+                       Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+                       res_nclose(statp);
+                       return (0);
+               }
+       } else if (send(s, (const char*)buf, buflen, 0) != buflen) {
                Perror(statp, stderr, "send", errno);
                res_nclose(statp);
                return (0);
        }
 #else /* !CANNOT_CONNECT_DGRAM */
+#ifndef _LIBC
        if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+#else
+       if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+#endif
        {
                Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
                res_nclose(statp);
@@ -863,13 +972,18 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
        now = evNowTime();
  nonow:
 #ifndef USE_POLL
-       FD_ZERO(&dsmask);
-       FD_SET(s, &dsmask);
        if (evCmpTime(finish, now) > 0)
                timeout = evSubTime(finish, now);
        else
                timeout = evConsTime(0, 0);
+#ifdef USE_KQUEUE
+       EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+       n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
+#else
+       FD_ZERO(&dsmask);
+       FD_SET(s, &dsmask);
        n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+#endif
 #else
        timeout = evSubTime(finish, now);
        if (timeout.tv_sec < 0)
@@ -889,17 +1003,29 @@ send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
        if (n < 0) {
                if (errno == EINTR)
                        goto wait;
+#ifdef USE_KQUEUE
+               Perror(statp, stderr, "kevent", errno);
+#else
 #ifndef USE_POLL
                Perror(statp, stderr, "select", errno);
 #else
                Perror(statp, stderr, "poll", errno);
 #endif /* USE_POLL */
+#endif
                res_nclose(statp);
                return (0);
        }
+#ifdef USE_KQUEUE
+       if (kv.ident != s)
+               goto wait;
+#endif
        errno = 0;
        fromlen = sizeof(from);
+#ifndef _LIBC
        resplen = recvfrom(s, (char*)ans, anssiz,0,
+#else
+       resplen = _recvfrom(s, (char*)ans, anssiz,0,
+#endif
                           (struct sockaddr *)&from, &fromlen);
        if (resplen <= 0) {
                Perror(statp, stderr, "recvfrom", errno);
@@ -1062,7 +1188,7 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) {
        }
 }
 
-#if defined(NEED_PSELECT) && !defined(USE_POLL)
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
 /* XXX needs to move to the porting library. */
 static int
 pselect(int nfds, void *rfds, void *wfds, void *efds,
index 8783d8a..d8ed05f 100644 (file)
@@ -43,7 +43,7 @@ static const char rcsid[] = "$Id: res_update.c,v 1.6.2.4.4.2 2004/03/16 12:34:20
 #include <stdlib.h>
 #include <string.h>
 
-#include <isc/list.h>
+#include "isc/list.h"
 #include <resolv.h>
 
 #include "port_after.h"
@@ -167,8 +167,16 @@ res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
 
                /* Send the update and remember the result. */
                if (key != NULL)
+#ifdef _LIBC
+               {
+                       DPRINTF(("TSIG is not supported\n"));
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       goto done;
+               }
+#else
                        n = res_nsendsigned(statp, packet, n, key,
                                            answer, sizeof answer);
+#endif
                else
                        n = res_nsend(statp, packet, n, answer, sizeof answer);
                if (n < 0) {
index 0ad7d7d..5747d93 100644 (file)
@@ -18,7 +18,8 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \
        mpool.h monetary.h ndbm.h netconfig.h \
        netdb.h nl_types.h nlist.h nss.h nsswitch.h objformat.h \
        paths.h pthread.h pthread_np.h pwd.h \
-       ranlib.h readpassphrase.h regex.h regexp.h resolv.h re_comp.h rmd160.h \
+       ranlib.h readpassphrase.h regex.h regexp.h \
+       res_update.h resolv.h re_comp.h rmd160.h \
        search.h setjmp.h sgtty.h \
        signal.h stab.h stdarg.h stdbool.h stddef.h stdint.h stdio.h stdlib.h \
        string.h stringlist.h strings.h struct.h sysexits.h tar.h time.h \
index 57f224f..163f910 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
  *
  * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
+ *    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
@@ -14,8 +14,8 @@
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
  * 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.
@@ -40,7 +40,7 @@
  * 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
@@ -53,8 +53,8 @@
 
 /*
  *     @(#)inet.h      8.1 (Berkeley) 6/2/93
- *     From: Id: inet.h,v 8.5 1997/01/29 08:48:09 vixie Exp $
- * $FreeBSD: src/include/arpa/inet.h,v 1.11.2.1 2001/04/21 14:53:03 ume Exp $
+ *     $Id: inet.h,v 1.2.18.1 2005/04/27 05:00:50 sra Exp $
+ * $FreeBSD: src/include/arpa/inet.h,v 1.30 2007/08/24 20:25:52 bms Exp $
  * $DragonFly: src/include/arpa/inet.h,v 1.5 2005/07/13 12:49:56 joerg Exp $
  */
 
 #include <sys/types.h>
 #include <sys/cdefs.h>
 
-#ifndef _STRUCT_IN_ADDR_DECLARED
-#define _STRUCT_IN_ADDR_DECLARED
+/* Required for byteorder(3) functions. */
+#include <machine/endian.h>
+
+#define        INET_ADDRSTRLEN         16
+#define        INET6_ADDRSTRLEN        46
+
 /*
- * Internet address (a structure for historical reasons)
+ * XXX socklen_t is used by a POSIX.1-2001 interface, but not required by
+ * POSIX.1-2001.
  */
+#ifndef _SOCKLEN_T_DECLARED
+typedef        __socklen_t     socklen_t;
+#define        _SOCKLEN_T_DECLARED
+#endif
+
+#ifndef _STRUCT_IN_ADDR_DECLARED
 struct in_addr {
        in_addr_t s_addr;
 };
+#define        _STRUCT_IN_ADDR_DECLARED
 #endif
 
 /* XXX all new diversions!! argh!! */
+#if __BSD_VISIBLE
 #define        inet_addr       __inet_addr
 #define        inet_aton       __inet_aton
 #define        inet_lnaof      __inet_lnaof
@@ -86,42 +99,46 @@ struct in_addr {
 #define        inet_network    __inet_network
 #define        inet_net_ntop   __inet_net_ntop
 #define        inet_net_pton   __inet_net_pton
+#define        inet_cidr_ntop  __inet_cidr_ntop
+#define        inet_cidr_pton  __inet_cidr_pton
 #define        inet_ntoa       __inet_ntoa
+#define        inet_ntoa_r     __inet_ntoa_r
 #define        inet_pton       __inet_pton
 #define        inet_ntop       __inet_ntop
 #define        inet_nsap_addr  __inet_nsap_addr
 #define        inet_nsap_ntoa  __inet_nsap_ntoa
+#endif /* __BSD_VISIBLE */
+
+__BEGIN_DECLS
+in_addr_t       inet_addr(const char *);
+/*const*/ char *inet_ntoa(struct in_addr);
+char           *inet_ntoa_r(struct in_addr, char *buf, socklen_t size);
+const char     *inet_ntop(int, const void * __restrict, char * __restrict,
+                   socklen_t);
+int             inet_pton(int, const char * __restrict, void * __restrict);
 
-#ifndef htonl
+#if __BSD_VISIBLE
+int             inet_aton(const char *, struct in_addr *);
+in_addr_t       inet_lnaof(struct in_addr);
+struct in_addr  inet_makeaddr(in_addr_t, in_addr_t);
+char           *inet_neta(in_addr_t, char *, size_t);
+in_addr_t       inet_netof(struct in_addr);
+in_addr_t       inet_network(const char *);
+char           *inet_net_ntop(int, const void *, int, char *, size_t);
+int             inet_net_pton(int, const char *, void *, size_t);
+char           *inet_cidr_ntop(int, const void *, int, char *, size_t);
+int             inet_cidr_pton(int, const char *, void *, int *);
+unsigned        inet_nsap_addr(const char *, unsigned char *, int);
+char           *inet_nsap_ntoa(int, const unsigned char *, char *);
+#endif /* __BSD_VISIBLE */
+__END_DECLS
+
+#ifndef _BYTEORDER_FUNC_DEFINED
+#define        _BYTEORDER_FUNC_DEFINED
 #define        htonl(x)        __htonl(x)
-#endif
-#ifndef htons
 #define        htons(x)        __htons(x)
-#endif
-#ifndef ntohl
 #define        ntohl(x)        __ntohl(x)
-#endif
-#ifndef ntohs
 #define        ntohs(x)        __ntohs(x)
 #endif
 
-__BEGIN_DECLS
-int             ascii2addr (int, const char *, void *);
-char           *addr2ascii (int, const void *, int, char *);
-in_addr_t       inet_addr (const char *);
-int             inet_aton (const char *, struct in_addr *);
-in_addr_t       inet_lnaof (struct in_addr);
-struct in_addr  inet_makeaddr (in_addr_t, in_addr_t);
-char *          inet_neta (in_addr_t, char *, size_t);
-in_addr_t       inet_netof (struct in_addr);
-in_addr_t       inet_network (const char *);
-char           *inet_net_ntop (int, const void *, int, char *, size_t);
-int             inet_net_pton (int, const char *, void *, size_t);
-char           *inet_ntoa (struct in_addr);
-int              inet_pton (int, const char *, void *);
-const char     *inet_ntop (int, const void *, char *, size_t);
-u_int           inet_nsap_addr (const char *, u_char *, int);
-char           *inet_nsap_ntoa (int, const u_char *, char *);
-__END_DECLS
-
-#endif /* !_INET_H_ */
+#endif /* !_ARPA_INET_H_ */
index 70ff02f..db4bd8a 100644 (file)
  */
 
 /*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 /*
- *     From: Id: nameser.h,v 8.16 1998/02/06 00:35:58 halley Exp
- * $FreeBSD: src/include/arpa/nameser.h,v 1.14.2.1 2001/06/15 22:08:27 ume Exp $
+ *     $Id: nameser.h,v 1.7.18.2 2008/04/03 23:15:15 marka Exp $
+ * $FreeBSD: src/include/arpa/nameser.h,v 1.21 2008/12/14 19:39:53 ume Exp $
  * $DragonFly: src/include/arpa/nameser.h,v 1.5 2007/04/18 18:39:11 swildner Exp $
  */
 
 
 #define BIND_4_COMPAT
 
+#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/cdefs.h>
 
 /*
- * revision information.  this is the release date in YYYYMMDD format.
- * it can change every day so the right thing to do with it is use it
- * in preprocessor commands such as "#if (__NAMESER > 19931104)".  do not
- * compare for equality; rather, use it to determine whether your libnameser.a
- * is new enough to contain a certain feature.
+ * Revision information.  This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__NAMESER > 19931104)".  Do not
+ * compare for equality; rather, use it to determine whether your libbind.a
+ * contains a new enough lib/nameser/ to support the feature you need.
  */
 
-/* XXXRTH I made this bigger than __BIND in 4.9.5 T6B */
-#define __NAMESER      19961001        /* New interface version stamp. */
-
+#define __NAMESER      19991006        /* New interface version stamp. */
 /*
  * Define constants based on RFC 883, RFC 1034, RFC 1035
  */
-#define NS_PACKETSZ    512     /* maximum packet size */
+#define NS_PACKETSZ    512     /* default UDP packet size */
 #define NS_MAXDNAME    1025    /* maximum domain name */
+#define NS_MAXMSG      65535   /* maximum message size */
 #define NS_MAXCDNAME   255     /* maximum compressed domain name */
 #define NS_MAXLABEL    63      /* maximum length of domain label */
 #define NS_HFIXEDSZ    12      /* #/bytes of fixed data in header */
@@ -90,7 +90,6 @@
 #define NS_IN6ADDRSZ   16      /* IPv6 T_AAAA */
 #define NS_CMPRSFLGS   0xc0    /* Flag bits indicating name compression. */
 #define NS_DEFAULTPORT 53      /* For both TCP and UDP. */
-
 /*
  * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord()
  * in synch with it.
@@ -117,7 +116,7 @@ typedef struct __ns_msg {
        const u_char    *_sections[ns_s_max];
        ns_sect         _sect;
        int             _rrnum;
-       const u_char    *_ptr;
+       const u_char    *_msg_ptr;
 } ns_msg;
 
 /* Private data structure - do not use from outside library. */
@@ -125,10 +124,7 @@ struct _ns_flagdata {  int mask, shift;  };
 extern struct _ns_flagdata _ns_flagdata[];
 
 /* Accessor macros - this is part of the public interface. */
-#define ns_msg_getflag(handle, flag) ( \
-                       ((handle)._flags & _ns_flagdata[flag].mask) \
-                        >> _ns_flagdata[flag].shift \
-                       )
+
 #define ns_msg_id(handle) ((handle)._id + 0)
 #define ns_msg_base(handle) ((handle)._msg + 0)
 #define ns_msg_end(handle) ((handle)._eom + 0)
@@ -139,7 +135,7 @@ extern struct _ns_flagdata _ns_flagdata[];
  * This is a parsed record.  It is caller allocated and has no dynamic data.
  */
 typedef        struct __ns_rr {
-       char            name[NS_MAXDNAME];      /* XXX need to malloc */
+       char            name[NS_MAXDNAME];
        u_int16_t       type;
        u_int16_t       rr_class;
        u_int32_t       ttl;
@@ -149,8 +145,8 @@ typedef     struct __ns_rr {
 
 /* Accessor macros - this is part of the public interface. */
 #define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
-#define ns_rr_type(rr) ((rr).type + 0)
-#define ns_rr_class(rr)        ((rr).rr_class + 0)
+#define ns_rr_type(rr) ((ns_type)((rr).type + 0))
+#define ns_rr_class(rr)        ((ns_class)((rr).rr_class + 0))
 #define ns_rr_ttl(rr)  ((rr).ttl + 0)
 #define ns_rr_rdlen(rr)        ((rr).rdlength + 0)
 #define ns_rr_rdata(rr)        ((rr).rdata + 0)
@@ -203,7 +199,13 @@ typedef    enum __ns_rcode {
        ns_r_nxrrset = 8,       /* RRset does not exist */
        ns_r_notauth = 9,       /* Not authoritative for zone */
        ns_r_notzone = 10,      /* Zone of record different from zone section */
-       ns_r_max = 11
+       ns_r_max = 11,
+       /* The following are EDNS extended rcodes */
+       ns_r_badvers = 16,
+       /* The following are TSIG errors */
+       ns_r_badsig = 16,
+       ns_r_badkey = 17,
+       ns_r_badtime = 18
 } ns_rcode;
 
 /* BIND_UPDATE */
@@ -214,31 +216,40 @@ typedef enum __ns_update_operation {
 } ns_update_operation;
 
 /*
- * This RR-like structure is particular to UPDATE.
+ * This structure is used for TSIG authenticated messages
+ */
+struct ns_tsig_key {
+        char name[NS_MAXDNAME], alg[NS_MAXDNAME];
+        unsigned char *data;
+        int len;
+};
+typedef struct ns_tsig_key ns_tsig_key;
+
+/*
+ * This structure is used for TSIG authenticated TCP messages
  */
-struct ns_updrec {
-       struct ns_updrec *r_prev;       /* prev record */
-       struct ns_updrec *r_next;       /* next record */
-       u_int8_t        r_section;      /* ZONE/PREREQUISITE/UPDATE */
-       char *          r_dname;        /* owner of the RR */
-       u_int16_t       r_class;        /* class number */
-       u_int16_t       r_type;         /* type number */
-       u_int32_t       r_ttl;          /* time to live */
-       u_char *        r_data;         /* rdata fields as text string */
-       u_int16_t       r_size;         /* size of r_data field */
-       int             r_opcode;       /* type of operation */
-       /* following fields for private use by the resolver/server routines */
-       struct ns_updrec *r_grpnext;    /* next record when grouped */
-       struct databuf *r_dp;           /* databuf to process */
-       struct databuf *r_deldp;        /* databuf's deleted/overwritten */
-       u_int16_t       r_zone;         /* zone number on server */
+struct ns_tcp_tsig_state {
+       int counter;
+       struct dst_key *key;
+       void *ctx;
+       unsigned char sig[NS_PACKETSZ];
+       int siglen;
 };
-typedef struct ns_updrec ns_updrec;
+typedef struct ns_tcp_tsig_state ns_tcp_tsig_state;
+
+#define NS_TSIG_FUDGE 300
+#define NS_TSIG_TCP_COUNT 100
+#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT"
+
+#define NS_TSIG_ERROR_NO_TSIG -10
+#define NS_TSIG_ERROR_NO_SPACE -11
+#define NS_TSIG_ERROR_FORMERR -12
 
 /*
  * Currently defined type values for resources and queries.
  */
 typedef enum __ns_type {
+       ns_t_invalid = 0,       /* Cookie. */
        ns_t_a = 1,             /* Host address. */
        ns_t_ns = 2,            /* Authoritative server. */
        ns_t_md = 3,            /* Mail destination. */
@@ -274,22 +285,42 @@ typedef enum __ns_type {
        ns_t_srv = 33,          /* Server Selection. */
        ns_t_atma = 34,         /* ATM Address */
        ns_t_naptr = 35,        /* Naming Authority PoinTeR */
-       ns_t_opt = 41,          /* OPT pseudo-RR, RFC2761 */
-       /* Query type values which do not appear in resource records. */
+       ns_t_kx = 36,           /* Key Exchange */
+       ns_t_cert = 37,         /* Certification record */
+       ns_t_a6 = 38,           /* IPv6 address (deprecates AAAA) */
+       ns_t_dname = 39,        /* Non-terminal DNAME (for IPv6) */
+       ns_t_sink = 40,         /* Kitchen sink (experimentatl) */
+       ns_t_opt = 41,          /* EDNS0 option (meta-RR) */
+       ns_t_apl = 42,          /* Address prefix list (RFC3123) */
+       ns_t_tkey = 249,        /* Transaction key */
+       ns_t_tsig = 250,        /* Transaction signature. */
        ns_t_ixfr = 251,        /* Incremental zone transfer. */
        ns_t_axfr = 252,        /* Transfer zone of authority. */
        ns_t_mailb = 253,       /* Transfer mailbox records. */
        ns_t_maila = 254,       /* Transfer mail agent records. */
        ns_t_any = 255,         /* Wildcard match. */
+       ns_t_zxfr = 256,        /* BIND-specific, nonstandard. */
        ns_t_max = 65536
 } ns_type;
 
+/* Exclusively a QTYPE? (not also an RTYPE) */
+#define        ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \
+                     (t) == ns_t_mailb || (t) == ns_t_maila)
+/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */
+#define        ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt)
+/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */
+#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t))
+#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr)
+#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \
+                      (t) == ns_t_zxfr)
+
 /*
  * Values for class field
  */
 typedef enum __ns_class {
+       ns_c_invalid = 0,       /* Cookie. */
        ns_c_in = 1,            /* Internet. */
-                               /* Class 2 unallocated/unsupported. */
+       ns_c_2 = 2,             /* unallocated/unsupported. */
        ns_c_chaos = 3,         /* MIT Chaos-net. */
        ns_c_hs = 4,            /* MIT Hesiod. */
        /* Query class values which do not appear in resource records */
@@ -298,9 +329,24 @@ typedef enum __ns_class {
        ns_c_max = 65536
 } ns_class;
 
-/*
- * Flags field of the KEY RR rdata
- */
+/* DNSSEC constants. */
+
+typedef enum __ns_key_types {
+       ns_kt_rsa = 1,          /* key type RSA/MD5 */
+       ns_kt_dh  = 2,          /* Diffie Hellman */
+       ns_kt_dsa = 3,          /* Digital Signature Standard (MANDATORY) */
+       ns_kt_private = 254     /* Private key type starts with OID */
+} ns_key_types;
+
+typedef enum __ns_cert_types {
+       cert_t_pkix = 1,        /* PKIX (X.509v3) */
+       cert_t_spki = 2,        /* SPKI */
+       cert_t_pgp  = 3,        /* PGP */
+       cert_t_url  = 253,      /* URL private type */
+       cert_t_oid  = 254       /* OID private type */
+} ns_cert_types;
+
+/* Flags field of the KEY RR rdata. */
 #define        NS_KEY_TYPEMASK         0xC000  /* Mask for "type" bits */
 #define        NS_KEY_TYPE_AUTH_CONF   0x0000  /* Key usable for both */
 #define        NS_KEY_TYPE_CONF_ONLY   0x8000  /* Key usable for confidentiality */
@@ -309,35 +355,56 @@ typedef enum __ns_class {
 /* The type bits can also be interpreted independently, as single bits: */
 #define        NS_KEY_NO_AUTH          0x8000  /* Key unusable for authentication */
 #define        NS_KEY_NO_CONF          0x4000  /* Key unusable for confidentiality */
-#define        NS_KEY_EXPERIMENTAL     0x2000  /* Security is *mandatory* if bit=0 */
-#define        NS_KEY_RESERVED3        0x1000  /* reserved - must be zero */
+#define        NS_KEY_RESERVED2        0x2000  /* Security is *mandatory* if bit=0 */
+#define        NS_KEY_EXTENDED_FLAGS   0x1000  /* reserved - must be zero */
 #define        NS_KEY_RESERVED4        0x0800  /* reserved - must be zero */
-#define        NS_KEY_USERACCOUNT      0x0400  /* key is assoc. with a user acct */
-#define        NS_KEY_ENTITY           0x0200  /* key is assoc. with entity eg host */
-#define        NS_KEY_ZONEKEY          0x0100  /* key is zone key */
-#define        NS_KEY_IPSEC            0x0080  /* key is for IPSEC (host or user)*/
-#define        NS_KEY_EMAIL            0x0040  /* key is for email (MIME security) */
+#define        NS_KEY_RESERVED5        0x0400  /* reserved - must be zero */
+#define        NS_KEY_NAME_TYPE        0x0300  /* these bits determine the type */
+#define        NS_KEY_NAME_USER        0x0000  /* key is assoc. with user */
+#define        NS_KEY_NAME_ENTITY      0x0200  /* key is assoc. with entity eg host */
+#define        NS_KEY_NAME_ZONE        0x0100  /* key is zone key */
+#define        NS_KEY_NAME_RESERVED    0x0300  /* reserved meaning */
+#define        NS_KEY_RESERVED8        0x0080  /* reserved - must be zero */
+#define        NS_KEY_RESERVED9        0x0040  /* reserved - must be zero */
 #define        NS_KEY_RESERVED10       0x0020  /* reserved - must be zero */
 #define        NS_KEY_RESERVED11       0x0010  /* reserved - must be zero */
 #define        NS_KEY_SIGNATORYMASK    0x000F  /* key can sign RR's of same name */
-
-#define        NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED3 | \
+#define        NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \
                                  NS_KEY_RESERVED4 | \
+                                 NS_KEY_RESERVED5 | \
+                                 NS_KEY_RESERVED8 | \
+                                 NS_KEY_RESERVED9 | \
                                  NS_KEY_RESERVED10 | \
                                  NS_KEY_RESERVED11 )
-
+#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */
 /* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
 #define        NS_ALG_MD5RSA           1       /* MD5 with RSA */
+#define        NS_ALG_DH               2       /* Diffie Hellman KEY */
+#define        NS_ALG_DSA              3       /* DSA KEY */
+#define        NS_ALG_DSS              NS_ALG_DSA
 #define        NS_ALG_EXPIRE_ONLY      253     /* No alg, no security */
 #define        NS_ALG_PRIVATE_OID      254     /* Key begins with OID giving alg */
+/* Protocol values  */
+/* value 0 is reserved */
+#define NS_KEY_PROT_TLS         1
+#define NS_KEY_PROT_EMAIL       2
+#define NS_KEY_PROT_DNSSEC      3
+#define NS_KEY_PROT_IPSEC       4
+#define NS_KEY_PROT_ANY                255
 
 /* Signatures */
 #define        NS_MD5RSA_MIN_BITS       512    /* Size of a mod or exp in bits */
-#define        NS_MD5RSA_MAX_BITS      2552
+#define        NS_MD5RSA_MAX_BITS      4096
        /* Total of binary mod and exp */
 #define        NS_MD5RSA_MAX_BYTES     ((NS_MD5RSA_MAX_BITS+7/8)*2+3)
        /* Max length of text sig block */
 #define        NS_MD5RSA_MAX_BASE64    (((NS_MD5RSA_MAX_BYTES+2)/3)*4)
+#define NS_MD5RSA_MIN_SIZE     ((NS_MD5RSA_MIN_BITS+7)/8)
+#define NS_MD5RSA_MAX_SIZE     ((NS_MD5RSA_MAX_BITS+7)/8)
+
+#define NS_DSA_SIG_SIZE         41
+#define NS_DSA_MIN_SIZE         213
+#define NS_DSA_MAX_BYTES        405
 
 /* Offsets into SIG record rdata to find various values */
 #define        NS_SIG_TYPE     0       /* Type flags */
@@ -348,26 +415,31 @@ typedef enum __ns_class {
 #define        NS_SIG_SIGNED   12      /* Signature time */
 #define        NS_SIG_FOOT     16      /* Key footprint */
 #define        NS_SIG_SIGNER   18      /* Domain name of who signed it */
-
 /* How RR types are represented as bit-flags in NXT records */
 #define        NS_NXT_BITS 8
 #define        NS_NXT_BIT_SET(  n,p) (p[(n)/NS_NXT_BITS] |=  (0x80>>((n)%NS_NXT_BITS)))
 #define        NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS)))
 #define        NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] &   (0x80>>((n)%NS_NXT_BITS)))
+#define NS_NXT_MAX 127
 
+/*
+ * EDNS0 extended flags and option codes, host order.
+ */
+#define NS_OPT_DNSSEC_OK       0x8000U
+#define NS_OPT_NSID             3
 
 /*
  * Inline versions of get/put short/long.  Pointer is advanced.
  */
-#define NS_GET16(s, cp) { \
+#define NS_GET16(s, cp) do { \
        const u_char *t_cp = (const u_char *)(cp); \
        (s) = ((u_int16_t)t_cp[0] << 8) \
            | ((u_int16_t)t_cp[1]) \
            ; \
        (cp) += NS_INT16SZ; \
-}
+} while (0)
 
-#define NS_GET32(l, cp) { \
+#define NS_GET32(l, cp) do { \
        const u_char *t_cp = (const u_char *)(cp); \
        (l) = ((u_int32_t)t_cp[0] << 24) \
            | ((u_int32_t)t_cp[1] << 16) \
@@ -375,17 +447,17 @@ typedef enum __ns_class {
            | ((u_int32_t)t_cp[3]) \
            ; \
        (cp) += NS_INT32SZ; \
-}
+} while (0)
 
-#define NS_PUT16(s, cp) { \
+#define NS_PUT16(s, cp) do { \
        u_int16_t t_s = (u_int16_t)(s); \
        u_char *t_cp = (u_char *)(cp); \
        *t_cp++ = t_s >> 8; \
        *t_cp   = t_s; \
        (cp) += NS_INT16SZ; \
-}
+} while (0)
 
-#define NS_PUT32(l, cp) { \
+#define NS_PUT32(l, cp) do { \
        u_int32_t t_l = (u_int32_t)(l); \
        u_char *t_cp = (u_char *)(cp); \
        *t_cp++ = t_l >> 24; \
@@ -393,54 +465,114 @@ typedef enum __ns_class {
        *t_cp++ = t_l >> 8; \
        *t_cp   = t_l; \
        (cp) += NS_INT32SZ; \
-}
+} while (0)
 
 /*
- * ANSI C identifier hiding.
+ * ANSI C identifier hiding for bind's lib/nameser.
  */
+#define        ns_msg_getflag          __ns_msg_getflag
 #define ns_get16               __ns_get16
 #define ns_get32               __ns_get32
 #define ns_put16               __ns_put16
 #define ns_put32               __ns_put32
 #define ns_initparse           __ns_initparse
+#define ns_skiprr              __ns_skiprr
 #define ns_parserr             __ns_parserr
 #define        ns_sprintrr             __ns_sprintrr
 #define        ns_sprintrrf            __ns_sprintrrf
 #define        ns_format_ttl           __ns_format_ttl
 #define        ns_parse_ttl            __ns_parse_ttl
+#if 0
+#define ns_datetosecs          __ns_datetosecs
+#endif
+#define        ns_name_ntol            __ns_name_ntol
 #define        ns_name_ntop            __ns_name_ntop
 #define        ns_name_pton            __ns_name_pton
 #define        ns_name_unpack          __ns_name_unpack
 #define        ns_name_pack            __ns_name_pack
 #define        ns_name_compress        __ns_name_compress
 #define        ns_name_uncompress      __ns_name_uncompress
+#define        ns_name_skip            __ns_name_skip
+#define        ns_name_rollback        __ns_name_rollback
+#if 0
+#define        ns_sign                 __ns_sign
+#define        ns_sign2                __ns_sign2
+#define        ns_sign_tcp             __ns_sign_tcp
+#define        ns_sign_tcp2            __ns_sign_tcp2
+#define        ns_sign_tcp_init        __ns_sign_tcp_init
+#define ns_find_tsig           __ns_find_tsig
+#define        ns_verify               __ns_verify
+#define        ns_verify_tcp           __ns_verify_tcp
+#define        ns_verify_tcp_init      __ns_verify_tcp_init
+#endif
+#define        ns_samedomain           __ns_samedomain
+#if 0
+#define        ns_subdomain            __ns_subdomain
+#endif
+#define        ns_makecanon            __ns_makecanon
+#define        ns_samename             __ns_samename
 
 __BEGIN_DECLS
-u_int          ns_get16 (const u_char *);
-u_long         ns_get32 (const u_char *);
-void           ns_put16 (u_int, u_char *);
-void           ns_put32 (u_long, u_char *);
-int            ns_initparse (const u_char *, int, ns_msg *);
-int            ns_parserr (ns_msg *, ns_sect, int, ns_rr *);
-int            ns_sprintrr (const ns_msg *, const ns_rr *,
-                                const char *, const char *, char *, size_t);
-int            ns_sprintrrf (const u_char *, size_t, const char *,
-                                 ns_class, ns_type, u_long, const u_char *,
-                                 size_t, const char *, const char *,
-                                 char *, size_t);
-int            ns_format_ttl (u_long, char *, size_t);
-int            ns_parse_ttl (const char *, u_long *);
-int            ns_name_ntop (const u_char *, char *, size_t);
-int            ns_name_pton (const char *, u_char *, size_t);
-int            ns_name_unpack (const u_char *, const u_char *,
-                                   const u_char *, u_char *, size_t);
-int            ns_name_pack (const u_char *, u_char *, int,
-                                 const u_char **, const u_char **);
-int            ns_name_uncompress (const u_char *, const u_char *,
-                                       const u_char *, char *, size_t);
-int            ns_name_compress (const char *, u_char *, size_t,
-                                     const u_char **, const u_char **);
-int            ns_name_skip (const u_char **, const u_char *);
+int            ns_msg_getflag(ns_msg, int);
+u_int          ns_get16(const u_char *);
+u_long         ns_get32(const u_char *);
+void           ns_put16(u_int, u_char *);
+void           ns_put32(u_long, u_char *);
+int            ns_initparse(const u_char *, int, ns_msg *);
+int            ns_skiprr(const u_char *, const u_char *, ns_sect, int);
+int            ns_parserr(ns_msg *, ns_sect, int, ns_rr *);
+int            ns_sprintrr(const ns_msg *, const ns_rr *,
+                           const char *, const char *, char *, size_t);
+int            ns_sprintrrf(const u_char *, size_t, const char *,
+                            ns_class, ns_type, u_long, const u_char *,
+                            size_t, const char *, const char *,
+                            char *, size_t);
+int            ns_format_ttl(u_long, char *, size_t);
+int            ns_parse_ttl(const char *, u_long *);
+#if 0
+u_int32_t      ns_datetosecs(const char *cp, int *errp);
+#endif
+int            ns_name_ntol(const u_char *, u_char *, size_t);
+int            ns_name_ntop(const u_char *, char *, size_t);
+int            ns_name_pton(const char *, u_char *, size_t);
+int            ns_name_unpack(const u_char *, const u_char *,
+                              const u_char *, u_char *, size_t);
+int            ns_name_pack(const u_char *, u_char *, int,
+                            const u_char **, const u_char **);
+int            ns_name_uncompress(const u_char *, const u_char *,
+                                  const u_char *, char *, size_t);
+int            ns_name_compress(const char *, u_char *, size_t,
+                                const u_char **, const u_char **);
+int            ns_name_skip(const u_char **, const u_char *);
+void           ns_name_rollback(const u_char *, const u_char **,
+                                const u_char **);
+#if 0
+int            ns_sign(u_char *, int *, int, int, void *,
+                       const u_char *, int, u_char *, int *, time_t);
+int            ns_sign2(u_char *, int *, int, int, void *,
+                        const u_char *, int, u_char *, int *, time_t,
+                        u_char **, u_char **);
+int            ns_sign_tcp(u_char *, int *, int, int,
+                           ns_tcp_tsig_state *, int);
+int            ns_sign_tcp2(u_char *, int *, int, int,
+                            ns_tcp_tsig_state *, int,
+                            u_char **, u_char **);
+int            ns_sign_tcp_init(void *, const u_char *, int,
+                                ns_tcp_tsig_state *);
+u_char         *ns_find_tsig(u_char *, u_char *);
+int            ns_verify(u_char *, int *, void *,
+                         const u_char *, int, u_char *, int *,
+                         time_t *, int);
+int            ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int);
+int            ns_verify_tcp_init(void *, const u_char *, int,
+                                  ns_tcp_tsig_state *);
+#endif
+int            ns_samedomain(const char *, const char *);
+#if 0
+int            ns_subdomain(const char *, const char *);
+#endif
+int            ns_makecanon(const char *, char *, size_t);
+int            ns_samename(const char *, const char *);
 __END_DECLS
 
 #ifdef BIND_4_COMPAT
index da6734e..1b84a22 100644 (file)
@@ -32,8 +32,8 @@
 
 /*
  *      from nameser.h 8.1 (Berkeley) 6/2/93
- *     From: Id: nameser_compat.h,v 8.9 1998/03/20 23:25:10 halley Exp
- * $FreeBSD: src/include/arpa/nameser_compat.h,v 1.2.2.1 2001/06/15 22:08:27 ume Exp $
+ *     $Id: nameser_compat.h,v 1.5.18.3 2006/05/19 02:36:00 marka Exp $
+ * $FreeBSD: src/include/arpa/nameser_compat.h,v 1.7 2007/06/03 17:20:25 ume Exp $
  * $DragonFly: src/include/arpa/nameser_compat.h,v 1.2 2003/06/17 04:25:58 dillon Exp $
  */
 
 
 #include <machine/endian.h>
 
-#if !defined(BYTE_ORDER) || \
-    (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
-    BYTE_ORDER != PDP_ENDIAN)
+#if !defined(_BYTE_ORDER) || \
+    (_BYTE_ORDER != _BIG_ENDIAN && _BYTE_ORDER != _LITTLE_ENDIAN && \
+    _BYTE_ORDER != _PDP_ENDIAN)
        /* you must determine what the correct bit order is for
         * your compiler - the next line is an intentional error
         * which will force your compiles to bomb until you fix
         * the above macros.
         */
-  error "Undefined or invalid BYTE_ORDER";
+#error "Undefined or invalid _BYTE_ORDER";
 #endif
 
 /*
@@ -64,7 +64,7 @@
 
 typedef struct {
        unsigned        id :16;         /* query identification number */
-#if BYTE_ORDER == BIG_ENDIAN
+#if _BYTE_ORDER == _BIG_ENDIAN
                        /* fields in third byte */
        unsigned        qr: 1;          /* response flag */
        unsigned        opcode: 4;      /* purpose of message */
@@ -78,7 +78,7 @@ typedef struct {
        unsigned        cd: 1;          /* checking disabled by resolver */
        unsigned        rcode :4;       /* response code */
 #endif
-#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+#if _BYTE_ORDER == _LITTLE_ENDIAN || _BYTE_ORDER == _PDP_ENDIAN
                        /* fields in third byte */
        unsigned        rd :1;          /* recursion desired */
        unsigned        tc :1;          /* truncated message */
@@ -108,6 +108,7 @@ typedef struct {
 #define RRFIXEDSZ      NS_RRFIXEDSZ
 #define        INT32SZ         NS_INT32SZ
 #define        INT16SZ         NS_INT16SZ
+#define        INT8SZ          NS_INT8SZ
 #define        INADDRSZ        NS_INADDRSZ
 #define        IN6ADDRSZ       NS_IN6ADDRSZ
 #define        INDIR_MASK      NS_CMPRSFLGS
@@ -135,6 +136,10 @@ typedef struct {
 #define NXRRSET                ns_r_nxrrset
 #define NOTAUTH                ns_r_notauth
 #define NOTZONE                ns_r_notzone
+/*#define BADSIG               ns_r_badsig*/
+/*#define BADKEY               ns_r_badkey*/
+/*#define BADTIME              ns_r_badtime*/
+
 
 #define DELETE         ns_uop_delete
 #define ADD            ns_uop_add
@@ -174,7 +179,9 @@ typedef struct {
 #define        T_SRV           ns_t_srv
 #define T_ATMA         ns_t_atma
 #define T_NAPTR                ns_t_naptr
+#define T_A6           ns_t_a6
 #define T_OPT          ns_t_opt
+#define        T_TSIG          ns_t_tsig
 #define        T_IXFR          ns_t_ixfr
 #define T_AXFR         ns_t_axfr
 #define T_MAILB                ns_t_mailb
index 3d8b1e0..5cd521f 100644 (file)
 /*
  *      @(#)netdb.h    8.1 (Berkeley) 6/2/93
  *      From: Id: netdb.h,v 8.9 1996/11/19 08:39:29 vixie Exp $
- * $FreeBSD: src/include/netdb.h,v 1.14.2.5 2001/08/29 08:46:51 alfred Exp $
+ * $FreeBSD: src/include/netdb.h,v 1.44 2006/05/21 11:27:28 ume Exp $
  * $DragonFly: src/include/netdb.h,v 1.7 2008/10/04 22:09:16 swildner Exp $
  */
 
 #ifndef _NETDB_H_
 #define _NETDB_H_
 
-#ifndef _MACHINE_STDINT_H_
-#include <machine/stdint.h>
-#endif
 #include <sys/cdefs.h>
+#include <sys/types.h>
 
 #ifndef _SIZE_T_DECLARED
-#define _SIZE_T_DECLARED
-typedef __size_t        size_t;
+typedef        __size_t        size_t;
+#define        _SIZE_T_DECLARED
 #endif
 
 #ifndef _SOCKLEN_T_DECLARED
-#define _SOCKLEN_T_DECLARED
-typedef __socklen_t     socklen_t;
+typedef        __socklen_t     socklen_t;
+#define        _SOCKLEN_T_DECLARED
 #endif
 
 #ifndef _PATH_HEQUIV
@@ -85,14 +83,14 @@ typedef __socklen_t     socklen_t;
 #define        _PATH_PROTOCOLS "/etc/protocols"
 #define        _PATH_SERVICES  "/etc/services"
 
-extern int h_errno;
+#define        h_errno (*__h_errno())
 
 /*
  * Structures returned by network data base library.  All addresses are
  * supplied in host order, and returned in network order (suitable for
  * use in system calls).
  */
-struct hostent {
+struct hostent {
        char    *h_name;        /* official name of host */
        char    **h_aliases;    /* alias list */
        int     h_addrtype;     /* host address type */
@@ -101,25 +99,21 @@ struct     hostent {
 #define        h_addr  h_addr_list[0]  /* address, for backward compatibility */
 };
 
-/*
- * Assumption here is that a network number
- * fits in an unsigned long -- probably a poor one.
- */
-struct netent {
+struct netent {
        char            *n_name;        /* official name of net */
        char            **n_aliases;    /* alias list */
        int             n_addrtype;     /* net address type */
-       unsigned long   n_net;          /* network # */
+       uint32_t        n_net;          /* network # */
 };
 
-struct servent {
+struct servent {
        char    *s_name;        /* official service name */
        char    **s_aliases;    /* alias list */
        int     s_port;         /* port # */
        char    *s_proto;       /* protocol to use */
 };
 
-struct protoent {
+struct protoent {
        char    *p_name;        /* official protocol name */
        char    **p_aliases;    /* alias list */
        int     p_proto;        /* protocol # */
@@ -130,7 +124,7 @@ struct addrinfo {
        int     ai_family;      /* PF_xxx */
        int     ai_socktype;    /* SOCK_xxx */
        int     ai_protocol;    /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
-       size_t ai_addrlen;      /* length of ai_addr */
+       socklen_t ai_addrlen;   /* length of ai_addr */
        char    *ai_canonname;  /* canonical name for hostname */
        struct  sockaddr *ai_addr;      /* binary address */
        struct  addrinfo *ai_next;      /* next structure in linked list */
@@ -138,7 +132,7 @@ struct addrinfo {
 
 /*
  * Error return codes from gethostbyname() and gethostbyaddr()
- * (left in extern int h_errno).
+ * (left in h_errno).
  */
 
 #define        NETDB_INTERNAL  -1      /* see errno */
@@ -178,7 +172,7 @@ struct addrinfo {
 /* valid flags for addrinfo (not a standard def, apps should not use it) */
 #define AI_MASK \
     (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | \
-     AI_ADDRCONFIG)
+    AI_ADDRCONFIG)
 
 #define        AI_ALL          0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
 #define        AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */
@@ -208,67 +202,77 @@ struct addrinfo {
  */
 #define        SCOPE_DELIMITER '%'
 
-/*
- * data types - basically forward decl for getnameinfo()
- */
-
 __BEGIN_DECLS
-void           endhostent (void);
-void           endnetent (void);
-void           endnetgrent (void);
-void           endprotoent (void);
-void           endservent (void);
-void           freehostent (struct hostent *);
-struct hostent *gethostbyaddr (const void *, socklen_t, int);
-struct hostent *gethostbyname (const char *);
-struct hostent *gethostbyname2 (const char *, int);
-struct hostent *gethostent (void);
-struct hostent *getipnodebyaddr (const void *, size_t, int, int *);
-struct hostent *getipnodebyname (const char *, int, int, int *);
-struct netent  *getnetbyaddr (unsigned long, int);
-struct netent  *getnetbyname (const char *);
-struct netent  *getnetent (void);
-int            getnetgrent (char **, char **, char **);
-struct protoent        *getprotobyname (const char *);
-struct protoent        *getprotobynumber (int);
-struct protoent        *getprotoent (void);
-struct servent *getservbyname (const char *, const char *);
-struct servent *getservbyport (int, const char *);
-struct servent *getservent (void);
-void           herror (const char *);
-__const char   *hstrerror (int);
-int            innetgr (const char *, const char *, const char *,
-                               const char *);
-void           sethostent (int);
-/* void                sethostfile (const char *); */
-void           setnetent (int);
-void           setprotoent (int);
-int            getaddrinfo (const char *, const char *,
-                                const struct addrinfo *, struct addrinfo **);
-int            getnameinfo (const struct sockaddr *, socklen_t, char *,
-                                size_t, char *, size_t, int);
-void           freeaddrinfo (struct addrinfo *);
-const char     *gai_strerror (int);
-void           setnetgrent (const char *);
-void           setservent (int);
+void           endhostent(void);
+void           endnetent(void);
+void           endnetgrent(void);
+void           endprotoent(void);
+void           endservent(void);
+void           freehostent(struct hostent *);
+struct hostent *gethostbyaddr(const void *, socklen_t, int);
+int            gethostbyaddr_r(const void *, socklen_t, int, struct hostent *,
+                               char *, size_t, struct hostent **, int *);
+struct hostent *gethostbyname(const char *);
+int            gethostbyname_r(const char *, struct hostent *, char *, size_t,
+                               struct hostent **, int *);
+struct hostent *gethostbyname2(const char *, int);
+int            gethostbyname2_r(const char *, int, struct hostent *, char *,
+                                size_t, struct hostent **, int *);
+struct hostent *gethostent(void);
+int            gethostent_r(struct hostent *, char *, size_t,
+                            struct hostent **, int *);
+struct hostent *getipnodebyaddr(const void *, size_t, int, int *);
+struct hostent *getipnodebyname(const char *, int, int, int *);
+struct netent  *getnetbyaddr(uint32_t, int);
+int            getnetbyaddr_r(uint32_t, int, struct netent *, char *, size_t,
+                              struct netent**, int *);
+struct netent  *getnetbyname(const char *);
+int            getnetbyname_r(const char *, struct netent *, char *, size_t,
+                              struct netent **, int *);
+struct netent  *getnetent(void);
+int            getnetent_r(struct netent *, char *, size_t, struct netent **,
+                           int *);
+int            getnetgrent(char **, char **, char **);
+struct protoent        *getprotobyname(const char *);
+int            getprotobyname_r(const char *, struct protoent *, char *,
+                                size_t, struct protoent **);
+struct protoent        *getprotobynumber(int);
+int            getprotobynumber_r(int, struct protoent *, char *, size_t,
+                                  struct protoent **);
+struct protoent        *getprotoent(void);
+int            getprotoent_r(struct protoent *, char *, size_t,
+                             struct protoent **);
+struct servent *getservbyname(const char *, const char *);
+int            getservbyname_r(const char *, const char *, struct servent *,
+                               char *, size_t, struct servent **);
+struct servent *getservbyport(int, const char *);
+int            getservbyport_r(int, const char *, struct servent *, char *,
+                               size_t, struct servent **);
+struct servent *getservent(void);
+int            getservent_r(struct servent *, char *, size_t,
+                            struct servent **);
+void           herror(const char *);
+__const char   *hstrerror(int);
+int            innetgr(const char *, const char *, const char *, const char *);
+void           sethostent(int);
+/* void                sethostfile(const char *); */
+void           setnetent(int);
+void           setprotoent(int);
+int            getaddrinfo(const char *, const char *,
+                           const struct addrinfo *, struct addrinfo **);
+int            getnameinfo(const struct sockaddr *, socklen_t, char *,
+                           size_t, char *, size_t, int);
+void           freeaddrinfo(struct addrinfo *);
+const char     *gai_strerror(int);
+void           setnetgrent(const char *);
+void           setservent(int);
 
 /*
  * PRIVATE functions specific to the FreeBSD implementation
  */
 
 /* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */
-void   _sethosthtent (int);
-void   _endhosthtent (void);
-void   _sethostdnsent (int);
-void   _endhostdnsent (void);
-void   _setnethtent (int);
-void   _endnethtent (void);
-void   _setnetdnsent (int);
-void   _endnetdnsent (void);
-struct hostent * _gethostbynisname (const char *, int);
-struct hostent * _gethostbynisaddr (const char *, int, int);
-void _map_v4v6_address (const char *, char *);
-void _map_v4v6_hostent (struct hostent *, char **, int *);
+int    * __h_errno(void);
 __END_DECLS
 
 #endif /* !_NETDB_H_ */
diff --git a/include/res_update.h b/include/res_update.h
new file mode 100644 (file)
index 0000000..dfcadcd
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *     $Id: res_update.h,v 1.2.18.1 2005/04/27 05:00:49 sra Exp $
+ * $FreeBSD: src/include/res_update.h,v 1.3 2007/06/03 17:20:25 ume Exp $
+ */
+
+#ifndef __RES_UPDATE_H
+#define __RES_UPDATE_H
+
+/*! \file */
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+/*%
+ * This RR-like structure is particular to UPDATE.
+ */
+struct ns_updrec {
+       struct {
+               struct ns_updrec *prev;
+               struct ns_updrec *next;
+       } r_link, r_glink;
+       ns_sect         r_section;      /*%< ZONE/PREREQUISITE/UPDATE */
+       char *          r_dname;        /*%< owner of the RR */
+       ns_class        r_class;        /*%< class number */
+       ns_type         r_type;         /*%< type number */
+       u_int32_t       r_ttl;          /*%< time to live */
+       u_char *        r_data;         /*%< rdata fields as text string */
+       u_int           r_size;         /*%< size of r_data field */
+       int             r_opcode;       /*%< type of operation */
+       /* following fields for private use by the resolver/server routines */
+       struct databuf *r_dp;           /*%< databuf to process */
+       struct databuf *r_deldp;        /*%< databuf's deleted/overwritten */
+       u_int           r_zone;         /*%< zone number on server */
+};
+typedef struct ns_updrec ns_updrec;
+typedef struct {
+       ns_updrec *head;
+       ns_updrec *tail;
+} ns_updque;
+
+#define res_mkupdate           __res_mkupdate
+#define res_update             __res_update
+#define res_mkupdrec           __res_mkupdrec
+#define res_freeupdrec         __res_freeupdrec
+#define res_nmkupdate          __res_nmkupdate
+#define res_nupdate            __res_nupdate
+
+int            res_mkupdate(ns_updrec *, u_char *, int);
+int            res_update(ns_updrec *);
+ns_updrec *    res_mkupdrec(int, const char *, u_int, u_int, u_long);
+void           res_freeupdrec(ns_updrec *);
+int            res_nmkupdate(res_state, ns_updrec *, u_char *, int);
+int            res_nupdate(res_state, ns_updrec *, ns_tsig_key *);
+
+#endif /*__RES_UPDATE_H*/
index 4e74d16..ca97b5b 100644 (file)
@@ -1,6 +1,6 @@
-/*-
- * Copyright (c) 1983, 1987, 1989, 1993
- *     The Regents of the University of California.  All rights reserved.
+/*
+ * Copyright (c) 1983, 1987, 1989
+ *    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
  */
 
 /*
- * Portions Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 /*
  *     @(#)resolv.h    8.1 (Berkeley) 6/2/93
- *     From Id: resolv.h,v 8.12 1998/04/28 19:36:46 halley Exp $
- * $FreeBSD: src/include/resolv.h,v 1.19.2.1 2001/06/15 22:08:26 ume Exp $
+ *     $Id: resolv.h,v 1.19.18.4 2008/04/03 23:15:15 marka Exp $
+ * $FreeBSD: src/include/resolv.h,v 1.33 2008/12/14 19:39:53 ume Exp $
  * $DragonFly: src/include/resolv.h,v 1.4 2004/02/26 13:58:25 joerg Exp $
  */
 
@@ -63,6 +63,7 @@
 #include <sys/cdefs.h>
 #include <sys/socket.h>
 #include <stdio.h>
+#include <arpa/nameser.h>
 
 /*
  * Revision information.  This is the release date in YYYYMMDD format.
  * is new enough to contain a certain feature.
  */
 
-#define        __RES   19960801
+#define        __RES   20030124
 
 /*
+ * This used to be defined in res_query.c, now it's in herror.c.
+ * [XXX no it's not.  It's in irs/irs_data.c]
+ * It was
+ * never extern'd by any *.h file before it was placed here.  For thread
+ * aware programs, the last h_errno value set is stored in res->h_errno.
+ *
+ * XXX:        There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO
+ *     (and __h_errno_set) to the public via <resolv.h>.
+ * XXX:        __h_errno_set is really part of IRS, not part of the resolver.
+ *     If somebody wants to build and use a resolver that doesn't use IRS,
+ *     what do they do?  Perhaps something like
+ *             #ifdef WANT_IRS
+ *             # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x)
+ *             #else
+ *             # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x))
+ *             #endif
+ */
+
+#define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x)
+struct __res_state; /*%< forward */
+__BEGIN_DECLS
+void __h_errno_set(struct __res_state *, int);
+__END_DECLS
+
+/*%
  * Resolver configuration file.
  * Normally not present, but may contain the address of the
- * inital name server(s) to query and the domain search list.
+ * initial name server(s) to query and the domain search list.
  */
 
 #ifndef _PATH_RESCONF
 #define        _PATH_RESCONF        "/etc/resolv.conf"
 #endif
 
+typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
+       res_sendhookact;
+
+typedef res_sendhookact (*res_send_qhook)(struct sockaddr * const *,
+                                         const u_char **, int *,
+                                         u_char *, int, int *);
+
+typedef res_sendhookact (*res_send_rhook)(const struct sockaddr *,
+                                         const u_char *, int, u_char *,
+                                         int, int *);
+
+struct res_sym {
+       int             number;     /* Identifying number, like T_MX */
+       const char      *name;      /* Its symbolic name, like "MX" */
+       const char      *humanname; /* Its fun name, like "mail exchanger" */
+};
+
 /*
  * Global defines and variables for resolver stub.
  */
 #define        MAXDFLSRCH              3       /* # default domain levels to try */
 #define        MAXDNSRCH               6       /* max # domains in search path */
 #define        LOCALDOMAINPARTS        2       /* min levels in name that is "local" */
-
 #define        RES_TIMEOUT             5       /* min. seconds between retries */
 #define        MAXRESOLVSORT           10      /* number of net to sort on */
 #define        RES_MAXNDOTS            15      /* should reflect bit field size */
+#define        RES_MAXRETRANS          30      /* only for resolv.conf/RES_OPTIONS */
+#define        RES_MAXRETRY            5       /* only for resolv.conf/RES_OPTIONS */
+#define        RES_DFLRETRY            2       /* Default #/tries. */
+#define        RES_MAXTIME             65535   /* Infinity, in milliseconds. */
+struct __res_state_ext;
 
 struct __res_state {
-       int     retrans;                /* retransmition time interval */
+       int     retrans;                /* retransmission time interval */
        int     retry;                  /* number of times to retransmit */
        u_long  options;                /* option flags - see below. */
        int     nscount;                /* number of name servers */
@@ -115,23 +162,54 @@ struct __res_state {
                struct in_addr  addr;
                u_int32_t       mask;
        } sort_list[MAXRESOLVSORT];
-       char    pad[72];                /* on an i386 this means 512b total */
+       res_send_qhook qhook;           /* query hook */
+       res_send_rhook rhook;           /* response hook */
+       int     res_h_errno;            /* last one set for this context */
+       int     _vcsock;                /* PRIVATE: for res_send VC i/o */
+       u_int   _flags;                 /* PRIVATE: see below */
+       u_int   _pad;                   /* make _u 64 bit aligned */
+       union {
+               /* On an 32-bit arch this means 512b total. */
+               char    pad[72 - 4*sizeof (int) - 2*sizeof (void *)];
+               struct {
+                       u_int16_t               nscount;
+                       u_int16_t               nstimes[MAXNS]; /* ms. */
+                       int                     nssocks[MAXNS];
+                       struct __res_state_ext *ext;    /* extention for IPv6 */
+               } _ext;
+       } _u;
+};
+
+typedef struct __res_state *res_state;
+
+union res_sockaddr_union {
+       struct sockaddr_in      sin;
+#ifdef IN6ADDR_ANY_INIT
+       struct sockaddr_in6     sin6;
+#endif
+#ifdef ISC_ALIGN64
+       int64_t                 __align64;      /* 64bit alignment */
+#else
+       int32_t                 __align32;      /* 32bit alignment */
+#endif
+       char                    __space[128];   /* max size */
 };
 
-/* for INET6 */
 /*
- * replacement of __res_state, separated to keep binary compatibility.
+ * Resolver flags (used to be discrete per-module statics ints).
  */
-struct __res_state_ext {
-       struct sockaddr_storage nsaddr_list[MAXNS];
-       struct {
-               int     af;             /* address family for addr, mask */
-               union {
-                       struct  in_addr ina;
-                       struct  in6_addr in6a;
-               } addr, mask;
-       } sort_list[MAXRESOLVSORT];
-};
+#define        RES_F_VC        0x00000001      /* socket is TCP */
+#define        RES_F_CONN      0x00000002      /* socket is connected */
+#define        RES_F_EDNS0ERR  0x00000004      /* EDNS0 caused errors */
+#define        RES_F__UNUSED   0x00000008      /* (unused) */
+#define        RES_F_LASTMASK  0x000000F0      /* ordinal server of last res_nsend */
+#define        RES_F_LASTSHIFT 4               /* bit position of LASTMASK "flag" */
+#define        RES_GETLAST(res) (((res)._flags & RES_F_LASTMASK) >> RES_F_LASTSHIFT)
+
+/* res_findzonecut2() options */
+#define        RES_EXHAUSTIVE  0x00000001      /* always do all queries */
+#define        RES_IPV4ONLY    0x00000002      /* IPv4 only */
+#define        RES_IPV6ONLY    0x00000004      /* IPv6 only */
 
 /*
  * Resolver options (keep these in synch with res_debug.c, please)
@@ -150,11 +228,21 @@ struct __res_state_ext {
 #define        RES_INSECURE2   0x00000800      /* type 2 security disabled */
 #define        RES_NOALIASES   0x00001000      /* shuts off HOSTALIASES feature */
 #define        RES_USE_INET6   0x00002000      /* use/map IPv6 in gethostbyname() */
-#define        RES_NOTLDQUERY  0x00004000      /* Don't query TLD names */
+#define RES_ROTATE     0x00004000      /* rotate ns list after each query */
+#define        RES_NOCHECKNAME 0x00008000      /* do not check names for sanity. */
+#define        RES_KEEPTSIG    0x00010000      /* do not strip TSIG records */
+#define        RES_BLAST       0x00020000      /* blast all recursive servers */
+#define RES_NSID       0x00040000      /* request name server ID */
+#define RES_NOTLDQUERY 0x00100000      /* don't unqualified name as a tld */
+#define RES_USE_DNSSEC 0x00200000      /* use DNSSEC using OK bit in OPT */
+/* #define RES_DEBUG2  0x00400000 */   /* nslookup internal */
 /* KAME extensions: use higher bit to avoid conflict with ISC use */
-#define        RES_USE_EDNS0   0x40000000      /* use EDNS0 */
+#define RES_USE_DNAME  0x10000000      /* use DNAME */
+#define RES_USE_EDNS0  0x40000000      /* use EDNS0 if configured */
+#define RES_NO_NIBBLE2 0x80000000      /* disable alternate nibble lookup */
 
-#define RES_DEFAULT    (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+#define RES_DEFAULT    (RES_RECURSE | RES_DEFNAMES | \
+                        RES_DNSRCH | RES_NO_NIBBLE2)
 
 /*
  * Resolver "pfcode" values.  Used by dig.
@@ -173,84 +261,143 @@ struct __res_state_ext {
 #define        RES_PRF_HEADX   0x00000800
 #define        RES_PRF_QUERY   0x00001000
 #define        RES_PRF_REPLY   0x00002000
-#define        RES_PRF_INIT    0x00004000
-/*                     0x00008000      */
+#define        RES_PRF_INIT    0x00004000
+#define        RES_PRF_TRUNC   0x00008000
+/*                     0x00010000      */
 
-typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
-       res_sendhookact;
-
-typedef res_sendhookact (*res_send_qhook)(struct sockaddr_in * const *,
-                                         const u_char **, int *,
-                                         u_char *, int, int *);
-
-typedef res_sendhookact (*res_send_rhook)(const struct sockaddr_in *,
-                                         const u_char *, int,
-                                         u_char *, int, int *);
+/* Things involving an internal (static) resolver context. */
+__BEGIN_DECLS
+extern struct __res_state *__res_state(void);
+__END_DECLS
+#define _res (*__res_state())
 
-struct res_sym {
-       int     number;         /* Identifying number, like T_MX */
-       char *  name;           /* Its symbolic name, like "MX" */
-       char *  humanname;      /* Its fun name, like "mail exchanger" */
-};
+#ifndef __BIND_NOSTATIC
+#define fp_nquery              __fp_nquery
+#define fp_query               __fp_query
+#define hostalias              __hostalias
+#define p_query                        __p_query
+#define res_close              __res_close
+#define res_init               __res_init
+#define res_isourserver                __res_isourserver
+#define res_mkquery            __res_mkquery
+#define res_opt                        __res_opt
+#define res_query              __res_query
+#define res_querydomain                __res_querydomain
+#define res_search             __res_search
+#define res_send               __res_send
+#define res_sendsigned         __res_sendsigned
 
-extern struct __res_state _res;
-/* for INET6 */
-extern struct __res_state_ext _res_ext;
+__BEGIN_DECLS
+void           fp_nquery(const u_char *, int, FILE *);
+void           fp_query(const u_char *, FILE *);
+const char     *hostalias(const char *);
+void           p_query(const u_char *);
+void           res_close(void);
+int            res_init(void);
+int            res_isourserver(const struct sockaddr_in *);
+int            res_mkquery(int, const char *, int, int, const u_char *,
+                           int, const u_char *, u_char *, int);
+int            res_opt(int, u_char *, int, int);
+int            res_query(const char *, int, int, u_char *, int);
+int            res_querydomain(const char *, const char *, int, int,
+                               u_char *, int);
+int            res_search(const char *, int, int, u_char *, int);
+int            res_send(const u_char *, int, u_char *, int);
+int            res_sendsigned(const u_char *, int, ns_tsig_key *,
+                              u_char *, int);
+__END_DECLS
+#endif
 
+#if !defined(SHARED_LIBBIND) || defined(LIB)
+/*
+ * If libbind is a shared object (well, DLL anyway)
+ * these externs break the linker when resolv.h is
+ * included by a lib client (like named)
+ * Make them go away if a client is including this
+ *
+ */
+extern const struct res_sym __p_key_syms[];
+extern const struct res_sym __p_cert_syms[];
 extern const struct res_sym __p_class_syms[];
 extern const struct res_sym __p_type_syms[];
+extern const struct res_sym __p_rcode_syms[];
+#endif /* SHARED_LIBBIND */
 
-/* Private routines shared between libc/net, named, nslookup and others. */
-#define        res_hnok        __res_hnok
-#define        res_ownok       __res_ownok
-#define        res_mailok      __res_mailok
-#define        res_dnok        __res_dnok
-#define        sym_ston        __sym_ston
-#define        sym_ntos        __sym_ntos
-#define        sym_ntop        __sym_ntop
-#define        b64_ntop        __b64_ntop
-#define        b64_pton        __b64_pton
-#define        loc_ntoa        __loc_ntoa
-#define        loc_aton        __loc_aton
-#define        fp_resstat      __fp_resstat
-#define        p_query         __p_query
-#define        dn_skipname     __dn_skipname
-#define        fp_resstat      __fp_resstat
-#define        fp_query        __fp_query
-#define        fp_nquery       __fp_nquery
-#define        hostalias       __hostalias
-#define        putlong         __putlong
-#define        putshort        __putshort
-#define        p_class         __p_class
-#define        p_time          __p_time
-#define        p_type          __p_type
-#define        p_query         __p_query
-#define        p_cdnname       __p_cdnname
-#define        p_section       __p_section
-#define        p_cdname        __p_cdname
-#define        p_fqnname       __p_fqnname
-#define        p_fqname        __p_fqname
-#define        p_option        __p_option
-#define        p_secstodate    __p_secstodate
-#define        dn_count_labels __dn_count_labels
-#define        dn_comp         __dn_comp
-#define        dn_expand       __dn_expand
-#define        res_init        __res_init
-#define        res_randomid    __res_randomid
-#define        res_query       __res_query
-#define        res_search      __res_search
-#define        res_querydomain __res_querydomain
-#define        res_mkquery     __res_mkquery
-#define        res_send        __res_send
-#define        res_isourserver __res_isourserver
-#define        res_nameinquery __res_nameinquery
-#define        res_queriesmatch __res_queriesmatch
-#define        res_close       __res_close
-#define        res_opt         __res_opt
-#define        res_mkupdate    __res_mkupdate
-#define        res_mkupdrec    __res_mkupdrec
-#define        res_freeupdrec  __res_freeupdrec
-
+#define b64_ntop               __b64_ntop
+#define b64_pton               __b64_pton
+#define dn_comp                        __dn_comp
+#define dn_count_labels                __dn_count_labels
+#define dn_expand              __dn_expand
+#define dn_skipname            __dn_skipname
+#define fp_resstat             __fp_resstat
+#define loc_aton               __loc_aton
+#define loc_ntoa               __loc_ntoa
+#define p_cdname               __p_cdname
+#define p_cdnname              __p_cdnname
+#define p_class                        __p_class
+#define p_fqname               __p_fqname
+#define p_fqnname              __p_fqnname
+#define p_option               __p_option
+#define p_secstodate           __p_secstodate
+#define p_section              __p_section
+#define p_time                 __p_time
+#define p_type                 __p_type
+#define p_rcode                        __p_rcode
+#define p_sockun               __p_sockun
+#define putlong                        __putlong
+#define putshort               __putshort
+#define res_dnok               __res_dnok
+#if 0
+#define res_findzonecut                __res_findzonecut
+#endif
+#define res_findzonecut2       __res_findzonecut2
+#define res_hnok               __res_hnok
+#define res_hostalias          __res_hostalias
+#define res_mailok             __res_mailok
+#define res_nameinquery                __res_nameinquery
+#define res_nclose             __res_nclose
+#define res_ninit              __res_ninit
+#define res_nmkquery           __res_nmkquery
+#define res_pquery             __res_pquery
+#define res_nquery             __res_nquery
+#define res_nquerydomain       __res_nquerydomain
+#define res_nsearch            __res_nsearch
+#define res_nsend              __res_nsend
+#if 0
+#define res_nsendsigned                __res_nsendsigned
+#endif
+#define res_nisourserver       __res_nisourserver
+#define res_ownok              __res_ownok
+#define res_queriesmatch       __res_queriesmatch
+#define res_randomid           __res_randomid
+#define sym_ntop               __sym_ntop
+#define sym_ntos               __sym_ntos
+#define sym_ston               __sym_ston
+#define res_nopt               __res_nopt
+#define res_nopt_rdata         __res_nopt_rdata
+#define res_ndestroy           __res_ndestroy
+#define        res_nametoclass         __res_nametoclass
+#define        res_nametotype          __res_nametotype
+#define        res_setservers          __res_setservers
+#define        res_getservers          __res_getservers
+#if 0
+#define        res_buildprotolist      __res_buildprotolist
+#define        res_destroyprotolist    __res_destroyprotolist
+#define        res_destroyservicelist  __res_destroyservicelist
+#define        res_get_nibblesuffix    __res_get_nibblesuffix
+#define        res_get_nibblesuffix2   __res_get_nibblesuffix2
+#endif
+#define        res_ourserver_p         __res_ourserver_p
+#if 0
+#define        res_protocolname        __res_protocolname
+#define        res_protocolnumber      __res_protocolnumber
+#endif
+#define        res_send_setqhook       __res_send_setqhook
+#define        res_send_setrhook       __res_send_setrhook
+#if 0
+#define        res_servicename         __res_servicename
+#define        res_servicenumber       __res_servicenumber
+#endif
 __BEGIN_DECLS
 int             res_hnok(const char *);
 int             res_ownok(const char *);
@@ -264,52 +411,76 @@ int                b64_pton(char const *, u_char *, size_t);
 int             loc_aton(const char *, u_char *);
 const char     *loc_ntoa(const u_char *, char *);
 int             dn_skipname(const u_char *, const u_char *);
-void            fp_resstat(struct __res_state *, FILE *);
-void            fp_query(const u_char *, FILE *);
-void            fp_nquery(const u_char *, int, FILE *);
-const char     *hostalias(const char *);
 void            putlong(u_int32_t, u_char *);
 void            putshort(u_int16_t, u_char *);
+u_int16_t      _getshort(const u_char *);
+u_int32_t      _getlong(const u_char *);
 const char     *p_class(int);
 const char     *p_time(u_int32_t);
 const char     *p_type(int);
-void            p_query(const u_char *);
+const char     *p_rcode(int);
+const char     *p_sockun(union res_sockaddr_union, char *, size_t);
 const u_char   *p_cdnname(const u_char *, const u_char *, int, FILE *);
 const u_char   *p_cdname(const u_char *, const u_char *, FILE *);
-const u_char   *p_fqnname(const u_char *, const u_char *,
-                          int, char *, int);
+const u_char   *p_fqnname(const u_char *, const u_char *, int, char *, int);
 const u_char   *p_fqname(const u_char *, const u_char *, FILE *);
 const char     *p_option(u_long);
 char           *p_secstodate(u_long);
 int             dn_count_labels(const char *);
-int             dn_comp(const char *, u_char *, int,
-                        u_char **, u_char **);
+int             dn_comp(const char *, u_char *, int, u_char **, u_char **);
 int             dn_expand(const u_char *, const u_char *, const u_char *,
                           char *, int);
-int             res_init(void);
 u_int           res_randomid(void);
-int             res_query(const char *, int, int, u_char *, int);
-int             res_search(const char *, int, int, u_char *, int);
-int             res_querydomain(const char *, const char *, int, int,
-                                u_char *, int);
-int             res_mkquery(int, const char *, int, int, const u_char *,
-                            int, const u_char *, u_char *, int);
-int             res_send(const u_char *, int, u_char *, int);
-int             res_isourserver(const struct sockaddr_in *);
-int             res_nameinquery(const char *, int, int,
-                                const u_char *, const u_char *);
+int             res_nameinquery(const char *, int, int, const u_char *,
+                                const u_char *);
 int             res_queriesmatch(const u_char *, const u_char *,
                                  const u_char *, const u_char *);
-void            res_close(void);
-int             res_opt(int, u_char *, int, int);
 const char     *p_section(int, int);
-/* XXX The following depend on the ns_updrec typedef in arpa/nameser.h */
-#ifdef _ARPA_NAMESER_H_
-int             res_update(ns_updrec *);
-int             res_mkupdate(ns_updrec *, u_char *, int);
-ns_updrec      *res_mkupdrec(int, const char *, u_int, u_int, u_long);
-void            res_freeupdrec(ns_updrec *);
+/* Things involving a resolver context. */
+int             res_ninit(res_state);
+int             res_nisourserver(const res_state, const struct sockaddr_in *);
+void            fp_resstat(const res_state, FILE *);
+void            res_pquery(const res_state, const u_char *, int, FILE *);
+const char     *res_hostalias(const res_state, const char *, char *, size_t);
+int             res_nquery(res_state, const char *, int, int, u_char *, int);
+int             res_nsearch(res_state, const char *, int, int, u_char *, int);
+int             res_nquerydomain(res_state, const char *, const char *,
+                                 int, int, u_char *, int);
+int             res_nmkquery(res_state, int, const char *, int, int,
+                             const u_char *, int, const u_char *,
+                             u_char *, int);
+int             res_nsend(res_state, const u_char *, int, u_char *, int);
+#if 0
+int             res_nsendsigned(res_state, const u_char *, int,
+                                ns_tsig_key *, u_char *, int);
+int             res_findzonecut(res_state, const char *, ns_class, int,
+                                char *, size_t, struct in_addr *, int);
+#endif
+int             res_findzonecut2(res_state, const char *, ns_class, int,
+                                 char *, size_t,
+                                 union res_sockaddr_union *, int);
+void            res_nclose(res_state);
+int             res_nopt(res_state, int, u_char *, int, int);
+int             res_nopt_rdata(res_state, int, u_char *, int, u_char *,
+                               u_short, u_short, u_char *);
+void            res_send_setqhook(res_send_qhook);
+void            res_send_setrhook(res_send_rhook);
+int             __res_vinit(res_state, int);
+#if 0
+void            res_destroyservicelist(void);
+const char     *res_servicename(u_int16_t, const char *);
+const char     *res_protocolname(int);
+void            res_destroyprotolist(void);
+void            res_buildprotolist(void);
+const char     *res_get_nibblesuffix(res_state);
+const char     *res_get_nibblesuffix2(res_state);
 #endif
+void            res_ndestroy(res_state);
+u_int16_t       res_nametoclass(const char *, int *);
+u_int16_t       res_nametotype(const char *, int *);
+void            res_setservers(res_state, const union res_sockaddr_union *,
+                               int);
+int             res_getservers(res_state, union res_sockaddr_union *, int);
 __END_DECLS
 
 #endif /* !_RESOLV_H_ */
index 1e6f019..bfc7ade 100644 (file)
@@ -33,6 +33,7 @@ NOASM=
 .include "${.CURDIR}/../libc/quad/Makefile.inc"
 .endif
 .include "${.CURDIR}/../libc/regex/Makefile.inc"
+.include "${.CURDIR}/../libc/resolv/Makefile.inc"
 .include "${.CURDIR}/../libc/stdio/Makefile.inc"
 .include "${.CURDIR}/../libc/stdlib/Makefile.inc"
 .include "${.CURDIR}/../libc/stdtime/Makefile.inc"
diff --git a/lib/libc/include/isc/platform.h b/lib/libc/include/isc/platform.h
new file mode 100644 (file)
index 0000000..1c9f634
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h.in,v 1.2.6.2 2008/01/23 02:15:02 tbox Exp $ */
+/* $FreeBSD: src/lib/libc/include/isc/platform.h,v 1.1 2008/12/14 19:39:53 ume Exp $ */
+
+/*! \file */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H
+
+/*
+ * Define if the OS does not define struct timespec.
+ */
+#undef ISC_PLATFORM_NEEDTIMESPEC
+#ifdef ISC_PLATFORM_NEEDTIMESPEC
+#include <time.h>               /* For time_t */
+struct timespec {
+       time_t  tv_sec;         /* seconds */
+       long    tv_nsec;        /* nanoseconds */
+};
+#endif
+
+#endif
diff --git a/lib/libc/include/port_after.h b/lib/libc/include/port_after.h
new file mode 100644 (file)
index 0000000..068916b
--- /dev/null
@@ -0,0 +1,11 @@
+/* $FreeBSD: src/lib/libc/include/port_after.h,v 1.2 2006/03/21 18:31:24 ume Exp $ */
+
+#ifndef _PORT_AFTER_H_
+#define _PORT_AFTER_H_
+
+#define HAVE_SA_LEN            1
+#define HAS_INET6_STRUCTS      1
+#define HAVE_SIN6_SCOPE_ID     1
+#define HAVE_TIME_R            1
+
+#endif /* _PORT_AFTER_H_ */
diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h
new file mode 100644 (file)
index 0000000..9bd1289
--- /dev/null
@@ -0,0 +1,22 @@
+/* $FreeBSD: src/lib/libc/include/port_before.h,v 1.1 2006/03/21 15:37:15 ume Exp $ */
+
+#ifndef _PORT_BEFORE_H_
+#define _PORT_BEFORE_H_
+
+#define _LIBC          1
+#define DO_PTHREADS    1
+#define USE_KQUEUE     1
+
+#define ISC_SOCKLEN_T  socklen_t
+#define ISC_FORMAT_PRINTF(fmt, args) \
+       __attribute__((__format__(__printf__, fmt, args)))
+#define DE_CONST(konst, var) \
+        do { \
+                union { const void *k; void *v; } _u; \
+                _u.k = konst; \
+                var = _u.v; \
+        } while (0)
+
+#define UNUSED(x) (x) = (x)
+
+#endif /* _PORT_BEFORE_H_ */
index 7b88378..fa1f3a8 100644 (file)
@@ -5,22 +5,21 @@
 # machine-independent net sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/net ${.CURDIR}/../libc/net
 
-SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c eui64.c getaddrinfo.c \
+SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c eui64.c \
+       gai_strerror.c getaddrinfo.c \
        gethostbydns.c gethostbyht.c gethostbynis.c gethostnamadr.c \
        getifaddrs.c getnameinfo.c \
        getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \
        getproto.c getprotoent.c getprotoname.c \
-       getservent.c herror.c inet_addr.c \
-       if_indextoname.c if_nameindex.c if_nametoindex.c inet_lnaof.c \
-       inet_makeaddr.c inet_net_ntop.c inet_net_pton.c inet_neta.c \
-       inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
-       inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
+       getservent.c \
+       if_indextoname.c if_nameindex.c if_nametoindex.c \
+       ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
        ns_name.c ns_netint.c \
        ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
        nsdispatch.c nslexer.c nsparser.y nss_compat.c \
        rcmd.c rcmdsh.c recv.c res_comp.c res_data.c res_debug.c \
-       res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
-       res_update.c rthdr.c send.c vars.c
+       res_init.c res_mkquery.c res_query.c res_send.c \
+       rthdr.c send.c vars.c
 # not supported: iso_addr.c 
 
 # This isn't ready yet.
diff --git a/lib/libc/net/gai_strerror.c b/lib/libc/net/gai_strerror.c
new file mode 100644 (file)
index 0000000..cced091
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project 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 PROJECT 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
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/gai_strerror.c,v 1.2 2006/05/21 11:22:31 ume Exp $
+ */
+
+#include <netdb.h>
+
+/* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) are obsoleted, but left */
+/* for backward compatibility with userland code prior to 2553bis-02 */
+static const char *ai_errlist[] = {
+       "Success",                                      /* 0 */
+       "Address family for hostname not supported",    /* 1 */
+       "Temporary failure in name resolution",         /* EAI_AGAIN */
+       "Invalid value for ai_flags",                   /* EAI_BADFLAGS */
+       "Non-recoverable failure in name resolution",   /* EAI_FAIL */
+       "ai_family not supported",                      /* EAI_FAMILY */
+       "Memory allocation failure",                    /* EAI_MEMORY */
+       "No address associated with hostname",          /* 7 */
+       "hostname nor servname provided, or not known", /* EAI_NONAME */
+       "servname not supported for ai_socktype",       /* EAI_SERVICE */
+       "ai_socktype not supported",                    /* EAI_SOCKTYPE */
+       "System error returned in errno",               /* EAI_SYSTEM */
+       "Invalid value for hints",                      /* EAI_BADHINTS */
+       "Resolved protocol is unknown",                 /* EAI_PROTOCOL */
+       "Argument buffer overflow"                      /* EAI_OVERFLOW */
+};
+
+const char *
+gai_strerror(int ecode)
+{
+       if (ecode >= 0 && ecode < EAI_MAX)
+               return ai_errlist[ecode];
+       return "Unknown error";
+}
index 9732e2c..b7ada3b 100644 (file)
@@ -1,7 +1,5 @@
 .\"    $KAME: getaddrinfo.3,v 1.36 2005/01/05 03:23:05 itojun Exp $
 .\"    $OpenBSD: getaddrinfo.3,v 1.35 2004/12/21 03:40:31 jaredy Exp $
-.\"    $FreeBSD: src/lib/libc/net/getaddrinfo.3,v 1.29 2005/01/23 16:02:48 gnn Exp $
-.\"    $DragonFly: src/lib/libc/net/getaddrinfo.3,v 1.7 2008/05/22 06:50:14 hasso Exp $
 .\"
 .\" Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
 .\" Copyright (C) 2000, 2001  Internet Software Consortium.
 .\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 .\" PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd May 22, 2008
+.\" $FreeBSD: src/lib/libc/net/getaddrinfo.3,v 1.34 2008/07/01 22:59:20 danger Exp $
+.\" $DragonFly: src/lib/libc/net/getaddrinfo.3,v 1.7 2008/05/22 06:50:14 hasso Exp $
+.\"
+.Dd July 1, 2008
 .Dt GETADDRINFO 3
 .Os
 .Sh NAME
 .In sys/socket.h
 .In netdb.h
 .Ft int
-.Fn getaddrinfo "const char *hostname" "const char *servname" \
-    "const struct addrinfo *hints" "struct addrinfo **res"
+.Fo getaddrinfo
+.Fa "const char *hostname" "const char *servname"
+.Fa "const struct addrinfo *hints" "struct addrinfo **res"
+.Fc
 .Ft void
 .Fn freeaddrinfo "struct addrinfo *ai"
 .Sh DESCRIPTION
@@ -119,10 +122,20 @@ If
 .Fa ai_protocol
 is zero the caller will accept any protocol.
 .It Fa ai_flags
+The
 .Fa ai_flags
-is formed by
-.Tn OR Ns 'ing
-the following values:
+field to which the
+.Fa hints
+parameter points shall be set to zero
+or be the bitwise-inclusive OR of one or more of the values
+.Dv AI_ADDRCONFIG ,
+.Dv AI_ALL ,
+.Dv AI_CANONNAME ,
+.Dv AI_NUMERICHOST ,
+.Dv AI_NUMERICSERV ,
+.Dv AI_PASSIVE ,
+and
+.Dv AI_V4MAPPED .
 .Bl -tag -width "AI_CANONNAMEXX"
 .It Dv AI_ADDRCONFIG
 If the
@@ -227,6 +240,11 @@ flag shall be ignored unless
 .Fa ai_family
 equals
 .Dv AF_INET6 .
+Note: this flag is currently
+.Em not
+supported, see the
+.Sx BUGS
+section.
 .El
 .El
 .Pp
@@ -475,15 +493,23 @@ freeaddrinfo(res0);
 .%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
 .%D June 2000
 .Re
+.Sh BUGS
+The
+.Nm
+function as implemented in
+.Dx
+currently does not support
+.Dv AI_ALL
+and
+.Dv AI_V4MAPPED
+flags and returns
+.Dv EAI_BADFLAGS
+if one of them is specified.
 .Sh STANDARDS
 The
 .Fn getaddrinfo
 function is defined by the
-.St -p1003.1g-2000
-draft specification and documented in
+.St -p1003.1-2004
+specification and documented in
 .Dv "RFC 3493" ,
 .Dq Basic Socket Interface Extensions for IPv6 .
-.Sh BUGS
-The implementation of
-.Fn getaddrinfo
-is not thread-safe.
index cde711c..7b64c10 100644 (file)
@@ -1,4 +1,4 @@
-/*     $FreeBSD: src/lib/libc/net/getaddrinfo.c,v 1.9.2.14 2002/11/08 17:49:31 ume Exp $       */
+/*     $FreeBSD: src/lib/libc/net/getaddrinfo.c,v 1.87 2008/02/03 19:07:55 ume Exp $   */
 /*     $DragonFly: src/lib/libc/net/getaddrinfo.c,v 1.9 2008/10/04 22:38:42 swildner Exp $     */
 /*     $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $    */
 
@@ -35,7 +35,6 @@
  * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
  *
  * Issues to be discussed:
- * - Thread safe-ness must be checked.
  * - Return values.  There are nonstandard return values defined and used
  *   in the source code.  This is because RFC2553 is silent about which error
  *   code must be returned for which situation.
  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
  *   non-loopback address configured?  global address configured?
  *
- * OS specific notes for netbsd/openbsd/freebsd4/bsdi4:
- * - To avoid search order issue, we have a big amount of code duplicate
- *   from gethnamaddr.c and some other places.  The issues that there's no
- *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
- *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
- *   presented above.
- *
  * OS specific notes for freebsd4:
  * - FreeBSD supported $GAI.  The code does not.
- * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not.
  */
 
 #include "namespace.h"
 #include <sys/socket.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#include <sys/queue.h>
+#ifdef INET6
+#include <net/if_var.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <netinet6/in6_var.h>  /* XXX */
+#endif
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
 #include <netdb.h>
 #include <resolv.h>
 #include <string.h>
@@ -116,10 +117,18 @@ static const char in6_loopback[] = {
 };
 #endif
 
+struct policyqueue {
+       TAILQ_ENTRY(policyqueue) pc_entry;
+#ifdef INET6
+       struct in6_addrpolicy pc_policy;
+#endif
+};
+TAILQ_HEAD(policyhead, policyqueue);
+
 static const struct afd {
        int a_af;
        int a_addrlen;
-       int a_socklen;
+       socklen_t a_socklen;
        int a_off;
        const char *a_addrany;
        const char *a_loopback;
@@ -177,19 +186,29 @@ static const struct explore explore[] = {
 #define PTON_MAX       4
 #endif
 
+#define AIO_SRCFLAG_DEPRECATED 0x1
+
+struct ai_order {
+       union {
+               struct sockaddr_storage aiou_ss;
+               struct sockaddr aiou_sa;
+       } aio_src_un;
+#define aio_srcsa aio_src_un.aiou_sa
+       u_int32_t aio_srcflag;
+       int aio_srcscope;
+       int aio_dstscope;
+       struct policyqueue *aio_srcpolicy;
+       struct policyqueue *aio_dstpolicy;
+       struct addrinfo *aio_ai;
+       int aio_matchlen;
+};
+
 static const ns_src default_dns_files[] = {
        { NSSRC_FILES,  NS_SUCCESS },
        { NSSRC_DNS,    NS_SUCCESS },
        { 0 }
 };
 
-#define MAXPACKET      (64*1024)
-
-typedef union {
-       HEADER hdr;
-       u_char buf[MAXPACKET];
-} querybuf;
-
 struct res_target {
        struct res_target *next;
        const char *name;       /* domain name */
@@ -199,81 +218,72 @@ struct res_target {
        int n;                  /* result length */
 };
 
-static int str2number (const char *);
-static int explore_fqdn (const struct addrinfo *, const char *,
-       const char *, struct addrinfo **);
-static int explore_null (const struct addrinfo *,
-       const char *, struct addrinfo **);
-static int explore_numeric (const struct addrinfo *, const char *,
-       const char *, struct addrinfo **);
-static int explore_numeric_scope (const struct addrinfo *, const char *,
-       const char *, struct addrinfo **);
-static int get_canonname (const struct addrinfo *,
-       struct addrinfo *, const char *);
-static struct addrinfo *get_ai (const struct addrinfo *,
-       const struct afd *, const char *);
-static int get_portmatch (const struct addrinfo *, const char *);
-static int get_port (struct addrinfo *, const char *, int);
-static const struct afd *find_afd (int);
-static int addrconfig (struct addrinfo *);
+#define MAXPACKET      (64*1024)
+
+typedef union {
+       HEADER hdr;
+       u_char buf[MAXPACKET];
+} querybuf;
+
+static int     str2number(const char *, int *);
+static int     explore_null(const struct addrinfo *,
+                            const char *, struct addrinfo **);
+static int     explore_numeric(const struct addrinfo *, const char *,
+                               const char *, struct addrinfo **, const char *);
+static int     explore_numeric_scope(const struct addrinfo *, const char *,
+                                     const char *, struct addrinfo **);
+static int     get_canonname(const struct addrinfo *,
+                             struct addrinfo *, const char *);
+static struct  addrinfo *get_ai(const struct addrinfo *,
+                                const struct afd *, const char *);
+static int     get_portmatch(const struct addrinfo *, const char *);
+static int     get_port(struct addrinfo *, const char *, int);
+static const struct afd *find_afd(int);
+static int     addrconfig(struct addrinfo *);
+static void    set_source(struct ai_order *, struct policyhead *);
+static int     comp_dst(const void *, const void *);
 #ifdef INET6
-static int ip6_str2scopeid (char *, struct sockaddr_in6 *, u_int32_t *);
+static int     ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
 #endif
+static int     gai_addr2scopetype(struct sockaddr *);
+
+static int     explore_fqdn(const struct addrinfo *, const char *,
+                            const char *, struct addrinfo **);
 
-static struct addrinfo *getanswer (const querybuf *, int, const char *,
-       int, const struct addrinfo *);
-static int _dns_getaddrinfo (void *, void *, va_list);
-static void _sethtent (void);
-static void _endhtent (void);
-static struct addrinfo *_gethtent (const char *, const struct addrinfo *);
-static int _files_getaddrinfo (void *, void *, va_list);
+static int     reorder(struct addrinfo *);
+static int     get_addrselectpolicy(struct policyhead *);
+static void    free_addrselectpolicy(struct policyhead *);
+static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
+                                                 struct policyhead *);
+static int     matchlen(struct sockaddr *, struct sockaddr *);
+
+static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
+                                 const struct addrinfo *, res_state);
+#if defined(RESOLVSORT)
+static int     addr4sort(struct addrinfo *, res_state);
+#endif
+static int     _dns_getaddrinfo(void *, void *, va_list);
+static void    _sethtent(FILE **);
+static void    _endhtent(FILE **);
+static struct addrinfo *_gethtent(FILE **, const char *,
+                                 const struct addrinfo *);
+static int     _files_getaddrinfo(void *, void *, va_list);
 #ifdef YP
-static struct addrinfo *_yphostent (char *, const struct addrinfo *);
-static int _yp_getaddrinfo (void *, void *, va_list);
+static struct addrinfo *_yphostent(char *, const struct addrinfo *);
+static int     _yp_getaddrinfo(void *, void *, va_list);
 #endif
 #ifdef NS_CACHING
-static int addrinfo_id_func(char *, size_t *, va_list, void *);
-static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *);
-static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *);
+static int     addrinfo_id_func(char *, size_t *, va_list, void *);
+static int     addrinfo_marshal_func(char *, size_t *, void *, va_list,
+                                     void *);
+static int     addrinfo_unmarshal_func(char *, size_t, void *, va_list,
+                                       void *);
 #endif
 
-static int res_queryN (const char *, struct res_target *);
-static int res_searchN (const char *, struct res_target *);
-static int res_querydomainN (const char *, const char *,
-       struct res_target *);
-
-static const char *ai_errlist[] = {
-       "Success",
-       "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
-       "Temporary failure in name resolution",         /* EAI_AGAIN      */
-       "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
-       "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
-       "ai_family not supported",                      /* EAI_FAMILY     */
-       "Memory allocation failure",                    /* EAI_MEMORY     */
-       "No address associated with hostname",          /* EAI_NODATA     */
-       "hostname nor servname provided, or not known", /* EAI_NONAME     */
-       "servname not supported for ai_socktype",       /* EAI_SERVICE    */
-       "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
-       "System error returned in errno",               /* EAI_SYSTEM     */
-       "Invalid value for hints",                      /* EAI_BADHINTS   */
-       "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
-       "Argument buffer overflow",                     /* EAI_OVERFLOW   */
-       "Unknown error",                                /* EAI_MAX        */
-};
-
-/* Make getaddrinfo() thread-safe in libc for use with kernel threads. */
-#include "spinlock.h"
-/*
- * XXX: Our res_*() is not thread-safe.  So, we share lock between
- * getaddrinfo() and getipnodeby*().  Still, we cannot use
- * getaddrinfo() and getipnodeby*() in conjunction with other
- * functions which call res_*().
- */
-spinlock_t __getaddrinfo_thread_lock = _SPINLOCK_INITIALIZER;
-#define THREAD_LOCK() \
-       if (__isthreaded) _SPINLOCK(&__getaddrinfo_thread_lock);
-#define THREAD_UNLOCK() \
-       if (__isthreaded) _SPINUNLOCK(&__getaddrinfo_thread_lock);
+static int     res_queryN(const char *, struct res_target *, res_state);
+static int     res_searchN(const char *, struct res_target *, res_state);
+static int     res_querydomainN(const char *, const char *,
+                                struct res_target *, res_state);
 
 /* XXX macros that make external reference is BAD. */
 
@@ -316,14 +326,6 @@ do { \
 #define MATCH(x, y, w) \
        ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
 
-const char *
-gai_strerror(int ecode)
-{
-       if (ecode < 0 || ecode > EAI_MAX)
-               ecode = EAI_MAX;
-       return ai_errlist[ecode];
-}
-
 void
 freeaddrinfo(struct addrinfo *ai)
 {
@@ -340,7 +342,7 @@ freeaddrinfo(struct addrinfo *ai)
 }
 
 static int
-str2number(const char *p)
+str2number(const char *p, int *portp)
 {
        char *ep;
        unsigned long v;
@@ -350,9 +352,10 @@ str2number(const char *p)
        ep = NULL;
        errno = 0;
        v = strtoul(p, &ep, 10);
-       if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
-               return v;
-       else
+       if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) {
+               *portp = v;
+               return 0;
+       } else
                return -1;
 }
 
@@ -367,6 +370,7 @@ getaddrinfo(const char *hostname, const char *servname,
        struct addrinfo ai0;
        struct addrinfo *pai;
        const struct explore *ex;
+       int numeric = 0;
 
        memset(&sentinel, 0, sizeof(sentinel));
        cur = &sentinel;
@@ -421,27 +425,6 @@ getaddrinfo(const char *hostname, const char *servname,
                }
        }
 
-       /*
-        * post-2553: AI_ALL and AI_V4MAPPED are effective only against
-        * AF_INET6 query.  They need to be ignored if specified in other
-        * occassions.
-        */
-       switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
-       case AI_V4MAPPED:
-       case AI_ALL | AI_V4MAPPED:
-               if (pai->ai_family != AF_INET6)
-                       pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
-               break;
-       case AI_ALL:
-#if 1
-               /* illegal */
-               ERR(EAI_BADFLAGS);
-#else
-               pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
-#endif
-               break;
-       }
-
        /*
         * check for special cases.  (1) numeric servname is disallowed if
         * socktype/protocol are left unspecified. (2) servname is disallowed
@@ -480,11 +463,9 @@ getaddrinfo(const char *hostname, const char *servname,
 
                if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
                        continue;
-               if (!MATCH(pai->ai_socktype, ex->e_socktype,
-                          WILD_SOCKTYPE(ex)))
+               if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
                        continue;
-               if (!MATCH(pai->ai_protocol, ex->e_protocol,
-                          WILD_PROTOCOL(ex)))
+               if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
                        continue;
 
                if (pai->ai_family == PF_UNSPEC)
@@ -498,7 +479,7 @@ getaddrinfo(const char *hostname, const char *servname,
                        error = explore_null(pai, servname, &cur->ai_next);
                else
                        error = explore_numeric_scope(pai, hostname, servname,
-                                                     &cur->ai_next);
+                           &cur->ai_next);
 
                if (error)
                        goto free;
@@ -512,13 +493,15 @@ getaddrinfo(const char *hostname, const char *servname,
         * If numreic representation of AF1 can be interpreted as FQDN
         * representation of AF2, we need to think again about the code below.
         */
-       if (sentinel.ai_next)
+       if (sentinel.ai_next) {
+               numeric = 1;
                goto good;
+       }
 
+       if (hostname == NULL)
+               ERR(EAI_NONAME);        /* used to be EAI_NODATA */
        if (pai->ai_flags & AI_NUMERICHOST)
                ERR(EAI_NONAME);
-       if (hostname == NULL)
-               ERR(EAI_NODATA);
 
        if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
                ERR(EAI_FAIL);
@@ -535,10 +518,12 @@ getaddrinfo(const char *hostname, const char *servname,
                if (pai->ai_family != ex->e_af)
                        continue;
 
-               if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) {
+               if (!MATCH(pai->ai_socktype, ex->e_socktype,
+                               WILD_SOCKTYPE(ex))) {
                        continue;
                }
-               if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) {
+               if (!MATCH(pai->ai_protocol, ex->e_protocol,
+                               WILD_PROTOCOL(ex))) {
                        continue;
                }
 
@@ -553,97 +538,505 @@ getaddrinfo(const char *hostname, const char *servname,
                        cur = cur->ai_next;
        }
 
-       /* XXX */
+       /* XXX inhibit errors if we have the result */
        if (sentinel.ai_next)
                error = 0;
 
-       if (error)
-               goto free;
+good:
+       /*
+        * ensure we return either:
+        * - error == 0, non-NULL *res
+        * - error != 0, NULL *res
+        */
        if (error == 0) {
                if (sentinel.ai_next) {
- good:
+                       /*
+                        * If the returned entry is for an active connection,
+                        * and the given name is not numeric, reorder the
+                        * list, so that the application would try the list
+                        * in the most efficient order.  Since the head entry
+                        * of the original list may contain ai_canonname and
+                        * that entry may be moved elsewhere in the new list,
+                        * we keep the pointer and will  restore it in the new
+                        * head entry.  (Note that RFC3493 requires the head
+                        * entry store it when requested by the caller).
+                        */
+                       if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) {
+                               if (!numeric) {
+                                       char *canonname;
+
+                                       canonname =
+                                           sentinel.ai_next->ai_canonname;
+                                       sentinel.ai_next->ai_canonname = NULL;
+                                       reorder(&sentinel);
+                                       if (sentinel.ai_next->ai_canonname ==
+                                           NULL) {
+                                               sentinel.ai_next->ai_canonname
+                                                   = canonname;
+                                       } else if (canonname != NULL)
+                                               free(canonname);
+                               }
+                       }
                        *res = sentinel.ai_next;
                        return SUCCESS;
                } else
                        error = EAI_FAIL;
        }
- free:
- bad:
+free:
+bad:
        if (sentinel.ai_next)
                freeaddrinfo(sentinel.ai_next);
        *res = NULL;
        return error;
 }
 
-/*
- * FQDN hostname, DNS lookup
- */
 static int
-explore_fqdn(const struct addrinfo *pai, const char *hostname,
-            const char *servname, struct addrinfo **res)
+reorder(struct addrinfo *sentinel)
 {
-       struct addrinfo *result;
-       struct addrinfo *cur;
-       int error = 0;
+       struct addrinfo *ai, **aip;
+       struct ai_order *aio;
+       int i, n;
+       struct policyhead policyhead;
 
-#ifdef NS_CACHING
-       static const nss_cache_info cache_info =
-       NS_COMMON_CACHE_INFO_INITIALIZER(
-               hosts, NULL, addrinfo_id_func, addrinfo_marshal_func,
-               addrinfo_unmarshal_func);
+       /* count the number of addrinfo elements for sorting. */
+       for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++)
+               ;
+
+       /*
+        * If the number is small enough, we can skip the reordering process.
+        */
+       if (n <= 1)
+               return(n);
+
+       /* allocate a temporary array for sort and initialization of it. */
+       if ((aio = malloc(sizeof(*aio) * n)) == NULL)
+               return(n);      /* give up reordering */
+       memset(aio, 0, sizeof(*aio) * n);
+
+       /* retrieve address selection policy from the kernel */
+       TAILQ_INIT(&policyhead);
+       if (!get_addrselectpolicy(&policyhead)) {
+               /* no policy is installed into kernel, we don't sort. */
+               free(aio);
+               return (n);
+       }
+
+       for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) {
+               aio[i].aio_ai = ai;
+               aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr);
+               aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr,
+                                                             &policyhead);
+               set_source(&aio[i], &policyhead);
+       }
+
+       /* perform sorting. */
+       qsort(aio, n, sizeof(*aio), comp_dst);
+
+       /* reorder the addrinfo chain. */
+       for (i = 0, aip = &sentinel->ai_next; i < n; i++) {
+               *aip = aio[i].aio_ai;
+               aip = &aio[i].aio_ai->ai_next;
+       }
+       *aip = NULL;
+
+       /* cleanup and return */
+       free(aio);
+       free_addrselectpolicy(&policyhead);
+       return(n);
+}
+
+static int
+get_addrselectpolicy(struct policyhead *head)
+{
+#ifdef INET6
+       int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+       size_t l;
+       char *buf;
+       struct in6_addrpolicy *pol, *ep;
+
+       if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
+               return (0);
+       if ((buf = malloc(l)) == NULL)
+               return (0);
+       if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
+               free(buf);
+               return (0);
+       }
+
+       ep = (struct in6_addrpolicy *)(buf + l);
+       for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
+               struct policyqueue *new;
+
+               if ((new = malloc(sizeof(*new))) == NULL) {
+                       free_addrselectpolicy(head); /* make the list empty */
+                       break;
+               }
+               new->pc_policy = *pol;
+               TAILQ_INSERT_TAIL(head, new, pc_entry);
+       }
+
+       free(buf);
+       return (1);
+#else
+       return (0);
 #endif
-       static const ns_dtab dtab[] = {
-               NS_FILES_CB(_files_getaddrinfo, NULL)
-               { NSSRC_DNS, _dns_getaddrinfo, NULL },  /* force -DHESIOD */
-               NS_NIS_CB(_yp_getaddrinfo, NULL)
-#ifdef NS_CACHING
-               NS_CACHE_CB(&cache_info)
+}
+
+static void
+free_addrselectpolicy(struct policyhead *head)
+{
+       struct policyqueue *ent, *nent;
+
+       for (ent = TAILQ_FIRST(head); ent; ent = nent) {
+               nent = TAILQ_NEXT(ent, pc_entry);
+               TAILQ_REMOVE(head, ent, pc_entry);
+               free(ent);
+       }
+}
+
+static struct policyqueue *
+match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
+{
+#ifdef INET6
+       struct policyqueue *ent, *bestent = NULL;
+       struct in6_addrpolicy *pol;
+       int matchlen, bestmatchlen = -1;
+       u_char *mp, *ep, *k, *p, m;
+       struct sockaddr_in6 key;
+
+       switch(addr->sa_family) {
+       case AF_INET6:
+               key = *(struct sockaddr_in6 *)addr;
+               break;
+       case AF_INET:
+               /* convert the address into IPv4-mapped IPv6 address. */
+               memset(&key, 0, sizeof(key));
+               key.sin6_family = AF_INET6;
+               key.sin6_len = sizeof(key);
+               key.sin6_addr.s6_addr[10] = 0xff;
+               key.sin6_addr.s6_addr[11] = 0xff;
+               memcpy(&key.sin6_addr.s6_addr[12],
+                      &((struct sockaddr_in *)addr)->sin_addr, 4);
+               break;
+       default:
+               return(NULL);
+       }
+
+       for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
+               pol = &ent->pc_policy;
+               matchlen = 0;
+
+               mp = (u_char *)&pol->addrmask.sin6_addr;
+               ep = mp + 16;   /* XXX: scope field? */
+               k = (u_char *)&key.sin6_addr;
+               p = (u_char *)&pol->addr.sin6_addr;
+               for (; mp < ep && *mp; mp++, k++, p++) {
+                       m = *mp;
+                       if ((*k & m) != *p)
+                               goto next; /* not match */
+                       if (m == 0xff) /* short cut for a typical case */
+                               matchlen += 8;
+                       else {
+                               while (m >= 0x80) {
+                                       matchlen++;
+                                       m <<= 1;
+                               }
+                       }
+               }
+
+               /* matched.  check if this is better than the current best. */
+               if (matchlen > bestmatchlen) {
+                       bestent = ent;
+                       bestmatchlen = matchlen;
+               }
+
+         next:
+               continue;
+       }
+
+       return(bestent);
+#else
+       return(NULL);
 #endif
-               { 0 }
-       };
 
-       result = NULL;
+}
+
+static void
+set_source(struct ai_order *aio, struct policyhead *ph)
+{
+       struct addrinfo ai = *aio->aio_ai;
+       struct sockaddr_storage ss;
+       socklen_t srclen;
+       int s;
+
+       /* set unspec ("no source is available"), just in case */
+       aio->aio_srcsa.sa_family = AF_UNSPEC;
+       aio->aio_srcscope = -1;
+
+       switch(ai.ai_family) {
+       case AF_INET:
+#ifdef INET6
+       case AF_INET6:
+#endif
+               break;
+       default:                /* ignore unsupported AFs explicitly */
+               return;
+       }
+
+       /* XXX: make a dummy addrinfo to call connect() */
+       ai.ai_socktype = SOCK_DGRAM;
+       ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */
+       ai.ai_next = NULL;
+       memset(&ss, 0, sizeof(ss));
+       memcpy(&ss, ai.ai_addr, ai.ai_addrlen);
+       ai.ai_addr = (struct sockaddr *)&ss;
+       get_port(&ai, "1", 0);
+
+       /* open a socket to get the source address for the given dst */
+       if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0)
+               return;         /* give up */
+       if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0)
+               goto cleanup;
+       srclen = ai.ai_addrlen;
+       if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
+               aio->aio_srcsa.sa_family = AF_UNSPEC;
+               goto cleanup;
+       }
+       aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
+       aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
+       aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr);
+#ifdef INET6
+       if (ai.ai_family == AF_INET6) {
+               struct in6_ifreq ifr6;
+               u_int32_t flags6;
+
+               /* XXX: interface name should not be hardcoded */
+               strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
+               memset(&ifr6, 0, sizeof(ifr6));
+               memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen);
+               if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
+                       flags6 = ifr6.ifr_ifru.ifru_flags6;
+                       if ((flags6 & IN6_IFF_DEPRECATED))
+                               aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
+               }
+       }
+#endif
+
+  cleanup:
+       _close(s);
+       return;
+}
+
+static int
+matchlen(struct sockaddr *src, struct sockaddr *dst)
+{
+       int match = 0;
+       u_char *s, *d;
+       u_char *lim, r;
+       int addrlen;
+
+       switch (src->sa_family) {
+#ifdef INET6
+       case AF_INET6:
+               s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
+               d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
+               addrlen = sizeof(struct in6_addr);
+               lim = s + addrlen;
+               break;
+#endif
+       case AF_INET:
+               s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
+               d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
+               addrlen = sizeof(struct in_addr);
+               lim = s + addrlen;
+               break;
+       default:
+               return(0);
+       }
+
+       while (s < lim)
+               if ((r = (*d++ ^ *s++)) != 0) {
+                       while (r < addrlen * 8) {
+                               match++;
+                               r <<= 1;
+                       }
+                       break;
+               } else
+                       match += 8;
+       return(match);
+}
 
-       THREAD_LOCK();
+static int
+comp_dst(const void *arg1, const void *arg2)
+{
+       const struct ai_order *dst1 = arg1, *dst2 = arg2;
 
        /*
-        * if the servname does not match socktype/protocol, ignore it.
+        * Rule 1: Avoid unusable destinations.
+        * XXX: we currently do not consider if an appropriate route exists.
         */
-       if (get_portmatch(pai, servname) != 0) {
-               THREAD_UNLOCK();
-               return 0;
+       if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+           dst2->aio_srcsa.sa_family == AF_UNSPEC) {
+               return(-1);
+       }
+       if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
+           dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+               return(1);
        }
 
-       switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
-                       default_dns_files, hostname, pai)) {
-       case NS_TRYAGAIN:
-               error = EAI_AGAIN;
-               goto free;
-       case NS_UNAVAIL:
-               error = EAI_FAIL;
-               goto free;
-       case NS_NOTFOUND:
-               error = EAI_NODATA;
-               goto free;
-       case NS_SUCCESS:
-               error = 0;
-               for (cur = result; cur; cur = cur->ai_next) {
-                       GET_PORT(cur, servname);
-                       /* canonname should be filled already */
+       /* Rule 2: Prefer matching scope. */
+       if (dst1->aio_dstscope == dst1->aio_srcscope &&
+           dst2->aio_dstscope != dst2->aio_srcscope) {
+               return(-1);
+       }
+       if (dst1->aio_dstscope != dst1->aio_srcscope &&
+           dst2->aio_dstscope == dst2->aio_srcscope) {
+               return(1);
+       }
+
+       /* Rule 3: Avoid deprecated addresses. */
+       if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
+           dst2->aio_srcsa.sa_family != AF_UNSPEC) {
+               if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+                   (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+                       return(-1);
+               }
+               if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
+                   !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
+                       return(1);
                }
-               THREAD_UNLOCK();
-               break;
        }
 
-       *res = result;
+       /* Rule 4: Prefer home addresses. */
+       /* XXX: not implemented yet */
 
-       return 0;
+       /* Rule 5: Prefer matching label. */
+#ifdef INET6
+       if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
+           dst1->aio_srcpolicy->pc_policy.label ==
+           dst1->aio_dstpolicy->pc_policy.label &&
+           (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
+            dst2->aio_srcpolicy->pc_policy.label !=
+            dst2->aio_dstpolicy->pc_policy.label)) {
+               return(-1);
+       }
+       if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
+           dst2->aio_srcpolicy->pc_policy.label ==
+           dst2->aio_dstpolicy->pc_policy.label &&
+           (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
+            dst1->aio_srcpolicy->pc_policy.label !=
+            dst1->aio_dstpolicy->pc_policy.label)) {
+               return(1);
+       }
+#endif
 
-free:
-       THREAD_UNLOCK();
-       if (result)
-               freeaddrinfo(result);
-       return error;
+       /* Rule 6: Prefer higher precedence. */
+#ifdef INET6
+       if (dst1->aio_dstpolicy &&
+           (dst2->aio_dstpolicy == NULL ||
+            dst1->aio_dstpolicy->pc_policy.preced >
+            dst2->aio_dstpolicy->pc_policy.preced)) {
+               return(-1);
+       }
+       if (dst2->aio_dstpolicy &&
+           (dst1->aio_dstpolicy == NULL ||
+            dst2->aio_dstpolicy->pc_policy.preced >
+            dst1->aio_dstpolicy->pc_policy.preced)) {
+               return(1);
+       }
+#endif
+
+       /* Rule 7: Prefer native transport. */
+       /* XXX: not implemented yet */
+
+       /* Rule 8: Prefer smaller scope. */
+       if (dst1->aio_dstscope >= 0 &&
+           dst1->aio_dstscope < dst2->aio_dstscope) {
+               return(-1);
+       }
+       if (dst2->aio_dstscope >= 0 &&
+           dst2->aio_dstscope < dst1->aio_dstscope) {
+               return(1);
+       }
+
+       /*
+        * Rule 9: Use longest matching prefix.
+        * We compare the match length in a same AF only.
+        */
+       if (dst1->aio_ai->ai_addr->sa_family ==
+           dst2->aio_ai->ai_addr->sa_family) {
+               if (dst1->aio_matchlen > dst2->aio_matchlen) {
+                       return(-1);
+               }
+               if (dst1->aio_matchlen < dst2->aio_matchlen) {
+                       return(1);
+               }
+       }
+
+       /* Rule 10: Otherwise, leave the order unchanged. */
+       return(-1);
+}
+
+/*
+ * Copy from scope.c.
+ * XXX: we should standardize the functions and link them as standard
+ * library.
+ */
+static int
+gai_addr2scopetype(struct sockaddr *sa)
+{
+#ifdef INET6
+       struct sockaddr_in6 *sa6;
+#endif
+       struct sockaddr_in *sa4;
+
+       switch(sa->sa_family) {
+#ifdef INET6
+       case AF_INET6:
+               sa6 = (struct sockaddr_in6 *)sa;
+               if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
+                       /* just use the scope field of the multicast address */
+                       return(sa6->sin6_addr.s6_addr[2] & 0x0f);
+               }
+               /*
+                * Unicast addresses: map scope type to corresponding scope
+                * value defined for multcast addresses.
+                * XXX: hardcoded scope type values are bad...
+                */
+               if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
+                       return(1); /* node local scope */
+               if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
+                       return(2); /* link-local scope */
+               if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
+                       return(5); /* site-local scope */
+               return(14);     /* global scope */
+               break;
+#endif
+       case AF_INET:
+               /*
+                * IPv4 pseudo scoping according to RFC 3484.
+                */
+               sa4 = (struct sockaddr_in *)sa;
+               /* IPv4 autoconfiguration addresses have link-local scope. */
+               if (((u_char *)&sa4->sin_addr)[0] == 169 &&
+                   ((u_char *)&sa4->sin_addr)[1] == 254)
+                       return(2);
+               /* Private addresses have site-local scope. */
+               if (((u_char *)&sa4->sin_addr)[0] == 10 ||
+                   (((u_char *)&sa4->sin_addr)[0] == 172 &&
+                    (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
+                   (((u_char *)&sa4->sin_addr)[0] == 192 &&
+                    ((u_char *)&sa4->sin_addr)[1] == 168))
+                       return(14);     /* XXX: It should be 5 unless NAT */
+               /* Loopback addresses have link-local scope. */
+               if (((u_char *)&sa4->sin_addr)[0] == 127)
+                       return(2);
+               return(14);
+               break;
+       default:
+               errno = EAFNOSUPPORT; /* is this a good error? */
+               return(-1);
+       }
 }
 
 /*
@@ -657,13 +1050,11 @@ explore_null(const struct addrinfo *pai, const char *servname,
 {
        int s;
        const struct afd *afd;
-       struct addrinfo *cur;
-       struct addrinfo sentinel;
+       struct addrinfo *ai;
        int error;
 
        *res = NULL;
-       sentinel.ai_next = NULL;
-       cur = &sentinel;
+       ai = NULL;
 
        /*
         * filter out AFs that are not supported by the kernel
@@ -687,26 +1078,19 @@ explore_null(const struct addrinfo *pai, const char *servname,
                return 0;
 
        if (pai->ai_flags & AI_PASSIVE) {
-               GET_AI(cur->ai_next, afd, afd->a_addrany);
-               /* xxx meaningless?
-                * GET_CANONNAME(cur->ai_next, "anyaddr");
-                */
-               GET_PORT(cur->ai_next, servname);
+               GET_AI(ai, afd, afd->a_addrany);
+               GET_PORT(ai, servname);
        } else {
-               GET_AI(cur->ai_next, afd, afd->a_loopback);
-               /* xxx meaningless?
-                * GET_CANONNAME(cur->ai_next, "localhost");
-                */
-               GET_PORT(cur->ai_next, servname);
+               GET_AI(ai, afd, afd->a_loopback);
+               GET_PORT(ai, servname);
        }
-       cur = cur->ai_next;
 
-       *res = sentinel.ai_next;
+       *res = ai;
        return 0;
 
 free:
-       if (sentinel.ai_next)
-               freeaddrinfo(sentinel.ai_next);
+       if (ai != NULL)
+               freeaddrinfo(ai);
        return error;
 }
 
@@ -715,17 +1099,16 @@ free:
  */
 static int
 explore_numeric(const struct addrinfo *pai, const char *hostname,
-               const char *servname, struct addrinfo **res)
+               const char *servname, struct addrinfo **res,
+               const char *canonname)
 {
        const struct afd *afd;
-       struct addrinfo *cur;
-       struct addrinfo sentinel;
+       struct addrinfo *ai;
        int error;
        char pton[PTON_MAX];
 
        *res = NULL;
-       sentinel.ai_next = NULL;
-       cur = &sentinel;
+       ai = NULL;
 
        /*
         * if the servname does not match socktype/protocol, ignore it.
@@ -738,41 +1121,48 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
                return 0;
 
        switch (afd->a_af) {
-#if 1 /*X/Open spec*/
        case AF_INET:
-               if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
-                       if (pai->ai_family == afd->a_af ||
-                           pai->ai_family == PF_UNSPEC /*?*/) {
-                               GET_AI(cur->ai_next, afd, pton);
-                               GET_PORT(cur->ai_next, servname);
-                               while (cur && cur->ai_next)
-                                       cur = cur->ai_next;
-                       } else
-                               ERR(EAI_FAMILY);        /*xxx*/
-               }
+               /*
+                * RFC3493 requires getaddrinfo() to accept AF_INET formats
+                * that are accepted by inet_addr() and its family.  The
+                * accepted forms includes the "classful" one, which inet_pton
+                * does not accept.  So we need to separate the case for
+                * AF_INET.
+                */
+               if (inet_aton(hostname, (struct in_addr *)pton) != 1)
+                       return 0;
                break;
-#endif
        default:
-               if (inet_pton(afd->a_af, hostname, pton) == 1) {
-                       if (pai->ai_family == afd->a_af ||
-                           pai->ai_family == PF_UNSPEC /*?*/) {
-                               GET_AI(cur->ai_next, afd, pton);
-                               GET_PORT(cur->ai_next, servname);
-                               while (cur && cur->ai_next)
-                                       cur = cur->ai_next;
-                       } else
-                               ERR(EAI_FAMILY);        /* XXX */
-               }
+               if (inet_pton(afd->a_af, hostname, pton) != 1)
+                       return 0;
                break;
        }
 
-       *res = sentinel.ai_next;
+       if (pai->ai_family == afd->a_af) {
+               GET_AI(ai, afd, pton);
+               GET_PORT(ai, servname);
+               if ((pai->ai_flags & AI_CANONNAME)) {
+                       /*
+                        * Set the numeric address itself as the canonical
+                        * name, based on a clarification in RFC3493.
+                        */
+                       GET_CANONNAME(ai, canonname);
+               }
+       } else {
+               /*
+                * XXX: This should not happen since we already matched the AF
+                * by find_afd.
+                */
+               ERR(EAI_FAMILY);
+       }
+
+       *res = ai;
        return 0;
 
 free:
 bad:
-       if (sentinel.ai_next)
-               freeaddrinfo(sentinel.ai_next);
+       if (ai != NULL)
+               freeaddrinfo(ai);
        return error;
 }
 
@@ -784,7 +1174,7 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
                      const char *servname, struct addrinfo **res)
 {
 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
-       return explore_numeric(pai, hostname, servname, res);
+       return explore_numeric(pai, hostname, servname, res, hostname);
 #else
        const struct afd *afd;
        struct addrinfo *cur;
@@ -801,12 +1191,13 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
        afd = find_afd(pai->ai_family);
        if (afd == NULL)
                return 0;
+
        if (!afd->a_scoped)
-               return explore_numeric(pai, hostname, servname, res);
+               return explore_numeric(pai, hostname, servname, res, hostname);
 
        cp = strchr(hostname, SCOPE_DELIMITER);
        if (cp == NULL)
-               return explore_numeric(pai, hostname, servname, res);
+               return explore_numeric(pai, hostname, servname, res, hostname);
 
        /*
         * Handle special case of <scoped_address><delimiter><scope id>
@@ -819,7 +1210,7 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
        addr = hostname2;
        scope = cp + 1;
 
-       error = explore_numeric(pai, addr, servname, res);
+       error = explore_numeric(pai, addr, servname, res, hostname);
        if (error == 0) {
                u_int32_t scopeid;
 
@@ -829,7 +1220,7 @@ explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
                        sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
                        if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
                                free(hostname2);
-                               return(EAI_NODATA); /* XXX: is return OK? */
+                               return(EAI_NONAME); /* XXX: is return OK? */
                        }
                        sin6->sin6_scope_id = scopeid;
                }
@@ -845,10 +1236,9 @@ static int
 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
 {
        if ((pai->ai_flags & AI_CANONNAME) != 0) {
-               ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+               ai->ai_canonname = strdup(str);
                if (ai->ai_canonname == NULL)
                        return EAI_MEMORY;
-               strlcpy(ai->ai_canonname, str, strlen(str) + 1);
        }
        return 0;
 }
@@ -918,7 +1308,6 @@ get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
        else
 #endif
        memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
-
        return ai;
 }
 
@@ -926,7 +1315,7 @@ static int
 get_portmatch(const struct addrinfo *ai, const char *servname)
 {
 
-       /* get_port does not touch first argument. when matchonly == 1. */
+       /* get_port does not touch first argument when matchonly == 1. */
        /* LINTED const cast */
        return get_port((struct addrinfo *)ai, servname, 1);
 }
@@ -936,7 +1325,7 @@ get_port(struct addrinfo *ai, const char *servname, int matchonly)
 {
        const char *proto;
        struct servent *sp;
-       int port;
+       int port, error;
        int allownumeric;
 
        if (servname == NULL)
@@ -965,8 +1354,8 @@ get_port(struct addrinfo *ai, const char *servname, int matchonly)
                return EAI_SOCKTYPE;
        }
 
-       port = str2number(servname);
-       if (port >= 0) {
+       error = str2number(servname, &port);
+       if (error == 0) {
                if (!allownumeric)
                        return EAI_SERVICE;
                if (port < 0 || port > 65535)
@@ -1056,7 +1445,6 @@ addrconfig(struct addrinfo *pai)
                        else
                                _close(s);
                }
-
        }
        if (af != AF_UNSPEC) {
                if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
@@ -1114,81 +1502,258 @@ ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
 }
 #endif
 
-#ifdef RESOLVSORT
-struct addr_ptr {
-       struct addrinfo *ai;
-       int aval;
-};
 
+#ifdef NS_CACHING
 static int
-addr4sort(struct addrinfo *sentinel)
+addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap,
+                void *cache_mdata)
 {
-       struct addrinfo *ai;
-       struct addr_ptr *addrs, addr;
-       struct sockaddr_in *sin;
-       int naddrs, i, j;
-       int needsort = 0;
+       res_state statp;
+       u_long res_options;
 
-       if (!sentinel)
-               return -1;
-       naddrs = 0;
-       for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
-               naddrs++;
-       if (naddrs < 2)
-               return 0;               /* We don't need sorting. */
-       if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
-               return -1;
-       i = 0;
-       for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
-               sin = (struct sockaddr_in *)ai->ai_addr;
-               for (j = 0; (unsigned)j < _res.nsort; j++) {
-                       if (_res.sort_list[j].addr.s_addr == 
-                           (sin->sin_addr.s_addr & _res.sort_list[j].mask))
-                               break;
-               }
-               addrs[i].ai = ai;
-               addrs[i].aval = j;
-               if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
-                       needsort = i;
-               i++;
+       const int op_id = 0;    /* identifies the getaddrinfo for the cache */
+       char *hostname;
+       struct addrinfo *hints;
+
+       char *p;
+       int ai_flags, ai_family, ai_socktype, ai_protocol;
+       size_t desired_size, size;
+
+       statp = __res_state();
+       res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
+           RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
+
+       hostname = va_arg(ap, char *);
+       hints = va_arg(ap, struct addrinfo *);
+
+       desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4;
+       if (hostname != NULL) {
+               size = strlen(hostname);
+               desired_size += size + 1;
+       } else
+               size = 0;
+
+       if (desired_size > *buffer_size) {
+               *buffer_size = desired_size;
+               return (NS_RETURN);
        }
-       if (!needsort) {
-               free(addrs);
-               return 0;
+
+       if (hints == NULL)
+               ai_flags = ai_family = ai_socktype = ai_protocol = 0;
+       else {
+               ai_flags = hints->ai_flags;
+               ai_family = hints->ai_family;
+               ai_socktype = hints->ai_socktype;
+               ai_protocol = hints->ai_protocol;
        }
 
-       while (needsort < naddrs) {
-           for (j = needsort - 1; j >= 0; j--) {
-               if (addrs[j].aval > addrs[j+1].aval) {
-                   addr = addrs[j];
-                   addrs[j] = addrs[j + 1];
-                   addrs[j + 1] = addr;
-               } else
-                   break;
-           }
-           needsort++;
+       p = buffer;
+       memcpy(p, &res_options, sizeof(res_options));
+       p += sizeof(res_options);
+
+       memcpy(p, &op_id, sizeof(int));
+       p += sizeof(int);
+
+       memcpy(p, &ai_flags, sizeof(int));
+       p += sizeof(int);
+
+       memcpy(p, &ai_family, sizeof(int));
+       p += sizeof(int);
+
+       memcpy(p, &ai_socktype, sizeof(int));
+       p += sizeof(int);
+
+       memcpy(p, &ai_protocol, sizeof(int));
+       p += sizeof(int);
+
+       if (hostname != NULL)
+               memcpy(p, hostname, size);
+
+       *buffer_size = desired_size;
+       return (NS_SUCCESS);
+}
+
+static int
+addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval,
+                     va_list ap, void *cache_mdata)
+{
+       struct addrinfo *ai, *cai;
+       char *p;
+       size_t desired_size, size, ai_size;
+
+       ai = *((struct addrinfo **)retval);
+
+       desired_size = sizeof(size_t);
+       ai_size = 0;
+       for (cai = ai; cai != NULL; cai = cai->ai_next) {
+               desired_size += sizeof(struct addrinfo) + cai->ai_addrlen;
+               if (cai->ai_canonname != NULL)
+                       desired_size += sizeof(size_t) +
+                           strlen(cai->ai_canonname);
+               ++ai_size;
        }
 
-       ai = sentinel;
-       for (i = 0; i < naddrs; ++i) {
-               ai->ai_next = addrs[i].ai;
-               ai = ai->ai_next;
+       if (desired_size > *buffer_size) {
+               /* this assignment is here for future use */
+               errno = ERANGE;
+               *buffer_size = desired_size;
+               return (NS_RETURN);
        }
-       ai->ai_next = NULL;
-       free(addrs);
+
+       memset(buffer, 0, desired_size);
+       p = buffer;
+
+       memcpy(p, &ai_size, sizeof(size_t));
+       p += sizeof(size_t);
+       for (cai = ai; cai != NULL; cai = cai->ai_next) {
+               memcpy(p, cai, sizeof(struct addrinfo));
+               p += sizeof(struct addrinfo);
+
+               memcpy(p, cai->ai_addr, cai->ai_addrlen);
+               p += cai->ai_addrlen;
+
+               if (cai->ai_canonname != NULL) {
+                       size = strlen(cai->ai_canonname);
+                       memcpy(p, &size, sizeof(size_t));
+                       p += sizeof(size_t);
+
+                       memcpy(p, cai->ai_canonname, size);
+                       p += size;
+               }
+       }
+
+       return (NS_SUCCESS);
+}
+
+static int
+addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
+                       va_list ap, void *cache_mdata)
+{
+       struct addrinfo new_ai, *result, *sentinel, *lasts;
+
+       char *p;
+       size_t ai_size, ai_i, size;
+
+       p = buffer;
+       memcpy(&ai_size, p, sizeof(size_t));
+       p += sizeof(size_t);
+
+       result = NULL;
+       lasts = NULL;
+       for (ai_i = 0; ai_i < ai_size; ++ai_i) {
+               memcpy(&new_ai, p, sizeof(struct addrinfo));
+               p += sizeof(struct addrinfo);
+               size = new_ai.ai_addrlen + sizeof(struct addrinfo) +
+                       _ALIGNBYTES;
+
+               sentinel = (struct addrinfo *)malloc(size);
+               memset(sentinel, 0, size);
+
+               memcpy(sentinel, &new_ai, sizeof(struct addrinfo));
+               sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel +
+                   sizeof(struct addrinfo));
+
+               memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen);
+               p += new_ai.ai_addrlen;
+
+               if (new_ai.ai_canonname != NULL) {
+                       memcpy(&size, p, sizeof(size_t));
+                       p += sizeof(size_t);
+
+                       sentinel->ai_canonname = (char *)malloc(size + 1);
+                       memset(sentinel->ai_canonname, 0, size + 1);
+
+                       memcpy(sentinel->ai_canonname, p, size);
+                       p += size;
+               }
+
+               if (result == NULL) {
+                       result = sentinel;
+                       lasts = sentinel;
+               } else {
+                       lasts->ai_next = sentinel;
+                       lasts = sentinel;
+               }
+       }
+
+       *((struct addrinfo **)retval) = result;
+       return (NS_SUCCESS);
+}
+#endif /* NS_CACHING */
+
+/*
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(const struct addrinfo *pai, const char *hostname,
+            const char *servname, struct addrinfo **res)
+{
+       struct addrinfo *result;
+       struct addrinfo *cur;
+       int error = 0;
+
+#ifdef NS_CACHING
+       static const nss_cache_info cache_info =
+       NS_COMMON_CACHE_INFO_INITIALIZER(
+               hosts, NULL, addrinfo_id_func, addrinfo_marshal_func,
+               addrinfo_unmarshal_func);
+#endif
+       static const ns_dtab dtab[] = {
+               NS_FILES_CB(_files_getaddrinfo, NULL)
+               { NSSRC_DNS, _dns_getaddrinfo, NULL },  /* force -DHESIOD */
+               NS_NIS_CB(_yp_getaddrinfo, NULL)
+#ifdef NS_CACHING
+               NS_CACHE_CB(&cache_info)
+#endif
+               { 0 }
+       };
+
+       result = NULL;
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return 0;
+
+       switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
+                       default_dns_files, hostname, pai)) {
+       case NS_TRYAGAIN:
+               error = EAI_AGAIN;
+               goto free;
+       case NS_UNAVAIL:
+               error = EAI_FAIL;
+               goto free;
+       case NS_NOTFOUND:
+               error = EAI_NONAME;
+               goto free;
+       case NS_SUCCESS:
+               error = 0;
+               for (cur = result; cur; cur = cur->ai_next) {
+                       GET_PORT(cur, servname);
+                       /* canonname should be filled already */
+               }
+               break;
+       }
+
+       *res = result;
+
        return 0;
+
+free:
+       if (result)
+               freeaddrinfo(result);
+       return error;
 }
-#endif /*RESOLVSORT*/
 
 #ifdef DEBUG
 static const char AskedForGot[] =
        "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
 #endif
-static FILE *hostf = NULL;
 
 static struct addrinfo *
 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
-         const struct addrinfo *pai)
+         const struct addrinfo *pai, res_state res)
 {
        struct addrinfo sentinel, *cur;
        struct addrinfo ai;
@@ -1202,7 +1767,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
        int type, class, ancount, qdcount;
        int haveanswer, had_error;
        char tbuf[MAXDNAME];
-       int (*name_ok) (const char *);
+       int (*name_ok)(const char *);
        char hostbuf[8*1024];
 
        memset(&sentinel, 0, sizeof(sentinel));
@@ -1229,12 +1794,12 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
        ep = hostbuf + sizeof hostbuf;
        cp = answer->buf + HFIXEDSZ;
        if (qdcount != 1) {
-               h_errno = NO_RECOVERY;
+               RES_SET_H_ERRNO(res, NO_RECOVERY);
                return (NULL);
        }
        n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
        if ((n < 0) || !(*name_ok)(bp)) {
-               h_errno = NO_RECOVERY;
+               RES_SET_H_ERRNO(res, NO_RECOVERY);
                return (NULL);
        }
        cp += n + QFIXEDSZ;
@@ -1245,7 +1810,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
                 */
                n = strlen(bp) + 1;             /* for the \0 */
                if (n >= MAXHOSTNAMELEN) {
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(res, NO_RECOVERY);
                        return (NULL);
                }
                canonname = bp;
@@ -1263,9 +1828,9 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
                }
                cp += n;                        /* name */
                type = _getshort(cp);
-               cp += INT16SZ;                  /* type */
+               cp += INT16SZ;                  /* type */
                class = _getshort(cp);
-               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
                n = _getshort(cp);
                cp += INT16SZ;                  /* len */
                if (class != C_IN) {
@@ -1372,10 +1937,10 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
                 * We support only IPv4 address for backward
                 * compatibility against gethostbyname(3).
                 */
-               if (_res.nsort && qtype == T_A) {
-                       if (addr4sort(&sentinel) < 0) {
+               if (res->nsort && qtype == T_A) {
+                       if (addr4sort(&sentinel, res) < 0) {
                                freeaddrinfo(sentinel.ai_next);
-                               h_errno = NO_RECOVERY;
+                               RES_SET_H_ERRNO(res, NO_RECOVERY);
                                return NULL;
                        }
                }
@@ -1384,13 +1949,79 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
                        get_canonname(pai, sentinel.ai_next, qname);
                else
                        get_canonname(pai, sentinel.ai_next, canonname);
-               h_errno = NETDB_SUCCESS;
+               RES_SET_H_ERRNO(res, NETDB_SUCCESS);
                return sentinel.ai_next;
        }
 
-       h_errno = NO_RECOVERY;
-       return NULL;
+       RES_SET_H_ERRNO(res, NO_RECOVERY);
+       return NULL;
+}
+
+#ifdef RESOLVSORT
+struct addr_ptr {
+       struct addrinfo *ai;
+       int aval;
+};
+
+static int
+addr4sort(struct addrinfo *sentinel, res_state res)
+{
+       struct addrinfo *ai;
+       struct addr_ptr *addrs, addr;
+       struct sockaddr_in *sin;
+       int naddrs, i, j;
+       int needsort = 0;
+
+       if (!sentinel)
+               return -1;
+       naddrs = 0;
+       for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
+               naddrs++;
+       if (naddrs < 2)
+               return 0;               /* We don't need sorting. */
+       if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
+               return -1;
+       i = 0;
+       for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
+               sin = (struct sockaddr_in *)ai->ai_addr;
+               for (j = 0; (unsigned)j < res->nsort; j++) {
+                       if (res->sort_list[j].addr.s_addr ==
+                           (sin->sin_addr.s_addr & res->sort_list[j].mask))
+                               break;
+               }
+               addrs[i].ai = ai;
+               addrs[i].aval = j;
+               if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
+                       needsort = i;
+               i++;
+       }
+       if (!needsort) {
+               free(addrs);
+               return 0;
+       }
+
+       while (needsort < naddrs) {
+               for (j = needsort - 1; j >= 0; j--) {
+                       if (addrs[j].aval > addrs[j+1].aval) {
+                               addr = addrs[j];
+                               addrs[j] = addrs[j + 1];
+                               addrs[j + 1] = addr;
+                       } else
+                               break;
+               }
+               needsort++;
+       }
+
+       ai = sentinel;
+       for (i = 0; i < naddrs; ++i) {
+               ai->ai_next = addrs[i].ai;
+               ai = ai->ai_next;
+       }
+       ai->ai_next = NULL;
+       free(addrs);
+       return 0;
 }
+#endif /*RESOLVSORT*/
 
 /*ARGSUSED*/
 static int
@@ -1398,54 +2029,55 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
 {
        struct addrinfo *ai;
        querybuf *buf, *buf2;
-       const char *name;
+       const char *hostname;
        const struct addrinfo *pai;
        struct addrinfo sentinel, *cur;
        struct res_target q, q2;
+       res_state res;
 
-       name = va_arg(ap, char *);
+       hostname = va_arg(ap, char *);
        pai = va_arg(ap, const struct addrinfo *);
 
-       memset(&q, 0, sizeof(q2));
+       memset(&q, 0, sizeof(q));
        memset(&q2, 0, sizeof(q2));
        memset(&sentinel, 0, sizeof(sentinel));
        cur = &sentinel;
 
        buf = malloc(sizeof(*buf));
        if (!buf) {
-               h_errno = NETDB_INTERNAL;
-               return EAI_MEMORY;
+               RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+               return NS_NOTFOUND;
        }
        buf2 = malloc(sizeof(*buf2));
        if (!buf2) {
                free(buf);
-               h_errno = NETDB_INTERNAL;
-               return EAI_MEMORY;
+               RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+               return NS_NOTFOUND;
        }
 
        switch (pai->ai_family) {
        case AF_UNSPEC:
-               q.name = name;
+               q.name = hostname;
                q.qclass = C_IN;
                q.qtype = T_A;
                q.answer = buf->buf;
                q.anslen = sizeof(buf->buf);
                q.next = &q2;
-               q2.name = name;
+               q2.name = hostname;
                q2.qclass = C_IN;
                q2.qtype = T_AAAA;
                q2.answer = buf2->buf;
                q2.anslen = sizeof(buf2->buf);
                break;
        case AF_INET:
-               q.name = name;
+               q.name = hostname;
                q.qclass = C_IN;
                q.qtype = T_A;
                q.answer = buf->buf;
                q.anslen = sizeof(buf->buf);
                break;
        case AF_INET6:
-               q.name = name;
+               q.name = hostname;
                q.qclass = C_IN;
                q.qtype = T_AAAA;
                q.answer = buf->buf;
@@ -1456,28 +2088,36 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
                free(buf2);
                return NS_UNAVAIL;
        }
-       if (res_searchN(name, &q) < 0) {
+
+       res = __res_state();
+       if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) {
+               RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+               free(buf);
+               free(buf2);
+               return NS_NOTFOUND;
+       }
+
+       if (res_searchN(hostname, &q, res) < 0) {
                free(buf);
                free(buf2);
                return NS_NOTFOUND;
        }
        /* prefer IPv6 */
        if (q.next) {
-               ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
+               ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res);
                if (ai) {
                        cur->ai_next = ai;
                        while (cur && cur->ai_next)
                                cur = cur->ai_next;
                }
        }
-
-       ai = getanswer(buf, q.n, q.name, q.qtype, pai);
+       ai = getanswer(buf, q.n, q.name, q.qtype, pai, res);
        if (ai)
                cur->ai_next = ai;
        free(buf);
        free(buf2);
        if (sentinel.ai_next == NULL)
-               switch (h_errno) {
+               switch (res->res_h_errno) {
                case HOST_NOT_FOUND:
                        return NS_NOTFOUND;
                case TRY_AGAIN:
@@ -1490,25 +2130,25 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
 }
 
 static void
-_sethtent(void)
+_sethtent(FILE **hostf)
 {
-       if (!hostf)
-               hostf = fopen(_PATH_HOSTS, "r" );
+       if (!*hostf)
+               *hostf = fopen(_PATH_HOSTS, "r");
        else
-               rewind(hostf);
+               rewind(*hostf);
 }
 
 static void
-_endhtent(void)
+_endhtent(FILE **hostf)
 {
-       if (hostf) {
-               fclose(hostf);
-               hostf = NULL;
+       if (*hostf) {
+               fclose(*hostf);
+               *hostf = NULL;
        }
 }
 
 static struct addrinfo *
-_gethtent(const char *name, const struct addrinfo *pai)
+_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
 {
        char *p;
        char *cp, *tname, *cname;
@@ -1517,16 +2157,16 @@ _gethtent(const char *name, const struct addrinfo *pai)
        const char *addr;
        char hostbuf[8*1024];
 
-       if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
+       if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r")))
                return (NULL);
 again:
-       if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
+       if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
                return (NULL);
        if (*p == '#')
                goto again;
-       if (!(cp = strpbrk(p, "#\n")))
-               goto again;
-       *cp = '\0';
+       cp = strpbrk(p, "#\n");
+       if (cp != NULL)
+               *cp = '\0';
        if (!(cp = strpbrk(p, " \t")))
                goto again;
        *cp++ = '\0';
@@ -1590,6 +2230,7 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
        const struct addrinfo *pai;
        struct addrinfo sentinel, *cur;
        struct addrinfo *p;
+       FILE *hostf = NULL;
 
        name = va_arg(ap, char *);
        pai = va_arg(ap, struct addrinfo *);
@@ -1597,13 +2238,13 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
        memset(&sentinel, 0, sizeof(sentinel));
        cur = &sentinel;
 
-       _sethtent();
-       while ((p = _gethtent(name, pai)) != NULL) {
+       _sethtent(&hostf);
+       while ((p = _gethtent(&hostf, name, pai)) != NULL) {
                cur->ai_next = p;
                while (cur && cur->ai_next)
                        cur = cur->ai_next;
        }
-       _endhtent();
+       _endhtent(&hostf);
 
        *((struct addrinfo **)rv) = sentinel.ai_next;
        if (sentinel.ai_next == NULL)
@@ -1612,8 +2253,6 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
 }
 
 #ifdef YP
-static char *__ypdomain;
-
 /*ARGSUSED*/
 static struct addrinfo *
 _yphostent(char *line, const struct addrinfo *pai)
@@ -1696,10 +2335,14 @@ _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
 {
        struct addrinfo sentinel, *cur;
        struct addrinfo *ai = NULL;
-       static char *__ypcurrent;
-       int __ypcurrentlen, r;
+       char *ypbuf;
+       int ypbuflen, r;
        const char *name;
        const struct addrinfo *pai;
+       char *ypdomain;
+
+       if (_yp_check(&ypdomain) == 0)
+               return NS_UNAVAIL;
 
        name = va_arg(ap, char *);
        pai = va_arg(ap, const struct addrinfo *);
@@ -1707,46 +2350,37 @@ _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
        memset(&sentinel, 0, sizeof(sentinel));
        cur = &sentinel;
 
-       if (!__ypdomain) {
-               if (_yp_check(&__ypdomain) == 0)
-                       return NS_UNAVAIL;
-       }
-       if (__ypcurrent)
-               free(__ypcurrent);
-       __ypcurrent = NULL;
-
        /* hosts.byname is only for IPv4 (Solaris8) */
        if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
-               r = yp_match(__ypdomain, "hosts.byname", name,
-                       (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+               r = yp_match(ypdomain, "hosts.byname", name,
+                       (int)strlen(name), &ypbuf, &ypbuflen);
                if (r == 0) {
                        struct addrinfo ai4;
 
                        ai4 = *pai;
                        ai4.ai_family = AF_INET;
-                       ai = _yphostent(__ypcurrent, &ai4);
+                       ai = _yphostent(ypbuf, &ai4);
                        if (ai) {
                                cur->ai_next = ai;
                                while (cur && cur->ai_next)
                                        cur = cur->ai_next;
                        }
+                       free(ypbuf);
                }
        }
 
        /* ipnodes.byname can hold both IPv4/v6 */
-       r = yp_match(__ypdomain, "ipnodes.byname", name,
-               (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+       r = yp_match(ypdomain, "ipnodes.byname", name,
+               (int)strlen(name), &ypbuf, &ypbuflen);
        if (r == 0) {
-               ai = _yphostent(__ypcurrent, pai);
-               if (ai) {
+               ai = _yphostent(ypbuf, pai);
+               if (ai)
                        cur->ai_next = ai;
-                       while (cur && cur->ai_next)
-                               cur = cur->ai_next;
-               }
+               free(ypbuf);
        }
 
        if (sentinel.ai_next == NULL) {
-               h_errno = HOST_NOT_FOUND;
+               RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND);
                return NS_NOTFOUND;
        }
        *((struct addrinfo **)rv) = sentinel.ai_next;
@@ -1756,188 +2390,6 @@ _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
 
 /* resolver logic */
 
-extern const char *__hostalias (const char *);
-extern int h_errno;
-
-
-#ifdef NS_CACHING
-static int
-addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap,
-    void *cache_mdata)
-{
-       res_state statp;
-       u_long res_options;
-
-       const int op_id = 0;    /* identifies the getaddrinfo for the cache */
-       char *hostname;
-       struct addrinfo *hints;
-
-       char *p;
-       int ai_flags, ai_family, ai_socktype, ai_protocol;
-       size_t desired_size, size;
-
-       statp = __res_state();
-       res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
-           RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
-
-       hostname = va_arg(ap, char *);
-       hints = va_arg(ap, struct addrinfo *);
-
-       desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4;
-       if (hostname != NULL) {
-               size = strlen(hostname);
-               desired_size += size + 1;
-       } else
-               size = 0;
-
-       if (desired_size > *buffer_size) {
-               *buffer_size = desired_size;
-               return (NS_RETURN);
-       }
-
-       if (hints == NULL)
-               ai_flags = ai_family = ai_socktype = ai_protocol = 0;
-       else {
-               ai_flags = hints->ai_flags;
-               ai_family = hints->ai_family;
-               ai_socktype = hints->ai_socktype;
-               ai_protocol = hints->ai_protocol;
-       }
-
-       p = buffer;
-       memcpy(p, &res_options, sizeof(res_options));
-       p += sizeof(res_options);
-
-       memcpy(p, &op_id, sizeof(int));
-       p += sizeof(int);
-
-       memcpy(p, &ai_flags, sizeof(int));
-       p += sizeof(int);
-
-       memcpy(p, &ai_family, sizeof(int));
-       p += sizeof(int);
-
-       memcpy(p, &ai_socktype, sizeof(int));
-       p += sizeof(int);
-
-       memcpy(p, &ai_protocol, sizeof(int));
-       p += sizeof(int);
-
-       if (hostname != NULL)
-               memcpy(p, hostname, size);
-
-       *buffer_size = desired_size;
-       return (NS_SUCCESS);
-}
-
-static int
-addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval,
-    va_list ap, void *cache_mdata)
-{
-       struct addrinfo *ai, *cai;
-       char *p;
-       size_t desired_size, size, ai_size;
-
-       ai = *((struct addrinfo **)retval);
-
-       desired_size = sizeof(size_t);
-       ai_size = 0;
-       for (cai = ai; cai != NULL; cai = cai->ai_next) {
-               desired_size += sizeof(struct addrinfo) + cai->ai_addrlen;
-               if (cai->ai_canonname != NULL)
-                       desired_size += sizeof(size_t) +
-                           strlen(cai->ai_canonname);
-               ++ai_size;
-       }
-
-       if (desired_size > *buffer_size) {
-               /* this assignment is here for future use */
-               errno = ERANGE;
-               *buffer_size = desired_size;
-               return (NS_RETURN);
-       }
-
-       memset(buffer, 0, desired_size);
-       p = buffer;
-
-       memcpy(p, &ai_size, sizeof(size_t));
-       p += sizeof(size_t);
-       for (cai = ai; cai != NULL; cai = cai->ai_next) {
-               memcpy(p, cai, sizeof(struct addrinfo));
-               p += sizeof(struct addrinfo);
-
-               memcpy(p, cai->ai_addr, cai->ai_addrlen);
-               p += cai->ai_addrlen;
-
-               if (cai->ai_canonname != NULL) {
-                       size = strlen(cai->ai_canonname);
-                       memcpy(p, &size, sizeof(size_t));
-                       p += sizeof(size_t);
-
-                       memcpy(p, cai->ai_canonname, size);
-                       p += size;
-               }
-       }
-
-       return (NS_SUCCESS);
-}
-
-static int
-addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
-    va_list ap, void *cache_mdata)
-{
-       struct addrinfo new_ai, *result, *sentinel, *lasts;
-
-       char *p;
-       size_t ai_size, ai_i, size;
-
-       p = buffer;
-       memcpy(&ai_size, p, sizeof(size_t));
-       p += sizeof(size_t);
-
-       result = NULL;
-       lasts = NULL;
-       for (ai_i = 0; ai_i < ai_size; ++ai_i) {
-               memcpy(&new_ai, p, sizeof(struct addrinfo));
-               p += sizeof(struct addrinfo);
-               size = new_ai.ai_addrlen + sizeof(struct addrinfo) +
-                       _ALIGNBYTES;
-
-               sentinel = (struct addrinfo *)malloc(size);
-               memset(sentinel, 0, size);
-
-               memcpy(sentinel, &new_ai, sizeof(struct addrinfo));
-               sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel +
-                   sizeof(struct addrinfo));
-
-               memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen);
-               p += new_ai.ai_addrlen;
-
-               if (new_ai.ai_canonname != NULL) {
-                       memcpy(&size, p, sizeof(size_t));
-                       p += sizeof(size_t);
-
-                       sentinel->ai_canonname = (char *)malloc(size + 1);
-                       memset(sentinel->ai_canonname, 0, size + 1);
-
-                       memcpy(sentinel->ai_canonname, p, size);
-                       p += size;
-               }
-
-               if (result == NULL) {
-                       result = sentinel;
-                       lasts = sentinel;
-               } else {
-                       lasts->ai_next = sentinel;
-                       lasts = sentinel;
-               }
-       }
-
-       *((struct addrinfo **)retval) = result;
-       return (NS_SUCCESS);
-}
-#endif /* NS_CACHING */
-
 /*
  * Formulate a normal query, send, and await answer.
  * Returned answer is placed in supplied buffer "answer".
@@ -1949,12 +2401,12 @@ addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
  * Caller must parse answer and determine whether it answers the question.
  */
 static int
-res_queryN(const char *name,           /* domain name */
-          struct res_target *target)
+res_queryN(const char *name, struct res_target *target, res_state res)
 {
        u_char *buf;
        HEADER *hp;
        int n;
+       u_int oflags;
        struct res_target *t;
        int rcode;
        int ancount;
@@ -1962,15 +2414,10 @@ res_queryN(const char *name,            /* domain name */
        rcode = NOERROR;
        ancount = 0;
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
-       }
-
        buf = malloc(MAXPACKET);
        if (!buf) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
+               RES_SET_H_ERRNO(res, NETDB_INTERNAL);
+               return -1;
        }
 
        for (t = target; t; t = t->next) {
@@ -1979,50 +2426,65 @@ res_queryN(const char *name,            /* domain name */
                int anslen;
 
                hp = (HEADER *)(void *)t->answer;
-               hp->rcode = NOERROR;    /* default */
 
                /* make it easier... */
                class = t->qclass;
                type = t->qtype;
                answer = t->answer;
                anslen = t->anslen;
+
+               oflags = res->_flags;
+
+again:
+               hp->rcode = NOERROR;    /* default */
+
 #ifdef DEBUG
-               if (_res.options & RES_DEBUG)
+               if (res->options & RES_DEBUG)
                        printf(";; res_query(%s, %d, %d)\n", name, class, type);
 #endif
 
-               n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
+               n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
                    buf, MAXPACKET);
-               if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
-                       n = res_opt(n, buf, MAXPACKET, anslen);
+               if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 &&
+                   (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
+                       n = res_nopt(res, n, buf, MAXPACKET, anslen);
                if (n <= 0) {
 #ifdef DEBUG
-                       if (_res.options & RES_DEBUG)
+                       if (res->options & RES_DEBUG)
                                printf(";; res_query: mkquery failed\n");
 #endif
                        free(buf);
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(res, NO_RECOVERY);
                        return (n);
                }
-               n = res_send(buf, n, answer, anslen);
-#if 0
+               n = res_nsend(res, buf, n, answer, anslen);
                if (n < 0) {
+                       /*
+                        * if the query choked with EDNS0, retry
+                        * without EDNS0
+                        */
+                       if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC))
+                           != 0U &&
+                           ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
+                               res->_flags |= RES_F_EDNS0ERR;
+                               if (res->options & RES_DEBUG)
+                                       printf(";; res_nquery: retry without EDNS0\n");
+                               goto again;
+                       }
+                       rcode = hp->rcode;      /* record most recent error */
 #ifdef DEBUG
-                       if (_res.options & RES_DEBUG)
+                       if (res->options & RES_DEBUG)
                                printf(";; res_query: send error\n");
 #endif
-                       free(buf);
-                       h_errno = TRY_AGAIN;
-                       return (n);
+                       continue;
                }
-#endif
 
-               if (n < 0 || n > anslen)
+               if (n > anslen)
                        hp->rcode = FORMERR; /* XXX not very informative */
                if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
                        rcode = hp->rcode;      /* record most recent error */
 #ifdef DEBUG
-                       if (_res.options & RES_DEBUG)
+                       if (res->options & RES_DEBUG)
                                printf(";; rcode = %u, ancount=%u\n", hp->rcode,
                                    ntohs(hp->ancount));
 #endif
@@ -2039,19 +2501,19 @@ res_queryN(const char *name,            /* domain name */
        if (ancount == 0) {
                switch (rcode) {
                case NXDOMAIN:
-                       h_errno = HOST_NOT_FOUND;
+                       RES_SET_H_ERRNO(res, HOST_NOT_FOUND);
                        break;
                case SERVFAIL:
-                       h_errno = TRY_AGAIN;
+                       RES_SET_H_ERRNO(res, TRY_AGAIN);
                        break;
                case NOERROR:
-                       h_errno = NO_DATA;
+                       RES_SET_H_ERRNO(res, NO_DATA);
                        break;
                case FORMERR:
                case NOTIMP:
                case REFUSED:
                default:
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(res, NO_RECOVERY);
                        break;
                }
                return (-1);
@@ -2066,22 +2528,19 @@ res_queryN(const char *name,            /* domain name */
  * is detected.  Error code, if any, is left in h_errno.
  */
 static int
-res_searchN(const char *name,          /* domain name */
-           struct res_target *target)
+res_searchN(const char *name, struct res_target *target, res_state res)
 {
        const char *cp, * const *domain;
        HEADER *hp = (HEADER *)(void *)target->answer;  /*XXX*/
        u_int dots;
        int trailing_dot, ret, saved_herrno;
-       int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
-
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
-       }
+       int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+       int tried_as_is = 0;
+       int searched = 0;
+       char abuf[MAXDNAME];
 
        errno = 0;
-       h_errno = HOST_NOT_FOUND;       /* default, if we never query */
+       RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */
        dots = 0;
        for (cp = name; *cp; cp++)
                dots += (*cp == '.');
@@ -2092,19 +2551,36 @@ res_searchN(const char *name,           /* domain name */
        /*
         * if there aren't any dots, it could be a user-level alias
         */
-       if (!dots && (cp = __hostalias(name)) != NULL)
-               return (res_queryN(cp, target));
+       if (!dots &&
+           (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL)
+               return (res_queryN(cp, target, res));
 
        /*
-        * If there are dots in the name already, let's just give it a try
-        * 'as is'.  The threshold can be set with the "ndots" option.
+        * If there are enough dots in the name, let's just give it a
+        * try 'as is'. The threshold can be set with the "ndots" option.
+        * Also, query 'as is', if there is a trailing dot in the name.
         */
        saved_herrno = -1;
-       if (dots >= _res.ndots) {
-               ret = res_querydomainN(name, NULL, target);
-               if (ret > 0)
+       if (dots >= res->ndots || trailing_dot) {
+               ret = res_querydomainN(name, NULL, target, res);
+               if (ret > 0 || trailing_dot)
                        return (ret);
-               saved_herrno = h_errno;
+               if (errno == ECONNREFUSED) {
+                       RES_SET_H_ERRNO(res, TRY_AGAIN);
+                       return (-1);
+               }
+               switch (res->res_h_errno) {
+               case NO_DATA:
+               case HOST_NOT_FOUND:
+                       break;
+               case TRY_AGAIN:
+                       if (hp->rcode == SERVFAIL)
+                               break;
+                       /* FALLTHROUGH */
+               default:
+                       return (-1);
+               }
+               saved_herrno = res->res_h_errno;
                tried_as_is++;
        }
 
@@ -2114,15 +2590,23 @@ res_searchN(const char *name,           /* domain name */
         *      - there is at least one dot, there is no trailing dot,
         *        and RES_DNSRCH is set.
         */
-       if ((!dots && (_res.options & RES_DEFNAMES)) ||
-           (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
+       if ((!dots && (res->options & RES_DEFNAMES)) ||
+           (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
                int done = 0;
 
-               for (domain = (const char * const *)_res.dnsrch;
+               for (domain = (const char * const *)res->dnsrch;
                   *domain && !done;
                   domain++) {
+                       searched = 1;
+
+                       if (domain[0][0] == '\0' ||
+                           (domain[0][0] == '.' && domain[0][1] == '\0'))
+                               root_on_list++;
+
+                       if (root_on_list && tried_as_is)
+                               continue;
 
-                       ret = res_querydomainN(name, *domain, target);
+                       ret = res_querydomainN(name, *domain, target, res);
                        if (ret > 0)
                                return (ret);
 
@@ -2140,11 +2624,11 @@ res_searchN(const char *name,           /* domain name */
                         * fully-qualified.
                         */
                        if (errno == ECONNREFUSED) {
-                               h_errno = TRY_AGAIN;
+                               RES_SET_H_ERRNO(res, TRY_AGAIN);
                                return (-1);
                        }
 
-                       switch (h_errno) {
+                       switch (res->res_h_errno) {
                        case NO_DATA:
                                got_nodata++;
                                /* FALLTHROUGH */
@@ -2152,9 +2636,9 @@ res_searchN(const char *name,             /* domain name */
                                /* keep trying */
                                break;
                        case TRY_AGAIN:
+                               got_servfail++;
                                if (hp->rcode == SERVFAIL) {
                                        /* try next search element, if any */
-                                       got_servfail++;
                                        break;
                                }
                                /* FALLTHROUGH */
@@ -2166,18 +2650,30 @@ res_searchN(const char *name,           /* domain name */
                         * if we got here for some reason other than DNSRCH,
                         * we only wanted one iteration of the loop, so stop.
                         */
-                       if (!(_res.options & RES_DNSRCH))
+                       if (!(res->options & RES_DNSRCH))
                                done++;
                }
        }
 
+       switch (res->res_h_errno) {
+       case NO_DATA:
+       case HOST_NOT_FOUND:
+               break;
+       case TRY_AGAIN:
+               if (hp->rcode == SERVFAIL)
+                       break;
+               /* FALLTHROUGH */
+       default:
+               goto giveup;
+       }
+
        /*
-        * if we have not already tried the name "as is", do that now.
-        * note that we do this regardless of how many dots were in the
-        * name or whether it ends with a dot.
+        * If the query has not already been tried as is then try it
+        * unless RES_NOTLDQUERY is set and there were no dots.
         */
-       if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
-               ret = res_querydomainN(name, NULL, target);
+       if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) &&
+           !(tried_as_is || root_on_list)) {
+               ret = res_querydomainN(name, NULL, target, res);
                if (ret > 0)
                        return (ret);
        }
@@ -2190,12 +2686,13 @@ res_searchN(const char *name,           /* domain name */
         * else send back meaningless h_errno, that being the one from
         * the last DNSRCH we did.
         */
+giveup:
        if (saved_herrno != -1)
-               h_errno = saved_herrno;
+               RES_SET_H_ERRNO(res, saved_herrno);
        else if (got_nodata)
-               h_errno = NO_DATA;
+               RES_SET_H_ERRNO(res, NO_DATA);
        else if (got_servfail)
-               h_errno = TRY_AGAIN;
+               RES_SET_H_ERRNO(res, TRY_AGAIN);
        return (-1);
 }
 
@@ -2205,18 +2702,14 @@ res_searchN(const char *name,           /* domain name */
  */
 static int
 res_querydomainN(const char *name, const char *domain,
-                struct res_target *target)
+                struct res_target *target, res_state res)
 {
        char nbuf[MAXDNAME];
        const char *longname = nbuf;
        size_t n, d;
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
-       }
 #ifdef DEBUG
-       if (_res.options & RES_DEBUG)
+       if (res->options & RES_DEBUG)
                printf(";; res_querydomain(%s, %s)\n",
                        name, domain?domain:"<Nil>");
 #endif
@@ -2227,7 +2720,7 @@ res_querydomainN(const char *name, const char *domain,
                 */
                n = strlen(name);
                if (n >= MAXDNAME) {
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(res, NO_RECOVERY);
                        return (-1);
                }
                if (n > 0 && name[--n] == '.') {
@@ -2239,10 +2732,10 @@ res_querydomainN(const char *name, const char *domain,
                n = strlen(name);
                d = strlen(domain);
                if (n + d + 1 >= MAXDNAME) {
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(res, NO_RECOVERY);
                        return (-1);
                }
                snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
        }
-       return (res_queryN(longname, target));
+       return (res_queryN(longname, target, res));
 }
index 528a297..19ae1d2 100644 (file)
@@ -12,7 +12,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
+ * 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.
  *
@@ -49,8 +49,8 @@
  * --Copyright--
  *
  * @(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93
- * $From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $
- * $FreeBSD: src/lib/libc/net/gethostbydns.c,v 1.27.2.5 2002/11/02 18:54:57 ume Exp $
+ * From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $
+ * $FreeBSD: src/lib/libc/net/gethostbydns.c,v 1.58 2007/01/09 00:28:02 imp Exp $
  * $DragonFly: src/lib/libc/net/gethostbydns.c,v 1.6 2005/11/13 02:04:47 swildner Exp $
  */
 
 #include <stdarg.h>
 #include <nsswitch.h>
 
+#include "netdb_private.h"
 #include "res_config.h"
 
 #define SPRINTF(x) ((size_t)sprintf x)
 
-#define        MAXALIASES      35
-#define        MAXADDRS        35
-
 static const char AskedForGot[] =
                "gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
 
-static char *h_addr_ptrs[MAXADDRS + 1];
-
-static struct hostent host;
-static char *host_aliases[MAXALIASES];
-static char hostbuf[8*1024];
-static u_char host_addr[16];   /* IPv4 or IPv6 */
-
 #ifdef RESOLVSORT
-static void addrsort (char **, int);
+static void addrsort(char **, int, res_state);
+#endif
+
+#ifdef DEBUG
+static void dprintf(char *, int, res_state) __printflike(1, 0);
 #endif
 
 #define MAXPACKET      (64*1024)
@@ -106,14 +101,13 @@ typedef union {
     char ac;
 } align;
 
-extern int h_errno;
 int _dns_ttl_;
 
 #ifdef DEBUG
 static void
-dprintf(char *msg, int num)
+dprintf(char *msg, int num, res_state res)
 {
-       if (_res.options & RES_DEBUG) {
+       if (res->options & RES_DEBUG) {
                int save = errno;
 
                printf(msg, num);
@@ -121,43 +115,44 @@ dprintf(char *msg, int num)
        }
 }
 #else
-# define dprintf(msg, num) /*nada*/
+# define dprintf(msg, num, res) /*nada*/
 #endif
 
 #define BOUNDED_INCR(x) \
        do { \
                cp += x; \
                if (cp > eom) { \
-                       h_errno = NO_RECOVERY; \
-                       return (NULL); \
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY); \
+                       return (-1); \
                } \
        } while (0)
 
 #define BOUNDS_CHECK(ptr, count) \
        do { \
                if ((ptr) + (count) > eom) { \
-                       h_errno = NO_RECOVERY; \
-                       return (NULL); \
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY); \
+                       return (-1); \
                } \
        } while (0)
 
-static struct hostent *
-gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
+static int
+gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+             struct hostent *he, struct hostent_data *hed, res_state statp)
 {
        const HEADER *hp;
        const u_char *cp;
        int n;
        const u_char *eom, *erdata;
-       char *bp, **ap, **hap;
-       int type, class, buflen, ancount, qdcount;
+       char *bp, *ep, **ap, **hap;
+       int type, class, ancount, qdcount;
        int haveanswer, had_error;
        int toobig = 0;
        char tbuf[MAXDNAME];
        const char *tname;
-       int (*name_ok) (const char *);
+       int (*name_ok)(const char *);
 
        tname = qname;
-       host.h_name = NULL;
+       he->h_name = NULL;
        eom = answer->buf + anslen;
        switch (qtype) {
        case T_A:
@@ -168,8 +163,8 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                name_ok = res_dnok;
                break;
        default:
-               h_errno = NO_RECOVERY;
-               return (NULL);  /* XXX should be abort(); */
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               return (-1);    /* XXX should be abort(); */
        }
        /*
         * find first satisfactory answer
@@ -177,18 +172,18 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
        hp = &answer->hdr;
        ancount = ntohs(hp->ancount);
        qdcount = ntohs(hp->qdcount);
-       bp = hostbuf;
-       buflen = sizeof hostbuf;
+       bp = hed->hostbuf;
+       ep = hed->hostbuf + sizeof hed->hostbuf;
        cp = answer->buf;
        BOUNDED_INCR(HFIXEDSZ);
        if (qdcount != 1) {
-               h_errno = NO_RECOVERY;
-               return (NULL);
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               return (-1);
        }
-       n = dn_expand(answer->buf, eom, cp, bp, buflen);
+       n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
        if ((n < 0) || !(*name_ok)(bp)) {
-               h_errno = NO_RECOVERY;
-               return (NULL);
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               return (-1);
        }
        BOUNDED_INCR(n + QFIXEDSZ);
        if (qtype == T_A || qtype == T_AAAA) {
@@ -198,26 +193,25 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                 */
                n = strlen(bp) + 1;             /* for the \0 */
                if (n >= MAXHOSTNAMELEN) {
-                       h_errno = NO_RECOVERY;
-                       return (NULL);
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
                }
-               host.h_name = bp;
+               he->h_name = bp;
                bp += n;
-               buflen -= n;
                /* The qname can be abbreviated, but h_name is now absolute. */
-               qname = host.h_name;
+               qname = he->h_name;
        }
-       ap = host_aliases;
+       ap = hed->host_aliases;
        *ap = NULL;
-       host.h_aliases = host_aliases;
-       hap = h_addr_ptrs;
+       he->h_aliases = hed->host_aliases;
+       hap = hed->h_addr_ptrs;
        *hap = NULL;
-       host.h_addr_list = h_addr_ptrs;
+       he->h_addr_list = hed->h_addr_ptrs;
        haveanswer = 0;
        had_error = 0;
        _dns_ttl_ = -1;
        while (ancount-- > 0 && cp < eom && !had_error) {
-               n = dn_expand(answer->buf, eom, cp, bp, buflen);
+               n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
                if ((n < 0) || !(*name_ok)(bp)) {
                        had_error++;
                        continue;
@@ -225,9 +219,9 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                cp += n;                        /* name */
                BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
                type = _getshort(cp);
-               cp += INT16SZ;                  /* type */
+               cp += INT16SZ;                  /* type */
                class = _getshort(cp);
-               cp += INT16SZ;                  /* class */
+               cp += INT16SZ;                  /* class */
                if (qtype == T_A  && type == T_A)
                        _dns_ttl_ = _getlong(cp);
                cp += INT32SZ;                  /* TTL */
@@ -241,7 +235,7 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                        continue;               /* XXX - had_error++ ? */
                }
                if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
-                       if (ap >= &host_aliases[MAXALIASES-1])
+                       if (ap >= &hed->host_aliases[_MAXALIASES-1])
                                continue;
                        n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
                        if ((n < 0) || !(*name_ok)(tbuf)) {
@@ -250,8 +244,8 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                        }
                        cp += n;
                        if (cp != erdata) {
-                               h_errno = NO_RECOVERY;
-                               return (NULL);
+                               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                               return (-1);
                        }
                        /* Store alias. */
                        *ap++ = bp;
@@ -261,17 +255,15 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                                continue;
                        }
                        bp += n;
-                       buflen -= n;
                        /* Get canonical name. */
                        n = strlen(tbuf) + 1;   /* for the \0 */
-                       if (n > buflen || n >= MAXHOSTNAMELEN) {
+                       if (n > ep - bp || n >= MAXHOSTNAMELEN) {
                                had_error++;
                                continue;
                        }
                        strcpy(bp, tbuf);
-                       host.h_name = bp;
+                       he->h_name = bp;
                        bp += n;
-                       buflen -= n;
                        continue;
                }
                if (qtype == T_PTR && type == T_CNAME) {
@@ -282,19 +274,18 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                        }
                        cp += n;
                        if (cp != erdata) {
-                               h_errno = NO_RECOVERY;
-                               return (NULL);
+                               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                               return (-1);
                        }
                        /* Get canonical name. */
                        n = strlen(tbuf) + 1;   /* for the \0 */
-                       if (n > buflen || n >= MAXHOSTNAMELEN) {
+                       if (n > ep - bp || n >= MAXHOSTNAMELEN) {
                                had_error++;
                                continue;
                        }
                        strcpy(bp, tbuf);
                        tname = bp;
                        bp += n;
-                       buflen -= n;
                        continue;
                }
                if (type != qtype) {
@@ -314,7 +305,7 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                                cp += n;
                                continue;       /* XXX - had_error++ ? */
                        }
-                       n = dn_expand(answer->buf, eom, cp, bp, buflen);
+                       n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
                        if ((n < 0) || !res_hnok(bp)) {
                                had_error++;
                                break;
@@ -322,12 +313,12 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
 #if MULTI_PTRS_ARE_ALIASES
                        cp += n;
                        if (cp != erdata) {
-                               h_errno = NO_RECOVERY;
-                               return (NULL);
+                               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                               return (-1);
                        }
                        if (!haveanswer)
-                               host.h_name = bp;
-                       else if (ap < &host_aliases[MAXALIASES-1])
+                               he->h_name = bp;
+                       else if (ap < &hed->host_aliases[_MAXALIASES-1])
                                *ap++ = bp;
                        else
                                n = -1;
@@ -338,73 +329,69 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                                        break;
                                }
                                bp += n;
-                               buflen -= n;
                        }
                        break;
 #else
-                       host.h_name = bp;
-                       if (_res.options & RES_USE_INET6) {
+                       he->h_name = bp;
+                       if (statp->options & RES_USE_INET6) {
                                n = strlen(bp) + 1;     /* for the \0 */
                                if (n >= MAXHOSTNAMELEN) {
                                        had_error++;
                                        break;
                                }
                                bp += n;
-                               buflen -= n;
-                               _map_v4v6_hostent(&host, &bp, &buflen);
+                               _map_v4v6_hostent(he, &bp, ep);
                        }
-                       h_errno = NETDB_SUCCESS;
-                       return (&host);
+                       RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+                       return (0);
 #endif
                case T_A:
                case T_AAAA:
-                       if (strcasecmp(host.h_name, bp) != 0) {
+                       if (strcasecmp(he->h_name, bp) != 0) {
                                syslog(LOG_NOTICE|LOG_AUTH,
-                                      AskedForGot, host.h_name, bp);
+                                      AskedForGot, he->h_name, bp);
                                cp += n;
                                continue;       /* XXX - had_error++ ? */
                        }
-                       if (n != host.h_length) {
+                       if (n != he->h_length) {
                                cp += n;
                                continue;
                        }
                        if (!haveanswer) {
                                int nn;
 
-                               host.h_name = bp;
+                               he->h_name = bp;
                                nn = strlen(bp) + 1;    /* for the \0 */
                                bp += nn;
-                               buflen -= nn;
                        }
 
-                       buflen -= sizeof(align) - ((u_long)bp % sizeof(align));
                        bp += sizeof(align) - ((u_long)bp % sizeof(align));
 
-                       if (bp + n >= &hostbuf[sizeof hostbuf]) {
-                               dprintf("size (%d) too big\n", n);
+                       if (bp + n >= ep) {
+                               dprintf("size (%d) too big\n", n, statp);
                                had_error++;
                                continue;
                        }
-                       if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
+                       if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) {
                                if (!toobig++)
                                        dprintf("Too many addresses (%d)\n",
-                                               MAXADDRS);
+                                               _MAXADDRS, statp);
                                cp += n;
                                continue;
                        }
-                       bcopy(cp, *hap++ = bp, n);
+                       memcpy(*hap++ = bp, cp, n);
                        bp += n;
-                       buflen -= n;
                        cp += n;
                        if (cp != erdata) {
-                               h_errno = NO_RECOVERY;
-                               return (NULL);
+                               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                               return (-1);
                        }
                        break;
                default:
-                       dprintf("Impossible condition (type=%d)\n", type);
-                       h_errno = NO_RECOVERY;
-                       return (NULL);
+                       dprintf("Impossible condition (type=%d)\n", type,
+                           statp);
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
                        /* BIND has abort() here, too risky on bad data */
                }
                if (!had_error)
@@ -419,236 +406,182 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype)
                 * in its return structures - should give it the "best"
                 * address in that case, not some random one
                 */
-               if (_res.nsort && haveanswer > 1 && qtype == T_A)
-                       addrsort(h_addr_ptrs, haveanswer);
+               if (statp->nsort && haveanswer > 1 && qtype == T_A)
+                       addrsort(hed->h_addr_ptrs, haveanswer, statp);
 # endif /*RESOLVSORT*/
-               if (!host.h_name) {
+               if (!he->h_name) {
                        n = strlen(qname) + 1;  /* for the \0 */
-                       if (n > buflen || n >= MAXHOSTNAMELEN)
+                       if (n > ep - bp || n >= MAXHOSTNAMELEN)
                                goto no_recovery;
                        strcpy(bp, qname);
-                       host.h_name = bp;
+                       he->h_name = bp;
                        bp += n;
-                       buflen -= n;
                }
-               if (_res.options & RES_USE_INET6)
-                       _map_v4v6_hostent(&host, &bp, &buflen);
-               h_errno = NETDB_SUCCESS;
-               return (&host);
+               if (statp->options & RES_USE_INET6)
+                       _map_v4v6_hostent(he, &bp, ep);
+               RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+               return (0);
        }
  no_recovery:
-       h_errno = NO_RECOVERY;
-       return (NULL);
+       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+       return (-1);
 }
 
+/* XXX: for async DNS resolver in ypserv */
 struct hostent *
 __dns_getanswer(const char *answer, int anslen, const char *qname, int qtype)
 {
-       switch(qtype) {
+       struct hostent *he;
+       struct hostent_data *hed;
+       int error;
+       res_state statp;
+
+       statp = __res_state();
+       if ((he = __hostent_init()) == NULL ||
+           (hed = __hostent_data_init()) == NULL) {
+               RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+               return (NULL);
+       }
+       switch (qtype) {
        case T_AAAA:
-               host.h_addrtype = AF_INET6;
-               host.h_length = IN6ADDRSZ;
+               he->h_addrtype = AF_INET6;
+               he->h_length = NS_IN6ADDRSZ;
                break;
        case T_A:
        default:
-               host.h_addrtype = AF_INET;
-               host.h_length = INADDRSZ;
+               he->h_addrtype = AF_INET;
+               he->h_length = NS_INADDRSZ;
                break;
        }
 
-       return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
+       error = gethostanswer((const querybuf *)answer, anslen, qname, qtype,
+           he, hed, statp);
+       return (error == 0) ? he : NULL;
 }
 
 int
 _dns_gethostbyname(void *rval, void *cb_data, va_list ap)
 {
+       const char *name;
+       int af;
+       char *buffer;
+       size_t buflen;
+       int *errnop, *h_errnop;
+       struct hostent *hptr, he;
+       struct hostent_data *hed;
        querybuf *buf;
-       const char *cp, *name;
-       char *bp;
-       int af, n, size, type, len;
-       struct hostent *hp;
+       int n, type, error;
+       res_state statp;
 
        name = va_arg(ap, const char *);
        af = va_arg(ap, int);
-       *(struct hostent **)rval = NULL;
-
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return NS_UNAVAIL;
+       hptr = va_arg(ap, struct hostent *);
+       buffer = va_arg(ap, char *);
+       buflen = va_arg(ap, size_t);
+       errnop = va_arg(ap, int *);
+       h_errnop = va_arg(ap, int *);
+
+       *((struct hostent **)rval) = NULL;
+
+       statp = __res_state();
+       if ((hed = __hostent_data_init()) == NULL) {
+               RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+               *h_errnop = statp->res_h_errno;
+               return (NS_NOTFOUND);
        }
 
+       he.h_addrtype = af;
        switch (af) {
        case AF_INET:
-               size = INADDRSZ;
+               he.h_length = NS_INADDRSZ;
                type = T_A;
                break;
        case AF_INET6:
-               size = IN6ADDRSZ;
+               he.h_length = NS_IN6ADDRSZ;
                type = T_AAAA;
                break;
        default:
-               h_errno = NETDB_INTERNAL;
+               RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+               *h_errnop = statp->res_h_errno;
                errno = EAFNOSUPPORT;
-               return NS_UNAVAIL;
+               return (NS_UNAVAIL);
        }
 
-       host.h_addrtype = af;
-       host.h_length = size;
-
-       /*
-        * if there aren't any dots, it could be a user-level alias.
-        * this is also done in res_query() since we are not the only
-        * function that looks up host names.
-        */
-       if (!strchr(name, '.') && (cp = __hostalias(name)))
-               name = cp;
-
-       /*
-        * disallow names consisting only of digits/dots, unless
-        * they end in a dot.
-        */
-       if (isdigit((unsigned char)name[0]))
-               for (cp = name;; ++cp) {
-                       if (!*cp) {
-                               if (*--cp == '.')
-                                       break;
-                               /*
-                                * All-numeric, no dot at the end.
-                                * Fake up a hostent as if we'd actually
-                                * done a lookup.
-                                */
-                               if (inet_pton(af, name, host_addr) <= 0) {
-                         &nbs