Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 17 Oct 2002 21:51:21 +0000 (21:51 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 17 Oct 2002 21:51:21 +0000 (21:51 +0000)
2002-10-15  Jakub Jelinek  <jakub@redhat.com>

* include/resolv.h (__libc_res_nquery, __libc_res_nsearch,
__libc_res_nsend): New prototypes.
* resolv/res_query.c (QUERYSIZE): Define.
(__libc_res_nquery): Renamed from res_nquery.  Added answerp
argument.  Allocate only QUERYSIZE bytes first, if res_nmkquery
fails use MAXPACKET buffer.  Call __libc_res_nsend instead of
res_nsend, pass answerp.
(res_nquery): Changed into wrapper around __libc_res_nquery.
(__libc_res_nsearch): Renamed from res_nsearch.  Added answerp
argument.  Call __libc_res_nquerydomain and __libc_res_nquery
instead of the non-__libc_ variants, pass them answerp.
(res_nsearch): Changed into wrapper around __libc_res_nsearch.
(__libc_res_nquerydomain): Renamed from res_nquerydomain.
Added answerp argument.  Call __libc_res_nquery instead of
res_nquery, pass answerp.
(res_nquerydomain): Changed into wrapper around
__libc_res_nquerydomain.
* resolv/res_send.c: Include sys/ioctl.h.
(MAXPACKET): Define.
(send_vc): Change arguments.  Reallocate answer buffer if it is
too small.
(send_dg): Likewise.
(__libc_res_nsend): Renamed from res_nsend.  Added ansp argument.
Reallocate answer buffer if it is too small and hooks are in use.
Adjust calls to send_vc and send_dg.
(res_nsend): Changed into wrapper around __libc_res_nsend.
* resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname2_r): Allocate
just 1K answer buffer on the stack, use __libc_res_nsearch instead
of res_nsearch.
(_nss_dns_gethostbyaddr_r): Similarly with __libc_res_nquery.
* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise.
(_nss_dns_getnetbyname_r): Similarly with __libc_res_nsearch.
* resolv/gethnamaddr.c (gethostbyname2): Likewise.
(gethostbyaddr): Similarly with __libc_res_nquery.
* resolv/Versions (libresolv): Export __libc_res_nquery and
__libc_res_nsearch at GLIBC_PRIVATE.

ChangeLog
include/resolv.h
resolv/Versions
resolv/gethnamaddr.c
resolv/nss_dns/dns-host.c
resolv/nss_dns/dns-network.c
resolv/res_query.c
resolv/res_send.c

index 6207754..ebf51b7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2002-10-15  Jakub Jelinek  <jakub@redhat.com>
+
+       * include/resolv.h (__libc_res_nquery, __libc_res_nsearch,
+       __libc_res_nsend): New prototypes.
+       * resolv/res_query.c (QUERYSIZE): Define.
+       (__libc_res_nquery): Renamed from res_nquery.  Added answerp
+       argument.  Allocate only QUERYSIZE bytes first, if res_nmkquery
+       fails use MAXPACKET buffer.  Call __libc_res_nsend instead of
+       res_nsend, pass answerp.
+       (res_nquery): Changed into wrapper around __libc_res_nquery.
+       (__libc_res_nsearch): Renamed from res_nsearch.  Added answerp
+       argument.  Call __libc_res_nquerydomain and __libc_res_nquery
+       instead of the non-__libc_ variants, pass them answerp.
+       (res_nsearch): Changed into wrapper around __libc_res_nsearch.
+       (__libc_res_nquerydomain): Renamed from res_nquerydomain.
+       Added answerp argument.  Call __libc_res_nquery instead of
+       res_nquery, pass answerp.
+       (res_nquerydomain): Changed into wrapper around
+       __libc_res_nquerydomain.
+       * resolv/res_send.c: Include sys/ioctl.h.
+       (MAXPACKET): Define.
+       (send_vc): Change arguments.  Reallocate answer buffer if it is
+       too small.
+       (send_dg): Likewise.
+       (__libc_res_nsend): Renamed from res_nsend.  Added ansp argument.
+       Reallocate answer buffer if it is too small and hooks are in use.
+       Adjust calls to send_vc and send_dg.
+       (res_nsend): Changed into wrapper around __libc_res_nsend.
+       * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname2_r): Allocate
+       just 1K answer buffer on the stack, use __libc_res_nsearch instead
+       of res_nsearch.
+       (_nss_dns_gethostbyaddr_r): Similarly with __libc_res_nquery.
+       * resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise.
+       (_nss_dns_getnetbyname_r): Similarly with __libc_res_nsearch.
+       * resolv/gethnamaddr.c (gethostbyname2): Likewise.
+       (gethostbyaddr): Similarly with __libc_res_nquery.
+       * resolv/Versions (libresolv): Export __libc_res_nquery and
+       __libc_res_nsearch at GLIBC_PRIVATE.
+
 2002-10-17  Roland McGrath  <roland@redhat.com>
 
        * sysdeps/x86_64/dl-machine.h (elf_machine_rela): Do CHECK_STATIC_TLS
