]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - resolv/res_query.c
Consistency about byte vs character in string.texi
[thirdparty/glibc.git] / resolv / res_query.c
index e9898023bf1b1a230ced8bdce035507c411f342b..4a9b3b3f27288f1c6926082ba5aadcd0427b142e 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * ++Copyright++ 1988, 1993
- * -
  * Copyright (c) 1988, 1993
  *    The Regents of the University of California.  All rights reserved.
  *
  * 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. 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.
  * 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.
@@ -31,7 +25,9 @@
  * 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.
- * -
+ */
+
+/*
  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * 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.
- * -
- * --Copyright--
+ */
+
+/*
+ * 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.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)res_query.c        8.1 (Berkeley) 6/4/93";
-static char rcsid[] = "$Id$";
+static const char sccsid[] = "@(#)res_query.c  8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $";
 #endif /* LIBC_SCCS and not lint */
 
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
-
-#include <stdio.h>
-#include <netdb.h>
-#include <resolv.h>
 #include <ctype.h>
 #include <errno.h>
-#if defined(BSD) && (BSD >= 199306)
-# include <stdlib.h>
-# include <string.h>
-#else
-# include "../conf/portability.h"
-#endif
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#if defined(USE_OPTIONS_H)
-# include <../conf/options.h>
-#endif
+/* Options.  Leave them on. */
+/* #undef DEBUG */
 
-#if PACKETSZ > 1024
+#if PACKETSZ > 65536
 #define MAXPACKET      PACKETSZ
 #else
-#define MAXPACKET      1024
+#define MAXPACKET      65536
 #endif
 
-const char *hostalias __P((const char *));
+#define QUERYSIZE      (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
 
+static int
+__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
+                       int class, int type, u_char *answer, int anslen,
+                       u_char **answerp, u_char **answerp2, int *nanswerp2,
+                       int *resplen2, int *answerp2_malloced);
 
 /*
  * Formulate a normal query, send, and await answer.
@@ -95,129 +106,298 @@ const char *hostalias __P((const char *));
  * Perform preliminary check of answer, returning success only
  * if no error is indicated and the answer count is nonzero.
  * Return the size of the response on success, -1 on error.
- * Error number is left in h_errno.
+ * Error number is left in H_ERRNO.
  *
  * Caller must parse answer and determine whether it answers the question.
  */
 int
-res_query(name, class, type, answer, anslen)
-       const char *name;       /* domain name */
-       int class, type;        /* class and type of query */
-       u_char *answer;         /* buffer to put answer */
-       int anslen;             /* size of answer buffer */
+__libc_res_nquery(res_state statp,
+                 const char *name,     /* domain name */
+                 int class, int type,  /* class and type of query */
+                 u_char *answer,       /* buffer to put answer */
+                 int anslen,           /* size of answer buffer */
+                 u_char **answerp,     /* if buffer needs to be enlarged */
+                 u_char **answerp2,
+                 int *nanswerp2,
+                 int *resplen2,
+                 int *answerp2_malloced)
 {
-       u_char buf[MAXPACKET];
-       register HEADER *hp = (HEADER *) answer;
-       int n;
+       HEADER *hp = (HEADER *) answer;
+       HEADER *hp2;
+       int n, use_malloc = 0;
+       u_int oflags = statp->_flags;
 
+       size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
+       u_char *buf = alloca (bufsize);
+       u_char *query1 = buf;
+       int nquery1 = -1;
+       u_char *query2 = NULL;
+       int nquery2 = 0;
+
+ again:
        hp->rcode = NOERROR;    /* default */
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
-       }
 #ifdef DEBUG
-       if (_res.options & RES_DEBUG)
+       if (statp->options & RES_DEBUG)
                printf(";; res_query(%s, %d, %d)\n", name, class, type);
 #endif
 
