]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - resolv/res_query.c
hurd: Fix build
[thirdparty/glibc.git] / resolv / res_query.c
index a9db837a0131836c7bcff0421e503d1bb7530aaa..ebbe5a6a4ed86abe3fccd4a134bfcf6f613c9bbb 100644 (file)
  * SOFTWARE.
  */
 
-#if defined(LIBC_SCCS) && !defined(lint)
-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>
@@ -79,12 +74,12 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
 #include <errno.h>
 #include <netdb.h>
 #include <resolv.h>
+#include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-
-/* Options.  Leave them on. */
-/* #undef DEBUG */
+#include <shlib-compat.h>
 
 #if PACKETSZ > 65536
 #define MAXPACKET      PACKETSZ
@@ -95,39 +90,33 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
 #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.
- * Returned answer is placed in supplied buffer "answer".
- * 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.
- *
- * Caller must parse answer and determine whether it answers the question.
- */
+__res_context_querydomain (struct resolv_context *,
+                          const char *name, const char *domain,
+                          int class, int type, unsigned char *answer, int anslen,
+                          unsigned char **answerp, unsigned char **answerp2, int *nanswerp2,
+                          int *resplen2, int *answerp2_malloced);
+
+/* Formulate a normal query, send, and await answer.  Returned answer
+   is placed in supplied buffer ANSWER.  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.
+
+   Caller must parse answer and determine whether it answers the
+   question.  */
 int
-__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)
+__res_context_query (struct resolv_context *ctx, const char *name,
+                    int class, int type,
+                    unsigned char *answer, int anslen,
+                    unsigned char **answerp, unsigned char **answerp2,
+                    int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
+       struct __res_state *statp = ctx->resp;
        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;
+       size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE;
        u_char *buf = alloca (bufsize);
        u_char *query1 = buf;
        int nquery1 = -1;
@@ -137,21 +126,18 @@ __libc_res_nquery(res_state statp,
  again:
        hp->rcode = NOERROR;    /* default */
 
-#ifdef DEBUG
-       if (statp->options & RES_DEBUG)
-               printf(";; res_query(%s, %d, %d)\n", name, class, type);
-#endif
-
-       if (type == T_UNSPEC)
+       if (type == T_QUERY_A_AND_AAAA)
          {
-           n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
-                            query1, bufsize);
+           n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL,
+                                      query1, bufsize);
            if (n > 0)
              {
-               if ((oflags & RES_F_EDNS0ERR) == 0
-                   && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
+               if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
                  {
-                   n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
+                   /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+                      buffer can be reallocated.  */
+                   n = __res_nopt (ctx, n, query1, bufsize,
+                                   RESOLV_EDNS_BUFFER_SIZE);
                    if (n < 0)
                      goto unspec_nomem;
                  }
@@ -167,13 +153,14 @@ __libc_res_nquery(res_state statp,
                  }
                int nused = n + npad;
                query2 = buf + nused;
-               n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
-                                NULL, query2, bufsize - nused);
+               n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA,
+                                          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);
+                 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+                    buffer can be reallocated.  */
+                 n = __res_nopt (ctx, n, query2, bufsize,
+                                 RESOLV_EDNS_BUFFER_SIZE);
                nquery2 = n;
              }
 
@@ -181,21 +168,29 @@ __libc_res_nquery(res_state statp,
          }
        else
          {
-           n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-                            query1, bufsize);
+           n = __res_context_mkquery (ctx, QUERY, name, class, type, 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);
+             {
+               /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
+                  can be reallocated.  */
+               size_t advertise;
+               if (answerp == NULL)
+                 advertise = anslen;
+               else
+                 advertise = RESOLV_EDNS_BUFFER_SIZE;
+               n = __res_nopt (ctx, n, query1, bufsize, advertise);
+             }
 
            nquery1 = n;
          }
 