index 12b4f74..8b5b852 100644 (file)
@@ -46,6 +46,15 @@ extern int res_ourserver_p (const res_state __statp,
                            const struct sockaddr_in6 *__inp);
 libc_hidden_proto (__res_ninit)
 libc_hidden_proto (__res_randomid)
+
+int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
+                      u_char **);
+int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
+                       u_char **);
+int __libc_res_nsend (res_state, const u_char *, int, u_char *, int,
+                     u_char **)
+  attribute_hidden;
+
 #endif
 
 #endif
index ab6a386..09dca6a 100644 (file)
@@ -72,6 +72,7 @@ libresolv {
     # Needed in libnss_dns.
     __ns_name_unpack; __ns_name_ntop;
     __ns_get16; __ns_samename;
+    __libc_res_nquery; __libc_res_nsearch;
   }
 }
 
index 797af94..e941b5c 100644 (file)
@@ -510,10 +510,10 @@ gethostbyname2(name, af)
        const char *name;
        int af;
 {
-       querybuf *buf;
+       querybuf *buf, *origbuf;
        register const char *cp;
        char *bp;
-       int n, size, type, len, use_malloc = 0;
+       int n, size, type, len;
        struct hostent *ret;
        extern struct hostent *_gethtbyname2();
 
@@ -616,24 +616,19 @@ gethostbyname2(name, af)
                                break;
                }
 
-       if (!__libc_use_alloca (MAXPACKET)) {
-               buf = (querybuf *) malloc (sizeof (*buf));
-               if (buf == NULL) {
-                       __set_h_errno (NETDB_INTERNAL);
-                       return NULL;
-               }
-               use_malloc = 1;
-       } else
-               buf = (querybuf *) alloca (sizeof (*buf));
+       buf = origbuf = (querybuf *) alloca (1024);
 
-       if ((n = res_nsearch(&_res, name, C_IN, type, buf->buf, sizeof(buf->buf))) < 0) {
+       if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf->buf, 1024,
+                                   (u_char **) &buf)) < 0) {
+               if (buf != origbuf)
+                       free (buf);
                dprintf("res_nsearch failed (%d)\n", n);
                if (errno == ECONNREFUSED)
                        return (_gethtbyname2(name, af));
                return (NULL);
        }
        ret = getanswer(buf, n, name, type);
-       if (use_malloc)
+       if (buf != origbuf)
                free (buf);
        return ret;
 }
@@ -647,9 +642,9 @@ gethostbyaddr(addr, len, af)
        const u_char *uaddr = (const u_char *)addr;
        static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
        static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
-       int n, use_malloc = 0;
+       int n;
        socklen_t size;
-       querybuf *buf;
+       querybuf *buf, *orig_buf;
        register struct hostent *hp;
        char qbuf[MAXDNAME+1], *qp = NULL;
 #ifdef SUNSECURITY
@@ -711,23 +706,18 @@ gethostbyaddr(addr, len, af)
                abort();
        }
 