-       n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
-                       buf, sizeof(buf));
-       if (n <= 0) {
+       if (type == T_UNSPEC)
+         {
+           n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
+                            query1, bufsize);
+           if (n > 0)
+             {
+               if ((oflags & RES_F_EDNS0ERR) == 0
+                   && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+                 {
+                   n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
+                   if (n < 0)
+                     goto unspec_nomem;
+                 }
+
+               nquery1 = n;
+               /* Align the buffer.  */
+               int npad = ((nquery1 + __alignof__ (HEADER) - 1)
+                           & ~(__alignof__ (HEADER) - 1)) - nquery1;
+               if (n > bufsize - npad)
+                 {
+                   n = -1;
+                   goto unspec_nomem;
+                 }
+               int nused = n + npad;
+               query2 = buf + nused;
+               n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
+                                NULL, query2, bufsize - nused);
+               if (n > 0
+                   && (oflags & RES_F_EDNS0ERR) == 0
+                   && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+                 n = __res_nopt(statp, n, query2, bufsize - nused - n,
+                                anslen / 2);
+               nquery2 = n;
+             }
+
+         unspec_nomem:;
+         }
+       else
+         {
+           n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+                            query1, bufsize);
+
+           if (n > 0
+               && (oflags & RES_F_EDNS0ERR) == 0
+               && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+             n = __res_nopt(statp, n, query1, bufsize, anslen);
+
+           nquery1 = n;
+         }
+
+       if (__builtin_expect (n <= 0, 0) && !use_malloc) {
+               /* Retry just in case res_nmkquery failed because of too
+                  short buffer.  Shouldn't happen.  */
+               bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
+               buf = malloc (bufsize);
+               if (buf != NULL) {
+                       query1 = buf;
+                       use_malloc = 1;
+                       goto again;
+               }
+       }
+       if (__glibc_unlikely (n <= 0))       {
+               /* If the query choked with EDNS0, retry without EDNS0.  */
+               if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0
+                   && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+                       statp->_flags |= RES_F_EDNS0ERR;
 #ifdef DEBUG
-               if (_res.options & RES_DEBUG)
+                       if (statp->options & RES_DEBUG)
+                               printf(";; res_nquery: retry without EDNS0\n");
+#endif
+                       goto again;
+               }
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
                        printf(";; res_query: mkquery failed\n");
 #endif
-               h_errno = NO_RECOVERY;
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               if (use_malloc)
+                       free (buf);
                return (n);
        }
-       n = res_send(buf, n, answer, anslen);
+       assert (answerp == NULL || (void *) *answerp == (void *) answer);
+       n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
+                            anslen, answerp, answerp2, nanswerp2, resplen2,
+                            answerp2_malloced);
+       if (use_malloc)
+               free (buf);
        if (n < 0) {
 #ifdef DEBUG
-               if (_res.options & RES_DEBUG)
+               if (statp->options & RES_DEBUG)
                        printf(";; res_query: send error\n");
 #endif
-               h_errno = TRY_AGAIN;
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
                return (n);
        }
 
-       if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+       if (answerp != NULL)
+         /* __libc_res_nsend might have reallocated the buffer.  */
+         hp = (HEADER *) *answerp;
+
+       /* We simplify the following tests by assigning HP to HP2 or
+          vice versa.  It is easy to verify that this is the same as
+          ignoring all tests of HP or HP2.  */
+       if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER))
+         {
+           hp2 = hp;
+         }
+       else
+         {
+           hp2 = (HEADER *) *answerp2;
+           if (n < (int) sizeof (HEADER))
+             {
+               hp = hp2;
+             }
+         }
+
+       /* Make sure both hp and hp2 are defined */
+       assert((hp != NULL) && (hp2 != NULL));
+
+       if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
+           && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
 #ifdef DEBUG
-               if (_res.options & RES_DEBUG)
+               if (statp->options & RES_DEBUG) {
                        printf(";; rcode = %d, ancount=%d\n", hp->rcode,
                            ntohs(hp->ancount));
+                       if (hp != hp2)
+                         printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
+                                ntohs(hp2->ancount));
+               }
 #endif
-               switch (hp->rcode) {
+               switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
                case NXDOMAIN:
-                       h_errno = HOST_NOT_FOUND;
+                       if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
+                           || (hp2->rcode == NOERROR
+                               && ntohs (hp2->ancount) != 0))
+                               goto success;
+                       RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
                        break;
                case SERVFAIL:
-                       h_errno = TRY_AGAIN;
+                       RES_SET_H_ERRNO(statp, TRY_AGAIN);
                        break;
                case NOERROR:
-                       h_errno = NO_DATA;
+                       if (ntohs (hp->ancount) != 0
+                           || ntohs (hp2->ancount) != 0)
+                               goto success;
+                       RES_SET_H_ERRNO(statp, NO_DATA);
                        break;
                case FORMERR:
                case NOTIMP:
+                       /* Servers must not reply to AAAA queries with
+                          NOTIMP etc but some of them do.  */
+                       if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
+                           || (hp2->rcode == NOERROR
+                               && ntohs (hp2->ancount) != 0))
+                               goto success;
+                       /* FALLTHROUGH */
                case REFUSED:
                default:
-                       h_errno = NO_RECOVERY;
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
                        break;
                }
                return (-1);
        }
+ success:
        return (n);
 }
+libresolv_hidden_def (__libc_res_nquery)
+
+int
+res_nquery(res_state statp,
+          const char *name,    /* domain name */
+          int class, int type, /* class and type of query */
+          u_char *answer,      /* buffer to put answer */
+          int anslen)          /* size of answer buffer */
+{
+       return __libc_res_nquery(statp, name, class, type, answer, anslen,
+                                NULL, NULL, NULL, NULL, NULL);
+}
+libresolv_hidden_def (res_nquery)
 
 /*
  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  * Return the size of the response on success, -1 on error.
  * If enabled, implement search rules until answer or unrecoverable failure
- * is detected.  Error code, if any, is left in h_errno.
+ * is detected.  Error code, if any, is left in H_ERRNO.
  */
 int
-res_search(name, class, type, answer, anslen)
-       const char *name;       /* domain name */
-       int class, type;        /* class and type of query */
-       u_char *answer;         /* buffer to put answer */
-       int anslen;             /* size of answer */
+__libc_res_nsearch(res_state statp,
+                  const char *name,    /* domain name */
+                  int class, int type, /* class and type of query */
+                  u_char *answer,      /* buffer to put answer */
+                  int anslen,          /* size of answer */
+                  u_char **answerp,
+                  u_char **answerp2,
+                  int *nanswerp2,
+                  int *resplen2,
+                  int *answerp2_malloced)
 {
-       register const char *cp, * const *domain;
+       const char *cp, * const *domain;
        HEADER *hp = (HEADER *) answer;
+       char tmp[NS_MAXDNAME];
        u_int dots;
        int trailing_dot, ret, saved_herrno;
-       int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
+       int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+       int tried_as_is = 0;
+       int searched = 0;
 
-       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
-               h_errno = NETDB_INTERNAL;
-               return (-1);
-       }
        __set_errno (0);
-       h_errno = HOST_NOT_FOUND;       /* default, if we never query */
+       RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
+
        dots = 0;
-       for (cp = name; *cp; cp++)
+       for (cp = name; *cp != '\0'; cp++)
                dots += (*cp == '.');
        trailing_dot = 0;
        if (cp > name && *--cp == '.')
                trailing_dot++;
 
-       /*
-        * if there aren't any dots, it could be a user-level alias
-        */
-       if (!dots && (cp = __hostalias(name)) != NULL)
-               return (res_query(cp, class, type, answer, anslen));
+       /* If there aren't any dots, it could be a user-level alias. */
+       if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+               return (__libc_res_nquery(statp, cp, class, type, answer,
+                                         anslen, answerp, answerp2,
+                                         nanswerp2, resplen2, answerp2_malloced));
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
+                      (int)dots,(int)statp->ndots,(int)trailing_dot,name);
+#endif
 
        /*
-        * 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_querydomain(name, NULL, class, type, answer, anslen);
-               if (ret > 0)
+       if (dots >= statp->ndots || trailing_dot) {
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+                                             answerp2, nanswerp2, resplen2,
+                                             answerp2_malloced);
+               if (ret > 0 || trailing_dot
+                   /* If the second response is valid then we use that.  */
+                   || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
                        return (ret);
                saved_herrno = h_errno;
                tried_as_is++;