-       if (__builtin_expect (n <= 0, 0) && !use_malloc) {
+       if (__glibc_unlikely (n <= 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;
+               bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET;
                buf = malloc (bufsize);
                if (buf != NULL) {
                        query1 = buf;
@@ -204,42 +199,24 @@ __libc_res_nquery(res_state statp,
                }
        }
        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 (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
                RES_SET_H_ERRNO(statp, NO_RECOVERY);
                if (use_malloc)
                        free (buf);
                return (n);
        }
        assert (answerp == NULL || (void *) *answerp == (void *) answer);
-       n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
-                            anslen, answerp, answerp2, nanswerp2, resplen2,
-                            answerp2_malloced);
+       n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer,
+                               anslen, answerp, answerp2, nanswerp2, resplen2,
+                               answerp2_malloced);
        if (use_malloc)
                free (buf);
        if (n < 0) {
-#ifdef DEBUG
-               if (statp->options & RES_DEBUG)
-                       printf(";; res_query: send error\n");
-#endif
                RES_SET_H_ERRNO(statp, TRY_AGAIN);
                return (n);
        }
 
        if (answerp != NULL)
-         /* __libc_res_nsend might have reallocated the buffer.  */
+         /* __res_context_send might have reallocated the buffer.  */
          hp = (HEADER *) *answerp;
 
        /* We simplify the following tests by assigning HP to HP2 or
@@ -263,15 +240,6 @@ __libc_res_nquery(res_state statp,
 
        if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
            && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
-#ifdef 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 == NOERROR ? hp2->rcode : hp->rcode) {
                case NXDOMAIN:
                        if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
@@ -308,7 +276,24 @@ __libc_res_nquery(res_state statp,
  success:
        return (n);
 }
-libresolv_hidden_def (__libc_res_nquery)
+libresolv_hidden_def (__res_context_query)
+
+/* Common part of res_nquery and res_query.  */
+static int
+context_query_common (struct resolv_context *ctx,
+                     const char *name, int class, int type,
+                     unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_query (ctx, name, class, type, answer, anslen,
+                                   NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nquery(res_state statp,
@@ -317,30 +302,31 @@ res_nquery(res_state statp,
           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);
+  return context_query_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-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.
- */
 int
-__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)
+res_query (const char *name, int class, int type,
+          unsigned char *answer, int anslen)
 {
-       const char *cp, * const *domain;
+  return context_query_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
+}
+
+/* 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.  */
+int
+__res_context_search (struct resolv_context *ctx,
+                     const char *name, int class, int type,
+                     unsigned char *answer, int anslen,
+                     unsigned char **answerp, unsigned char **answerp2,
+                     int *nanswerp2, int *resplen2, int *answerp2_malloced)
+{
+       struct __res_state *statp = ctx->resp;
+       const char *cp;
        HEADER *hp = (HEADER *) answer;
        char tmp[NS_MAXDNAME];
        u_int dots;
@@ -360,16 +346,11 @@ __libc_res_nsearch(res_state statp,
                trailing_dot++;
 
        /* 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 (!dots && (cp = __res_context_hostalias
+                     (ctx, name, tmp, sizeof tmp))!= NULL)
+         return __res_context_query (ctx, cp, class, type, answer,
+                                     anslen, answerp, answerp2,
+                                     nanswerp2, resplen2, answerp2_malloced);
 
        /*
         * If there are enough dots in the name, let's just give it a
@@ -378,11 +359,13 @@ __libc_res_nsearch(res_state statp,
         */
        saved_herrno = -1;
        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)
+               ret = __res_context_querydomain (ctx, 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++;
@@ -394,6 +377,7 @@ __libc_res_nsearch(res_state statp,
                  {
                    free (*answerp2);
                    *answerp2 = NULL;
+                   *nanswerp2 = 0;
                    *answerp2_malloced = 0;
                  }
        }
@@ -408,21 +392,33 @@ __libc_res_nsearch(res_state statp,
            (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
                int done = 0;
 
-               for (domain = (const char * const *)statp->dnsrch;
-                    *domain && !done;
-                    domain++) {
+               for (size_t domain_index = 0; !done; ++domain_index) {
+                       const char *dname = __resolv_context_search_list
+                         (ctx, domain_index);
+                       if (dname == NULL)
+                         break;
                        searched = 1;
 
-                       if (domain[0][0] == '\0' ||
-                           (domain[0][0] == '.' && domain[0][1] == '\0'))
+                       /* __res_context_querydoman 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 = __libc_res_nquerydomain(statp, name, *domain,
-                                                     class, type,
-                                                     answer, anslen, answerp,
-                                                     answerp2, nanswerp2,
-                                                     resplen2, answerp2_malloced);
-                       if (ret > 0)
+                       ret = __res_context_querydomain
+                         (ctx, 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) {
@@ -433,6 +429,7 @@ __libc_res_nsearch(res_state statp,
                          {
                            free (*answerp2);
                            *answerp2 = NULL;
+                           *nanswerp2 = 0;
                            *answerp2_malloced = 0;
                          }
 
@@ -487,11 +484,12 @@ __libc_res_nsearch(res_state statp,
         */
        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 = __res_context_querydomain
+                 (ctx, name, NULL, class, type,
+                  answer, anslen, answerp, answerp2, nanswerp2,
+                  resplen2, answerp2_malloced);
+               if (ret > 0 || (ret == 0 && resplen2 != NULL
+                               && *resplen2 > 0))
                        return (ret);
        }
 
@@ -506,6 +504,7 @@ __libc_res_nsearch(res_state statp,
          {
            free (*answerp2);
            *answerp2 = NULL;
+           *nanswerp2 = 0;
            *answerp2_malloced = 0;
          }
        if (saved_herrno != -1)
@@ -516,7 +515,24 @@ __libc_res_nsearch(res_state statp,
                RES_SET_H_ERRNO(statp, TRY_AGAIN);
        return (-1);
 }
-libresolv_hidden_def (__libc_res_nsearch)
+libresolv_hidden_def (__res_context_search)
+
+/* Common part of res_nsearch and res_search.  */
+static int
+context_search_common (struct resolv_context *ctx,
+                      const char *name, int class, int type,
+                      unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_search (ctx, name, class, type, answer, anslen,
+                                    NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nsearch(res_state statp,
@@ -525,42 +541,35 @@ res_nsearch(res_state statp,
            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);
+  return context_search_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-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.
- */
+int
+res_search (const char *name, int class, int type,
+           unsigned char *answer, int anslen)
+{
+  return context_search_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
+}
+
+/*  Perform a call on res_query on the concatenation of name and
+    domain.  */
 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)
+__res_context_querydomain (struct resolv_context *ctx,
+                          const char *name, const char *domain,
+                          int class, int type,
+                          unsigned char *answer, int anslen,
+                          unsigned char **answerp, unsigned char **answerp2,
+                          int *nanswerp2, int *resplen2,
+                          int *answerp2_malloced)
 {
+       struct __res_state *statp = ctx->resp;
        char nbuf[MAXDNAME];
        const char *longname = nbuf;
        size_t n, d;
 
-#ifdef DEBUG
-       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);
 
                /* Decrement N prior to checking it against MAXDNAME
@@ -571,11 +580,7 @@ __libc_res_nquerydomain(res_state statp,
                        RES_SET_H_ERRNO(statp, NO_RECOVERY);
                        return (-1);
                }
-               if (name[n] == '.') {
-                       strncpy(nbuf, name, n);
-                       nbuf[n] = '\0';
-               } else
-                       longname = name;
+               longname = name;
        } else {
                n = strlen(name);
                d = strlen(domain);
@@ -585,9 +590,28 @@ __libc_res_nquerydomain(res_state statp,
                }
                sprintf(nbuf, "%s.%s", name, domain);
        }
-       return (__libc_res_nquery(statp, longname, class, type, answer,
-                                 anslen, answerp, answerp2, nanswerp2,
-                                 resplen2, answerp2_malloced));
+       return __res_context_query (ctx, longname, class, type, answer,
+                                   anslen, answerp, answerp2, nanswerp2,
+                                   resplen2, answerp2_malloced);
+}
+
+/* Common part of res_nquerydomain and res_querydomain.  */
+static int
+context_querydomain_common (struct resolv_context *ctx,
+                           const char *name, const char *domain,
+                           int class, int type,
+                           unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_querydomain (ctx, name, domain, class, type,
+                                         answer, anslen,
+                                         NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
 }
 
 int
@@ -598,19 +622,28 @@ res_nquerydomain(res_state statp,
            u_char *answer,             /* buffer to put answer */
            int anslen)         /* size of answer */
 {
-       return __libc_res_nquerydomain(statp, name, domain, class, type,
-                                      answer, anslen, NULL, NULL, NULL, NULL,
-                                      NULL);
+  return context_querydomain_common
+    (__resolv_context_get_override (statp),
+     name, domain, class, type, answer, anslen);
+}
+
+int
+res_querydomain (const char *name, const char *domain, int class, int type,
+                unsigned char *answer, int anslen)
+{
+  return context_querydomain_common
+    (__resolv_context_get (), name, domain, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nquerydomain)
 
 const char *
-res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+__res_context_hostalias (struct resolv_context *ctx,
+                        const char *name, char *dst, size_t siz)
+{
        char *file, *cp1, *cp2;
        char buf[BUFSIZ];
        FILE *fp;
 
-       if (statp->options & RES_NOALIASES)
+       if (ctx->resp->options & RES_NOALIASES)
                return (NULL);
        file = getenv("HOSTALIASES");
        if (file == NULL || (fp = fopen(file, "rce")) == NULL)
@@ -640,4 +673,43 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
        fclose(fp);
        return (NULL);
 }
-libresolv_hidden_def (res_hostalias)
+libresolv_hidden_def (__res_context_hostalias)
+
+/* Common part of res_hostalias and hostalias.  */
+static const char *
+context_hostalias_common (struct resolv_context *ctx,
+                         const char *name, char *dst, size_t siz)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return NULL;
+    }
+  const char *result = __res_context_hostalias (ctx, name, dst, siz);
+  __resolv_context_put (ctx);
+  return result;
+}
+
+const char *
+res_hostalias (res_state statp, const char *name, char *dst, size_t siz)
+{
+  return context_hostalias_common
+    (__resolv_context_get_override (statp), name, dst, siz);
+}
+
+const char *
+hostalias (const char *name)
+{
+  static char abuf[MAXDNAME];
+  return context_hostalias_common
+    (__resolv_context_get (), name, abuf, sizeof (abuf));
+}
+
+#if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
+# undef res_query
+# undef res_querydomain
+# undef res_search
+weak_alias (__res_query, res_query);
+weak_alias (__res_querydomain, res_querydomain);
+weak_alias (__res_search, res_search);
+#endif