-       if (!__libc_use_alloca (MAXPACKET)) {
-               buf = (querybuf *) malloc (sizeof (*buf));
-               if (buf == NULL) {
-                       __set_h_errno (NETDB_INTERNAL);
-                       return NULL;
-               }
-               use_malloc = 1;
-       } else
-               buf = (querybuf *) alloca (sizeof (*buf));
+       buf = orig_buf = (querybuf *) alloca (1024);
 
-       n = res_nquery(&_res, qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
+       n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf->buf, 1024,
+                             (u_char **) &buf);
        if (n < 0 && af == AF_INET6) {
                strcpy(qp, "ip6.int");
-               n = res_nquery(&_res, qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
+               n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf->buf,
+                                     buf != orig_buf ? MAXPACKET : 1024,
+                                     (u_char **) &buf);
        }
        if (n < 0) {
-               if (use_malloc)
+               if (buf != orig_buf)
                        free (buf);
                dprintf("res_nquery failed (%d)\n", n);
                if (errno == ECONNREFUSED)
@@ -735,7 +725,7 @@ gethostbyaddr(addr, len, af)
                return (NULL);
        }
        hp = getanswer(buf, n, qbuf, T_PTR);
-       if (use_malloc)
+       if (buf != orig_buf)
                free (buf);
        if (!hp)
                return (NULL);  /* h_errno was set by getanswer() */
index 39eccab..b01dc54 100644 (file)
@@ -132,11 +132,11 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
                           char *buffer, size_t buflen, int *errnop,
                           int *h_errnop)
 {
-  querybuf *host_buffer;
+  querybuf *host_buffer, *orig_host_buffer;
   char tmp[NS_MAXDNAME];
   int size, type, n;
   const char *cp;
-  int map = 0, use_malloc = 0;
+  int map = 0;
   int olderr = errno;
   enum nss_status status;
 
@@ -170,21 +170,10 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
       && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL)
     name = cp;
 
-  if (!__libc_use_alloca (MAXPACKET))
-    {
-      host_buffer = (querybuf *) malloc (sizeof (querybuf));
-      if (host_buffer == NULL)
-       {
-         *errnop = ENOMEM;
-         return NSS_STATUS_UNAVAIL;
-       }
-      use_malloc = 1;
-    }
-  else
-    host_buffer = (querybuf *) alloca (sizeof (querybuf));
+  host_buffer = orig_host_buffer = (querybuf *) alloca (1024);
 
-  n = res_nsearch (&_res, name, C_IN, type, host_buffer->buf,
-                  sizeof (host_buffer->buf));
+  n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer->buf,
+                         1024, (u_char **) &host_buffer);
   if (n < 0)
     {
       enum nss_status status = (errno == ECONNREFUSED
@@ -199,12 +188,13 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
         by having the RES_USE_INET6 bit in _res.options set, we try
         another lookup.  */
       if (af == AF_INET6 && (_res.options & RES_USE_INET6))
-       n = res_nsearch (&_res, name, C_IN, T_A, host_buffer->buf,
-                        sizeof (host_buffer->buf));
+       n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer->buf,
+                               host_buffer != orig_host_buffer
+                               ? MAXPACKET : 1024, (u_char **) &host_buffer);
 
       if (n < 0)
        {
-         if (use_malloc)
+         if (host_buffer != orig_host_buffer)
            free (host_buffer);
          return status;
        }
@@ -217,7 +207,7 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
 
   status = getanswer_r (host_buffer, n, name, type, result, buffer, buflen,
                        errnop, h_errnop, map);
-  if (use_malloc)
+  if (host_buffer != orig_host_buffer)
     free (host_buffer);
   return status;
 }
@@ -257,10 +247,10 @@ _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
     char *h_addr_ptrs[MAX_NR_ADDRS + 1];
     char linebuffer[0];
   } *host_data = (struct host_data *) buffer;
-  querybuf *host_buffer;
+  querybuf *host_buffer, *orig_host_buffer;
   char qbuf[MAXDNAME+1], *qp = NULL;
   size_t size;
-  int n, status, use_malloc = 0;
+  int n, status;
   int olderr = errno;
 
   if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
@@ -315,39 +305,29 @@ _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af,
       break;
     }
 