+               if (answerp && *answerp != answer) {
+                       answer = *answerp;
+                       anslen = MAXPACKET;
+               }
+               if (answerp2 && *answerp2_malloced)
+                 {
+                   free (*answerp2);
+                   *answerp2 = NULL;
+                   *answerp2_malloced = 0;
+                 }
        }
 
        /*
@@ -226,19 +406,50 @@ res_search(name, class, type, answer, anslen)
         *      - 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 && (statp->options & RES_DEFNAMES) != 0) ||
+           (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
                int done = 0;
 
-               for (domain = (const char * const *)_res.dnsrch;
+               for (domain = (const char * const *)statp->dnsrch;
                     *domain && !done;
                     domain++) {
+                       const char *dname = domain[0];
+                       searched = 1;
+
+                       /* __libc_res_nquerydoman concatenates name
+                          with dname with a "." in between.  If we
+                          pass it in dname the "." we got from the
+                          configured default search path, we'll end
+                          up with "name..", which won't resolve.
+                          OTOH, passing it "" will result in "name.",
+                          which has the intended effect for both
+                          possible representations of the root
+                          domain.  */
+                       if (dname[0] == '.')
+                               dname++;
+                       if (dname[0] == '\0')
+                               root_on_list++;
 
-                       ret = res_querydomain(name, *domain, class, type,
-                                             answer, anslen);
-                       if (ret > 0)
+                       ret = __libc_res_nquerydomain(statp, name, dname,
+                                                     class, type,
+                                                     answer, anslen, answerp,
+                                                     answerp2, nanswerp2,
+                                                     resplen2, answerp2_malloced);
+                       if (ret > 0 || (ret == 0 && resplen2 != NULL
+                                       && *resplen2 > 0))
                                return (ret);
 
+                       if (answerp && *answerp != answer) {
+                               answer = *answerp;
+                               anslen = MAXPACKET;
+                       }
+                       if (answerp2 && *answerp2_malloced)
+                         {
+                           free (*answerp2);
+                           *answerp2 = NULL;
+                           *answerp2_malloced = 0;
+                         }
+
                        /*
                         * If no server present, give up.
                         * If name isn't found in this domain,
@@ -253,11 +464,11 @@ res_search(name, class, type, answer, anslen)
                         * fully-qualified.
                         */
                        if (errno == ECONNREFUSED) {
-                               h_errno = TRY_AGAIN;
+                               RES_SET_H_ERRNO(statp, TRY_AGAIN);
                                return (-1);
                        }
 
-                       switch (h_errno) {
+                       switch (statp->res_h_errno) {
                        case NO_DATA:
                                got_nodata++;
                                /* FALLTHROUGH */
@@ -279,92 +490,136 @@ res_search(name, class, type, answer, anslen)
                        /* 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 ((statp->options & RES_DNSRCH) == 0)
                                done++;
                }
        }
 
-       /* 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) {
-               ret = res_querydomain(name, NULL, class, type, answer, anslen);
-               if (ret > 0)
+       if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
+           && !(tried_as_is || root_on_list)) {
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp,
+                                             answerp2, nanswerp2, resplen2,
+                                             answerp2_malloced);
+               if (ret > 0 || (ret == 0 && resplen2 != NULL
+                               && *resplen2 > 0))
                        return (ret);
        }
 
        /* if we got here, we didn't satisfy the search.
-        * if we did an initial full query, return that query's h_errno
+        * if we did an initial full query, return that query's H_ERRNO
         * (note that we wouldn't be here if that query had succeeded).
         * else if we ever got a nodata, send that back as the reason.
-        * else send back meaningless h_errno, that being the one from
+        * else send back meaningless H_ERRNO, that being the one from
         * the last DNSRCH we did.
         */
+       if (answerp2 && *answerp2_malloced)
+         {
+           free (*answerp2);
+           *answerp2 = NULL;
+           *answerp2_malloced = 0;
+         }
        if (saved_herrno != -1)
-               h_errno = saved_herrno;
+               RES_SET_H_ERRNO(statp, saved_herrno);
        else if (got_nodata)
-               h_errno = NO_DATA;
+               RES_SET_H_ERRNO(statp, NO_DATA);
        else if (got_servfail)
-               h_errno = TRY_AGAIN;
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
        return (-1);
 }
+libresolv_hidden_def (__libc_res_nsearch)
+
+int
+res_nsearch(res_state statp,
+           const char *name,   /* domain name */
+           int class, int type,        /* class and type of query */
+           u_char *answer,     /* buffer to put answer */
+           int anslen)         /* size of answer */
+{
+       return __libc_res_nsearch(statp, name, class, type, answer,
+                                 anslen, NULL, NULL, NULL, NULL, NULL);
+}
+libresolv_hidden_def (res_nsearch)
 
 /*
- * Perform a call on res_query on the concatenation of name and domain,
- * removing a trailing dot from name if domain is NULL.
+ * Perform a call on res_query on the concatenation of name and domain.
  */
-int
-res_querydomain(name, domain, class, type, answer, anslen)
-       const char *name, *domain;
-       int class, type;        /* class and type of query */
-       u_char *answer;         /* buffer to put answer */
-       int anslen;             /* size of answer */
+static int
+__libc_res_nquerydomain(res_state statp,
+                       const char *name,
+                       const char *domain,
+                       int class, int type,    /* class and type of query */
+                       u_char *answer,         /* buffer to put answer */
+                       int anslen,                     /* size of answer */
+                       u_char **answerp,
+                       u_char **answerp2,
+                       int *nanswerp2,
+                       int *resplen2,
+                       int *answerp2_malloced)
 {
        char nbuf[MAXDNAME];
        const char *longname = nbuf;
-       int n;
+       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)
-               printf(";; res_querydomain(%s, %s, %d, %d)\n",
+       if (statp->options & RES_DEBUG)
+               printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
                       name, domain?domain:"<Nil>", class, type);
 #endif
        if (domain == NULL) {
-               /*
-                * Check for trailing '.';
-                * copy without '.' if present.
-                */
-               n = strlen(name) - 1;
-               if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) {
-                       bcopy(name, nbuf, n);
-                       nbuf[n] = '\0';
-               } else
-                       longname = name;
-       } else
-               sprintf(nbuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
-
-       return (res_query(longname, class, type, answer, anslen));
+               n = strlen(name);
+
+               /* Decrement N prior to checking it against MAXDNAME
+                  so that we detect a wrap to SIZE_MAX and return
+                  a reasonable error.  */
+               n--;
+               if (n >= MAXDNAME - 1) {
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
+               }
+               longname = name;
+       } else {
+               n = strlen(name);
+               d = strlen(domain);
+               if (n + d + 1 >= MAXDNAME) {
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
+               }
+               sprintf(nbuf, "%s.%s", name, domain);
+       }
+       return (__libc_res_nquery(statp, longname, class, type, answer,
+                                 anslen, answerp, answerp2, nanswerp2,
+                                 resplen2, answerp2_malloced));
 }
 