-  if (!__libc_use_alloca (MAXPACKET))
-    {
-      host_buffer = (querybuf *) malloc (sizeof (querybuf));
-      if (host_buffer == NULL)
-       {
-         *errnop = ENOMEM;
-         return NSS_STATUS_UNAVAIL;
-       }
-      use_malloc = 1;
-    }
-  else
-    host_buffer = (querybuf *) alloca (sizeof (querybuf));
+  host_buffer = orig_host_buffer = (querybuf *) alloca (1024);
 
-  n = res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer->buf,
-                 sizeof (host_buffer->buf));
+  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer->buf,
+                        1024, (u_char **) &host_buffer);
   if (n < 0 && af == AF_INET6)
     {
       strcpy (qp, "ip6.int");
-      n = res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer->buf,
-                     sizeof (host_buffer->buf));
+      n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer->buf,
+                            host_buffer != orig_host_buffer
+                            ? MAXPACKET : 1024, (u_char **) &host_buffer);
     }
   if (n < 0)
     {
       *h_errnop = h_errno;
       __set_errno (olderr);
-      if (use_malloc)
+      if (host_buffer != orig_host_buffer)
        free (host_buffer);
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
   status = getanswer_r (host_buffer, n, qbuf, T_PTR, result, buffer, buflen,
                        errnop, h_errnop, 0 /* XXX */);
-  if (use_malloc)
+  if (host_buffer != orig_host_buffer)
     free (host_buffer);
   if (status != NSS_STATUS_SUCCESS)
     {
index 9a366ac..5956c84 100644 (file)
@@ -110,8 +110,8 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
                         int *herrnop)
 {
   /* Return entry for network with NAME.  */
-  querybuf *net_buffer;
-  int anslen, use_malloc = 0;
+  querybuf *net_buffer, *orig_net_buffer;
+  int anslen;
   char *qbuf;
   enum nss_status status;
 
@@ -120,26 +120,15 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
 
   qbuf = strdupa (name);
 
-  if (!__libc_use_alloca (MAXPACKET))
-    {
-      net_buffer = (querybuf *) malloc (sizeof (querybuf));
-      if (net_buffer == NULL)
-       {
-         *errnop = ENOMEM;
-         return NSS_STATUS_UNAVAIL;
-       }
-      use_malloc = 1;
-    }
-  else
-    net_buffer = (querybuf *) alloca (sizeof (querybuf));
+  net_buffer = orig_net_buffer = (querybuf *) alloca (1024);
 
-  anslen = res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer->buf,
-                       sizeof (net_buffer->buf));
+  anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer->buf,
+                              1024, (u_char **) &net_buffer);
   if (anslen < 0)
     {
       /* Nothing found.  */
       *errnop = errno;
-      if (use_malloc)
+      if (net_buffer != orig_net_buffer)
        free (net_buffer);
       return (errno == ECONNREFUSED
              || errno == EPFNOSUPPORT
@@ -148,7 +137,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
     }
 
   status = getanswer_r (net_buffer, anslen, result, buffer, buflen, BYNAME);
-  if (use_malloc)
+  if (net_buffer != orig_net_buffer)
     free (net_buffer);
   return status;
 }
@@ -161,10 +150,10 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
 {
   /* Return entry for network with NAME.  */
   enum nss_status status;
-  querybuf *net_buffer;
+  querybuf *net_buffer, *orig_net_buffer;
   unsigned int net_bytes[4];
   char qbuf[MAXDNAME];
-  int cnt, anslen, use_malloc = 0;
+  int cnt, anslen;
   u_int32_t net2;
   int olderr = errno;
 
@@ -201,27 +190,16 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
       break;
     }
 
-  if (!__libc_use_alloca (MAXPACKET))
-    {
-      net_buffer = (querybuf *) malloc (sizeof (querybuf));
-      if (net_buffer == NULL)
-       {
-         *errnop = ENOMEM;
-         return NSS_STATUS_UNAVAIL;
-       }
-      use_malloc = 1;
-    }
-  else
-    net_buffer = (querybuf *) alloca (sizeof (querybuf));
+  net_buffer = orig_net_buffer = (querybuf *) alloca (1024);
 
-  anslen = res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer->buf,
-                      sizeof (net_buffer->buf));
+  anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer->buf,
+                             1024, (u_char **) &net_buffer);
   if (anslen < 0)
     {
       /* Nothing found.  */
       int err = errno;
       __set_errno (olderr);
-      if (use_malloc)
+      if (net_buffer != orig_net_buffer)
        free (net_buffer);
       return (err == ECONNREFUSED
              || err == EPFNOSUPPORT
@@ -230,7 +208,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
     }
 
   status = getanswer_r (net_buffer, anslen, result, buffer, buflen, BYADDR);
-  if (use_malloc)
+  if (net_buffer != orig_net_buffer)
     free (net_buffer);
   if (status == NSS_STATUS_SUCCESS)
     {
index 968ba8b..ab4e02a 100644 (file)
@@ -91,6 +91,13 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
 #define MAXPACKET      65536
 #endif
 
+#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);
+
 /*
  * Formulate a normal query, send, and await answer.
  * Returned answer is placed in supplied buffer "answer".
@@ -102,11 +109,12 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
  * Caller must parse answer and determine whether it answers the question.
  */
 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 */
+__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 *buf;
        HEADER *hp = (HEADER *) answer;
@@ -114,15 +122,7 @@ res_nquery(res_state statp,
 
        hp->rcode = NOERROR;    /* default */
 
-       if (!__libc_use_alloca (MAXPACKET)) {
-               buf = malloc (MAXPACKET);
-               if (buf == NULL) {
-                       __set_h_errno (NETDB_INTERNAL);
-                       return -1;
-               }
-               use_malloc = 1;
-       } else
-               buf = alloca (MAXPACKET);
+       buf = alloca (QUERYSIZE);
 
 #ifdef DEBUG
        if (statp->options & RES_DEBUG)
@@ -130,8 +130,18 @@ res_nquery(res_state statp,
 #endif
 
        n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-                        buf, MAXPACKET);
-       if (n <= 0) {
+                        buf, QUERYSIZE);
+       if (__builtin_expect (n <= 0, 0)) {
+               /* Retry just in case res_nmkquery failed because of too
+                  short buffer.  Shouldn't happen.  */
+               buf = malloc (MAXPACKET);
+               if (buf != NULL) {
+                       use_malloc = 1;
+                       n = res_nmkquery(statp, QUERY, name, class, type, NULL,
+                                        0, NULL, buf, MAXPACKET);
+               }               
+       }
+       if (__builtin_expect (n <= 0, 0)) {
 #ifdef DEBUG
                if (statp->options & RES_DEBUG)
                        printf(";; res_query: mkquery failed\n");
@@ -141,7 +151,7 @@ res_nquery(res_state statp,
                        free (buf);
                return (n);
        }
-       n = res_nsend(statp, buf, n, answer, anslen);
+       n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
        if (use_malloc)
                free (buf);
        if (n < 0) {
@@ -181,6 +191,17 @@ res_nquery(res_state statp,
        return (n);
 }
 
+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);
+}
+
 /*
  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  * Return the size of the response on success, -1 on error.
@@ -188,11 +209,12 @@ res_nquery(res_state statp,
  * is detected.  Error code, if any, is left in H_ERRNO.
  */
 int
-res_nsearch(res_state statp,
+__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 */
+           int anslen,         /* size of answer */
+           u_char **answerp)
 {
        const char *cp, * const *domain;
        HEADER *hp = (HEADER *) answer;
@@ -214,7 +236,8 @@ res_nsearch(res_state statp,
 
        /* 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 (res_nquery(statp, cp, class, type, answer, anslen));
+               return (__libc_res_nquery(statp, cp, class, type, answer,
+                                         anslen, answerp));
 
        /*
         * If there are enough dots in the name, let's just give it a
@@ -223,12 +246,16 @@ res_nsearch(res_state statp,
         */
        saved_herrno = -1;
        if (dots >= statp->ndots || trailing_dot) {
-               ret = res_nquerydomain(statp, name, NULL, class, type,
-                                        answer, anslen);
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp);
                if (ret > 0 || trailing_dot)
                        return (ret);
                saved_herrno = h_errno;
                tried_as_is++;
+               if (answerp && *answerp != answer) {
+                       answer = *answerp;
+                       anslen = MAXPACKET;
+               }
        }
 
        /*
@@ -249,12 +276,17 @@ res_nsearch(res_state statp,
                            (domain[0][0] == '.' && domain[0][1] == '\0'))
                                root_on_list++;
 
-                       ret = res_nquerydomain(statp, name, *domain,
-                                              class, type,
-                                              answer, anslen);
+                       ret = __libc_res_nquerydomain(statp, name, *domain,
+                                                     class, type,
+                                                     answer, anslen, answerp);
                        if (ret > 0)
                                return (ret);
 
+                       if (answerp && *answerp != answer) {
+                               answer = *answerp;
+                               anslen = MAXPACKET;
+                       }
+
                        /*
                         * If no server present, give up.
                         * If name isn't found in this domain,
@@ -306,8 +338,8 @@ res_nsearch(res_state statp,
         * query now.
         */
        if (statp->ndots && !(tried_as_is || root_on_list)) {
-               ret = res_nquerydomain(statp, name, NULL, class, type,
-                                      answer, anslen);
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp);
                if (ret > 0)
                        return (ret);
        }
@@ -328,17 +360,29 @@ res_nsearch(res_state statp,
        return (-1);
 }
 
+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);
+}
+
 /*
  * 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_nquerydomain(res_state statp,
+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 */
+           int anslen,                 /* size of answer */
+           u_char **answerp)
 {
        char nbuf[MAXDNAME];
        const char *longname = nbuf;
@@ -374,7 +418,20 @@ res_nquerydomain(res_state statp,
                }
                sprintf(nbuf, "%s.%s", name, domain);
        }