-const char *
-hostalias(name)
-       register const char *name;
+int
+res_nquerydomain(res_state statp,
+           const char *name,
+           const char *domain,
+           int class, int type,        /* class and type of query */
+           u_char *answer,             /* buffer to put answer */
+           int anslen)         /* size of answer */
 {
-       register char *cp1, *cp2;
-       FILE *fp;
-       char *file;
+       return __libc_res_nquerydomain(statp, name, domain, class, type,
+                                      answer, anslen, NULL, NULL, NULL, NULL,
+                                      NULL);
+}
+libresolv_hidden_def (res_nquerydomain)
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+       char *file, *cp1, *cp2;
        char buf[BUFSIZ];
-       static char abuf[MAXDNAME];
+       FILE *fp;
 
-       if (_res.options & RES_NOALIASES)
+       if (statp->options & RES_NOALIASES)
                return (NULL);
        file = getenv("HOSTALIASES");
-       if (file == NULL || (fp = fopen(file, "r")) == NULL)
+       if (file == NULL || (fp = fopen(file, "rce")) == NULL)
                return (NULL);
        setbuf(fp, NULL);
        buf[sizeof(buf) - 1] = '\0';
@@ -374,19 +629,21 @@ hostalias(name)
                if (!*cp1)
                        break;
                *cp1 = '\0';
-               if (!strcasecmp(buf, name)) {
+               if (ns_samename(buf, name) == 1) {
                        while (isspace(*++cp1))
                                ;
                        if (!*cp1)
                                break;
                        for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
                                ;
-                       abuf[sizeof(abuf) - 1] = *cp2 = '\0';
-                       strncpy(abuf, cp1, sizeof(abuf) - 1);
+                       *cp2 = '\0';
+                       strncpy(dst, cp1, siz - 1);
+                       dst[siz - 1] = '\0';
                        fclose(fp);
-                       return (abuf);
+                       return (dst);
                }
        }
        fclose(fp);
        return (NULL);
 }
+libresolv_hidden_def (res_hostalias)