-       return (res_nquery(statp, longname, class, type, answer, anslen));
+       return (__libc_res_nquery(statp, longname, class, type, answer,
+                                 anslen, answerp));
+}
+
+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 */
+{
+       return __libc_res_nquerydomain(statp, name, domain, class, type,
+                                      answer, anslen, NULL);
 }
 
 const char *
index a163d06..d237c9a 100644 (file)
@@ -85,6 +85,7 @@ static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixi
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
+#include <sys/ioctl.h>
 
 #include <errno.h>
 #include <netdb.h>
@@ -95,6 +96,12 @@ static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixi
 #include <string.h>
 #include <unistd.h>
 
+#if PACKETSZ > 65536
+#define MAXPACKET       PACKETSZ
+#else
+#define MAXPACKET       65536
+#endif
+
 #ifndef _LIBC
 #include <isc/eventlib.h>
 #else
@@ -193,10 +200,10 @@ static const int highestFD = FD_SETSIZE - 1;
 /* Forward. */
 
 static int             send_vc(res_state, const u_char *, int,
-                               u_char *, int, int *, int);
+                               u_char **, int *, int *, int, u_char **);
 static int             send_dg(res_state, const u_char *, int,
-                               u_char *, int, int *, int,
-                               int *, int *);
+                               u_char **, int *, int *, int,
+                               int *, int *, u_char **);
 #ifdef DEBUG
 static void            Aerror(const res_state, FILE *, const char *, int,
                               struct sockaddr_in);
@@ -371,8 +378,8 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1,
 }
 
 int
-res_nsend(res_state statp,
-         const u_char *buf, int buflen, u_char *ans, int anssiz)
+__libc_res_nsend(res_state statp, const u_char *buf, int buflen,
+                u_char *ans, int anssiz, u_char **ansp)
 {
        int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
 
@@ -380,10 +387,22 @@ res_nsend(res_state statp,
                __set_errno (ESRCH);
                return (-1);
        }
+
        if (anssiz < HFIXEDSZ) {
                __set_errno (EINVAL);
                return (-1);
        }
+
+       if ((statp->qhook || statp->rhook) && anssiz < MAXPACKET && ansp) {
+               u_char *buf = malloc (MAXPACKET);
+               if (buf == NULL)
+                       return (-1);
+               memcpy (buf, ans, HFIXEDSZ);
+               *ansp = buf;
+               ans = buf;
+               anssiz = MAXPACKET;
+       }
+
        DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
                (stdout, ";; res_send()\n"), buf, buflen);
        v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
@@ -578,8 +597,8 @@ res_nsend(res_state statp,
                if (v_circuit) {
                        /* Use VC; at most one attempt per server. */
                        try = statp->retry;
-                       n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
-                                   ns);
+                       n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno,
+                                   ns, ansp);
                        if (n < 0)
                                return (-1);
                        if (n == 0)
@@ -587,8 +606,8 @@ res_nsend(res_state statp,
                        resplen = n;
                } else {
                        /* Use datagrams. */
-                       n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
-                                   ns, &v_circuit, &gotsomewhere);
+                       n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
+                                   ns, &v_circuit, &gotsomewhere, ansp);
                        if (n < 0)
                                return (-1);
                        if (n == 0)
@@ -667,14 +686,23 @@ res_nsend(res_state statp,
        return (-1);
 }
 
+int
+res_nsend(res_state statp,
+         const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+       return __libc_res_nsend(statp, buf, buflen, ans, anssiz, NULL);
+}
+
 /* Private */
 
 static int
 send_vc(res_state statp,
-       const u_char *buf, int buflen, u_char *ans, int anssiz,
-       int *terrno, int ns)
+       const u_char *buf, int buflen, u_char **ansp, int *anssizp,
+       int *terrno, int ns, u_char **anscp)
 {
        const HEADER *hp = (HEADER *) buf;
+       u_char *ans = *ansp;
+       int anssiz = *anssizp;
        HEADER *anhp = (HEADER *) ans;
 #ifdef _LIBC
        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
@@ -782,11 +810,26 @@ send_vc(res_state statp,
        }
        resplen = ns_get16(ans);
        if (resplen > anssiz) {
-               Dprint(statp->options & RES_DEBUG,
-                      (stdout, ";; response truncated\n")
-                      );
-               truncating = 1;
-               len = anssiz;
+               if (anscp) {
+                       ans = malloc (MAXPACKET);
+                       if (ans == NULL) {
+                               *terrno = ENOMEM;
+                               res_nclose(statp);
+                               return (0);
+                       }
+                       anssiz = MAXPACKET;
+                       *anssizp = MAXPACKET;
+                       *ansp = ans;
+                       *anscp = ans;
+                       anhp = (HEADER *) ans;
+                       len = resplen;
+               } else {
+                       Dprint(statp->options & RES_DEBUG,
+                               (stdout, ";; response truncated\n")
+                       );
+                       truncating = 1;
+                       len = anssiz;
+               }
        } else
                len = resplen;
        if (len < HFIXEDSZ) {
@@ -851,10 +894,12 @@ send_vc(res_state statp,
 
 static int
 send_dg(res_state statp,
-       const u_char *buf, int buflen, u_char *ans, int anssiz,
-       int *terrno, int ns, int *v_circuit, int *gotsomewhere)
+       const u_char *buf, int buflen, u_char **ansp, int *anssizp,
+       int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp)
 {
        const HEADER *hp = (HEADER *) buf;
+       u_char *ans = *ansp;
+       int anssiz = *anssizp;
        HEADER *anhp = (HEADER *) ans;
 #ifdef _LIBC
        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
@@ -992,6 +1037,21 @@ send_dg(res_state statp,
 #else
        fromlen = sizeof(struct sockaddr_in);
 #endif
+       if (anssiz < MAXPACKET
+           && anscp
+           && (ioctl (s, FIONREAD, &resplen) < 0
+               || anssiz < resplen)) {
+               ans = malloc (MAXPACKET);
+               if (ans == NULL)
+                       ans = *ansp;
+               else {
+                       anssiz = MAXPACKET;
+                       *anssizp = MAXPACKET;
+                       *ansp = ans;
+                       *anscp = ans;
+                       anhp = (HEADER *) ans;
+               }
+       }
        resplen = recvfrom(s, (char*)ans, anssiz,0,
                           (struct sockaddr *)&from, &fromlen);
        if (resplen <= 0) {