mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-08 17:42:12 +03:00
* include/resolv.h: Adjust __libc_res_nquery and __libc_res_nsend
prototypes. * include/arpa/nameser_compat.h: Define T_UNSPEC. * nis/Versions (libnss_nis): Export _nss_nis_gethostbyname4_r. (libnss_nisplus): Export _nss_nisplus_gethostbyname4_r. * nis/nss_nis/nis-hosts.c (LINE_PARSER): Change to also handle af==AF_UNSPEC. (_nss_nis_gethostbyname4_r): New function. * nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent): Change to also handle af==AF_UNSPEC. (get_tablename): New function. Use it to avoid duplication. (_nss_nisplus_gethostbyname4_r): New function. * nscd/aicache.c (addhstaiX): Use gethostbyname4_r function is available. * nss/Versions (libnss_files): Export _nss_files_gethostbyname4_r. * nss/nss.h: Define struct gaih_addrtuple. * nss/nss_files/files-hosts.c (LINE_PARSER): Change to also handle af==AF_UNSPEC. (_nss_files_gethostbyname4_r): New function. * resolv/Versions (libnss_dns): Export _nss_dns_gethostbyname4_r. * resolv/gethnmaddr.c: Adjust __libc_res_nsearch and __libc_res_nquery calls. * resolv/res_query.c (__libc_res_nquery): Take two additional parameters for second answer buffer. Handle type=T_UNSPEC to mean look up IPv4 and IPv6. Change all callers. * resolv/res_send.c (__libc_res_nsend): Take five aditional parameters for an additional query and answer buffer. Pass to send_vc and send_dg. (send_vc): Send possibly two requests and receive two answers. (send_dg): Likewise. * resolv/nss_dns/dns-host.c: Adjust calls to __libc_res_nsearch and __libc_res_nquery. (_nss_dns_gethostbyname4_r): New function. (gaih_getanswer_slice): Likewise. (gaih_getanswer): Likewise. * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Adjust __libc_res_nquery call. * resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise. (_nss_dns_getnetbyname_r): Adjust __libc_res_nsearch call. * sysdeps/posix/getaddrinfo.c: Use gethostbyname4_r function is available.
This commit is contained in:
@@ -89,6 +89,7 @@ libnss_dns {
|
||||
_nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
|
||||
_nss_dns_getnetbyname_r; _nss_dns_getcanonname_r;
|
||||
_nss_dns_gethostbyaddr2_r;
|
||||
_nss_dns_gethostbyname4_r;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -621,7 +621,7 @@ gethostbyname2(name, af)
|
||||
buf.buf = origbuf = (querybuf *) alloca (1024);
|
||||
|
||||
if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
|
||||
&buf.ptr)) < 0) {
|
||||
&buf.ptr, NULL, NULL)) < 0) {
|
||||
if (buf.buf != origbuf)
|
||||
free (buf.buf);
|
||||
Dprintf("res_nsearch failed (%d)\n", n);
|
||||
@@ -716,12 +716,12 @@ gethostbyaddr(addr, len, af)
|
||||
buf.buf = orig_buf = (querybuf *) alloca (1024);
|
||||
|
||||
n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
|
||||
&buf.ptr);
|
||||
&buf.ptr, NULL, NULL);
|
||||
if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
|
||||
strcpy(qp, "ip6.int");
|
||||
n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
|
||||
buf.buf != orig_buf ? MAXPACKET : 1024,
|
||||
&buf.ptr);
|
||||
&buf.ptr, NULL, NULL);
|
||||
}
|
||||
if (n < 0) {
|
||||
if (buf.buf != orig_buf)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2004, 2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2004, 2006, 2008 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
|
||||
|
||||
@@ -61,7 +61,7 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
|
||||
for (int i = 0; i < nqtypes; ++i)
|
||||
{
|
||||
int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
|
||||
buf, sizeof (buf), &ansp.ptr);
|
||||
buf, sizeof (buf), &ansp.ptr, NULL, NULL);
|
||||
if (r > 0)
|
||||
{
|
||||
/* We need to decode the response. Just one question record.
|
||||
|
@@ -71,6 +71,7 @@
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
@@ -127,6 +128,14 @@ static enum nss_status getanswer_r (const querybuf *answer, int anslen,
|
||||
size_t buflen, int *errnop, int *h_errnop,
|
||||
int map, int32_t *ttlp, char **canonp);
|
||||
|
||||
static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
|
||||
const querybuf *answer2, int anslen2,
|
||||
const char *qname,
|
||||
struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp);
|
||||
|
||||
extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
|
||||
struct hostent *result,
|
||||
char *buffer, size_t buflen,
|
||||
@@ -186,11 +195,11 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
|
||||
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
|
||||
|
||||
n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
|
||||
1024, &host_buffer.ptr);
|
||||
1024, &host_buffer.ptr, NULL, NULL);
|
||||
if (n < 0)
|
||||
{
|
||||
enum nss_status status = (errno == ECONNREFUSED
|
||||
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
|
||||
status = (errno == ECONNREFUSED
|
||||
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
|
||||
*h_errnop = h_errno;
|
||||
if (h_errno == TRY_AGAIN)
|
||||
*errnop = EAGAIN;
|
||||
@@ -203,7 +212,8 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
|
||||
if (af == AF_INET6 && (_res.options & RES_USE_INET6))
|
||||
n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
|
||||
host_buffer.buf != orig_host_buffer
|
||||
? MAXPACKET : 1024, &host_buffer.ptr);
|
||||
? MAXPACKET : 1024, &host_buffer.ptr,
|
||||
NULL, NULL);
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
@@ -255,6 +265,70 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
|
||||
}
|
||||
|
||||
|
||||
enum nss_status
|
||||
_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen, int *errnop,
|
||||
int *herrnop, int32_t *ttlp)
|
||||
{
|
||||
if (__res_maybe_init (&_res, 0) == -1)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
char tmp[NS_MAXDNAME];
|
||||
|
||||
/*
|
||||
* 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, '.') == NULL)
|
||||
{
|
||||
const char *cp = res_hostalias (&_res, name, tmp, sizeof (tmp));
|
||||
if (cp != NULL)
|
||||
name = cp;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
querybuf *buf;
|
||||
u_char *ptr;
|
||||
} host_buffer;
|
||||
querybuf *orig_host_buffer;
|
||||
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
|
||||
u_char *ans2p = NULL;
|
||||
int nans2p = 0;
|
||||
|
||||
int olderr = errno;
|
||||
enum nss_status status;
|
||||
int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
|
||||
host_buffer.buf->buf, 2048, &host_buffer.ptr,
|
||||
&ans2p, &nans2p);
|
||||
if (n < 0)
|
||||
{
|
||||
status = (errno == ECONNREFUSED
|
||||
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
|
||||
*herrnop = h_errno;
|
||||
if (h_errno == TRY_AGAIN)
|
||||
*errnop = EAGAIN;
|
||||
else
|
||||
__set_errno (olderr);
|
||||
|
||||
if (host_buffer.buf != orig_host_buffer)
|
||||
free (host_buffer.buf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
|
||||
nans2p, name, pat, buffer, buflen,
|
||||
errnop, herrnop, ttlp);
|
||||
|
||||
if (host_buffer.buf != orig_host_buffer)
|
||||
free (host_buffer.buf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
|
||||
socklen_t len, int af,
|
||||
struct hostent *result,
|
||||
@@ -342,7 +416,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
|
||||
qp += sprintf (qp, "%02hhx", uaddr[n]);
|
||||
strcpy (qp, "].ip6.arpa");
|
||||
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
|
||||
host_buffer.buf->buf, 1024, &host_buffer.ptr);
|
||||
host_buffer.buf->buf, 1024, &host_buffer.ptr,
|
||||
NULL, NULL);
|
||||
if (n >= 0)
|
||||
goto got_it_already;
|
||||
}
|
||||
@@ -363,13 +438,14 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
|
||||
}
|
||||
|
||||
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
|
||||
1024, &host_buffer.ptr);
|
||||
1024, &host_buffer.ptr, NULL, NULL);
|
||||
if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
|
||||
{
|
||||
strcpy (qp, "ip6.int");
|
||||
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
|
||||
host_buffer.buf != orig_host_buffer
|
||||
? MAXPACKET : 1024, &host_buffer.ptr);
|
||||
? MAXPACKET : 1024, &host_buffer.ptr,
|
||||
NULL, NULL);
|
||||
}
|
||||
if (n < 0)
|
||||
{
|
||||
@@ -555,7 +631,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
if (n > 0 && bp[0] == '.')
|
||||
bp[0] = '\0';
|
||||
|
||||
if (n < 0 || (*name_ok) (bp) == 0)
|
||||
if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
|
||||
0))
|
||||
{
|
||||
*errnop = errno;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
@@ -629,7 +706,7 @@ getanswer_r (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 ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
|
||||
{
|
||||
if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
|
||||
continue;
|
||||
@@ -857,3 +934,245 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
|
||||
? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
|
||||
struct gaih_addrtuple ***patp,
|
||||
char **bufferp, size_t *buflenp,
|
||||
int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
|
||||
{
|
||||
char *buffer = *bufferp;
|
||||
size_t buflen = *buflenp;
|
||||
|
||||
struct gaih_addrtuple **pat = *patp;
|
||||
const HEADER *hp = &answer->hdr;
|
||||
int ancount = ntohs (hp->ancount);
|
||||
int qdcount = ntohs (hp->qdcount);
|
||||
const u_char *cp = answer->buf + HFIXEDSZ;
|
||||
const u_char *end_of_message = answer->buf + anslen;
|
||||
if (__builtin_expect (qdcount != 1, 0))
|
||||
{
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
u_char packtmp[NS_MAXCDNAME];
|
||||
int n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||||
packtmp, sizeof packtmp);
|
||||
/* We unpack the name to check it for validity. But we do not need
|
||||
it later. */
|
||||
if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
|
||||
{
|
||||
if (__builtin_expect (errno, 0) == EMSGSIZE)
|
||||
{
|
||||
too_small:
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
|
||||
&& (errno = EBADMSG)), 0))
|
||||
{
|
||||
*errnop = errno;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
cp += n + QFIXEDSZ;
|
||||
|
||||
int haveanswer = 0;
|
||||
int had_error = 0;
|
||||
char *canon = NULL;
|
||||
char *h_name = NULL;
|
||||
int h_namelen = 0;
|
||||
|
||||
while (ancount-- > 0 && cp < end_of_message && had_error == 0)
|
||||
{
|
||||
n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
||||
packtmp, sizeof packtmp);
|
||||
if (n != -1 &&
|
||||
(h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
|
||||
{
|
||||
if (__builtin_expect (errno, 0) == EMSGSIZE)
|
||||
goto too_small;
|
||||
|
||||
n = -1;
|
||||
}
|
||||
if (n < 0 || res_hnok (buffer) == 0)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
}
|
||||
if (*firstp)
|
||||
{
|
||||
h_name = buffer;
|
||||
buffer += h_namelen;
|
||||
buflen -= h_namelen;
|
||||
}
|
||||
|
||||
cp += n; /* name */
|
||||
int type = ns_get16 (cp);
|
||||
cp += INT16SZ; /* type */
|
||||
int class = ns_get16 (cp);
|
||||
cp += INT16SZ; /* class */
|
||||
int32_t ttl = ns_get32 (cp);
|
||||
cp += INT32SZ; /* TTL */
|
||||
n = ns_get16 (cp);
|
||||
cp += INT16SZ; /* len */
|
||||
|
||||
if (class != C_IN)
|
||||
{
|
||||
cp += n;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == T_CNAME)
|
||||
{
|
||||
char tbuf[MAXDNAME];
|
||||
n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
|
||||
if (n < 0 || res_hnok (tbuf) == 0)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
}
|
||||
cp += n;
|
||||
|
||||
if (*firstp)
|
||||
{
|
||||
/* Reclaim buffer space. */
|
||||
if (h_name + h_namelen == buffer)
|
||||
{
|
||||
buffer = h_name;
|
||||
buflen += h_namelen;
|
||||
}
|
||||
|
||||
n = strlen (tbuf) + 1;
|
||||
if (__builtin_expect (n > buflen, 0))
|
||||
goto too_small;
|
||||
if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
}
|
||||
|
||||
canon = buffer;
|
||||
buffer = __mempcpy (buffer, tbuf, n);
|
||||
buflen -= n;
|
||||
h_namelen = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (__builtin_expect (type == T_SIG, 0)
|
||||
|| __builtin_expect (type == T_KEY, 0)
|
||||
|| __builtin_expect (type == T_NXT, 0)
|
||||
|| __builtin_expect (type == T_PTR, 0))
|
||||
{
|
||||
/* We don't support DNSSEC yet. For now, ignore the record
|
||||
and send a low priority message to syslog.
|
||||
|
||||
We also don't expect T_PTR messages. */
|
||||
syslog (LOG_DEBUG | LOG_AUTH,
|
||||
"getaddrinfo*.gaih_getanswer: got type \"%s\"",
|
||||
p_type (type));
|
||||
cp += n;
|
||||
continue;
|
||||
}
|
||||
if (type != T_A && type != T_AAAA)
|
||||
abort ();
|
||||
|
||||
if (*pat == NULL)
|
||||
{
|
||||
uintptr_t pad = (-(uintptr_t) buffer
|
||||
% __alignof__ (struct gaih_addrtuple));
|
||||
buffer += pad;
|
||||
buflen = buflen > pad ? buflen - pad : 0;
|
||||
|
||||
if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
|
||||
0))
|
||||
{
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
*pat = (struct gaih_addrtuple *) buffer;
|
||||
buffer += sizeof (struct gaih_addrtuple);
|
||||
buflen -= sizeof (struct gaih_addrtuple);
|
||||
}
|
||||
|
||||
(*pat)->name = NULL;
|
||||
(*pat)->next = NULL;
|
||||
|
||||
if (*firstp)
|
||||
{
|
||||
if (ttl != 0 && ttlp != NULL)
|
||||
*ttlp = ttl;
|
||||
|
||||
if (canon != NULL)
|
||||
{
|
||||
(*pat)->name = canon;
|
||||
|
||||
/* Reclaim buffer space. */
|
||||
if (h_name + h_namelen == buffer)
|
||||
{
|
||||
buffer = h_name;
|
||||
buflen += h_namelen;
|
||||
}
|
||||
}
|
||||
else
|
||||
(*pat)->name = h_name;
|
||||
|
||||
*firstp = 0;
|
||||
}
|
||||
|
||||
(*pat)->family = type == T_A ? AF_INET : AF_INET6;
|
||||
memcpy ((*pat)->addr, cp, n);
|
||||
cp += n;
|
||||
(*pat)->scopeid = 0;
|
||||
|
||||
pat = &((*pat)->next);
|
||||
|
||||
haveanswer = 1;
|
||||
}
|
||||
|
||||
if (haveanswer)
|
||||
{
|
||||
*patp = pat;
|
||||
*bufferp = buffer;
|
||||
*buflenp = buflen;
|
||||
|
||||
*h_errnop = NETDB_SUCCESS;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Special case here: if the resolver sent a result but it only
|
||||
contains a CNAME while we are looking for a T_A or T_AAAA record,
|
||||
we fail with NOTFOUND instead of TRYAGAIN. */
|
||||
return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
static enum nss_status
|
||||
gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||||
int anslen2, const char *qname,
|
||||
struct gaih_addrtuple **pat, char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop, int32_t *ttlp)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
enum nss_status status = gaih_getanswer_slice(answer1, anslen1, qname,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp,
|
||||
&first);
|
||||
if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
|
||||
&& answer2 != NULL)
|
||||
status = gaih_getanswer_slice(answer2, anslen2, qname,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp, &first);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007
|
||||
/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
||||
@@ -130,7 +130,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
|
||||
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
|
||||
|
||||
anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
|
||||
1024, &net_buffer.ptr);
|
||||
1024, &net_buffer.ptr, NULL, NULL);
|
||||
if (anslen < 0)
|
||||
{
|
||||
/* Nothing found. */
|
||||
@@ -206,7 +206,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
|
||||
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
|
||||
|
||||
anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
|
||||
1024, &net_buffer.ptr);
|
||||
1024, &net_buffer.ptr, NULL, NULL);
|
||||
if (anslen < 0)
|
||||
{
|
||||
/* Nothing found. */
|
||||
|
@@ -97,7 +97,7 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
|
||||
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 **answerp, u_char **answerp2, int *nanswerp2);
|
||||
|
||||
/*
|
||||
* Formulate a normal query, send, and await answer.
|
||||
@@ -115,15 +115,20 @@ __libc_res_nquery(res_state statp,
|
||||
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 **answerp, /* if buffer needs to be enlarged */
|
||||
u_char **answerp2,
|
||||
int *nanswerp2)
|
||||
{
|
||||
u_char *buf;
|
||||
HEADER *hp = (HEADER *) answer;
|
||||
int n, use_malloc = 0;
|
||||
u_int oflags = statp->_flags;
|
||||
|
||||
size_t bufsize = QUERYSIZE;
|
||||
buf = alloca (bufsize);
|
||||
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 */
|
||||
@@ -133,18 +138,47 @@ __libc_res_nquery(res_state statp,
|
||||
printf(";; res_query(%s, %d, %d)\n", name, class, type);
|
||||
#endif
|
||||
|
||||
n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
|
||||
buf, bufsize);
|
||||
if (n > 0
|
||||
&& (oflags & RES_F_EDNS0ERR) == 0
|
||||
&& (statp->options & RES_USE_EDNS0) != 0)
|
||||
n = __res_nopt(statp, n, buf, bufsize, anslen);
|
||||
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) != 0)
|
||||
n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
|
||||
|
||||
nquery1 = n;
|
||||
query2 = buf + nquery1;
|
||||
n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
|
||||
NULL, query2, bufsize - n);
|
||||
if (n > 0
|
||||
&& (oflags & RES_F_EDNS0ERR) == 0
|
||||
&& (statp->options & RES_USE_EDNS0) != 0)
|
||||
n = __res_nopt(statp, n, query2, bufsize - n, anslen / 2);
|
||||
nquery2 = n;
|
||||
}
|
||||
}
|
||||
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) != 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 = MAXPACKET;
|
||||
bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
|
||||
buf = malloc (bufsize);
|
||||
if (buf != NULL) {
|
||||
query1 = buf;
|
||||
use_malloc = 1;
|
||||
goto again;
|
||||
}
|
||||
@@ -168,7 +202,8 @@ __libc_res_nquery(res_state statp,
|
||||
return (n);
|
||||
}
|
||||
assert (answerp == NULL || (void *) *answerp == (void *) answer);
|
||||
n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
|
||||
n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
|
||||
anslen, answerp, answerp2, nanswerp2);
|
||||
if (use_malloc)
|
||||
free (buf);
|
||||
if (n < 0) {
|
||||
@@ -184,20 +219,37 @@ __libc_res_nquery(res_state statp,
|
||||
/* __libc_res_nsend might have reallocated the buffer. */
|
||||
hp = (HEADER *) *answerp;
|
||||
|
||||
if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
|
||||
/* We simplify the following tests by assigning HP to HP2. It
|
||||
is easy to verify that this is the same as ignoring all
|
||||
tests of HP2. */
|
||||
HEADER *hp2 = answerp2 ? (HEADER *) *answerp2 : hp;
|
||||
|
||||
if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
|
||||
&& (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
|
||||
#ifdef DEBUG
|
||||
if (statp->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:
|
||||
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:
|
||||
RES_SET_H_ERRNO(statp, TRY_AGAIN);
|
||||
break;
|
||||
case NOERROR:
|
||||
if (ntohs (hp->ancount) != 0
|
||||
|| ntohs (hp2->ancount) != 0)
|
||||
goto success;
|
||||
RES_SET_H_ERRNO(statp, NO_DATA);
|
||||
break;
|
||||
case FORMERR:
|
||||
@@ -209,6 +261,7 @@ __libc_res_nquery(res_state statp,
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
success:
|
||||
return (n);
|
||||
}
|
||||
libresolv_hidden_def (__libc_res_nquery)
|
||||
@@ -221,7 +274,7 @@ res_nquery(res_state statp,
|
||||
int anslen) /* size of answer buffer */
|
||||
{
|
||||
return __libc_res_nquery(statp, name, class, type, answer, anslen,
|
||||
NULL);
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
libresolv_hidden_def (res_nquery)
|
||||
|
||||
@@ -233,11 +286,13 @@ libresolv_hidden_def (res_nquery)
|
||||
*/
|
||||
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)
|
||||
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)
|
||||
{
|
||||
const char *cp, * const *domain;
|
||||
HEADER *hp = (HEADER *) answer;
|
||||
@@ -260,7 +315,8 @@ __libc_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 (__libc_res_nquery(statp, cp, class, type, answer,
|
||||
anslen, answerp));
|
||||
anslen, answerp, answerp2,
|
||||
nanswerp2));
|
||||
|
||||
#ifdef DEBUG
|
||||
if (statp->options & RES_DEBUG)
|
||||
@@ -276,7 +332,8 @@ __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);
|
||||
answer, anslen, answerp,
|
||||
answerp2, nanswerp2);
|
||||
if (ret > 0 || trailing_dot)
|
||||
return (ret);
|
||||
saved_herrno = h_errno;
|
||||
@@ -285,6 +342,12 @@ __libc_res_nsearch(res_state statp,
|
||||
answer = *answerp;
|
||||
anslen = MAXPACKET;
|
||||
}
|
||||
if (answerp2
|
||||
&& (*answerp2 < answer || *answerp2 >= answer + anslen))
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,7 +370,8 @@ __libc_res_nsearch(res_state statp,
|
||||
|
||||
ret = __libc_res_nquerydomain(statp, name, *domain,
|
||||
class, type,
|
||||
answer, anslen, answerp);
|
||||
answer, anslen, answerp,
|
||||
answerp2, nanswerp2);
|
||||
if (ret > 0)
|
||||
return (ret);
|
||||
|
||||
@@ -315,6 +379,13 @@ __libc_res_nsearch(res_state statp,
|
||||
answer = *answerp;
|
||||
anslen = MAXPACKET;
|
||||
}
|
||||
if (answerp2
|
||||
&& (*answerp2 < answer
|
||||
|| *answerp2 >= answer + anslen))
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no server present, give up.
|
||||
@@ -368,7 +439,8 @@ __libc_res_nsearch(res_state statp,
|
||||
*/
|
||||
if (dots && !(tried_as_is || root_on_list)) {
|
||||
ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
|
||||
answer, anslen, answerp);
|
||||
answer, anslen, answerp,
|
||||
answerp2, nanswerp2);
|
||||
if (ret > 0)
|
||||
return (ret);
|
||||
}
|
||||
@@ -380,6 +452,11 @@ __libc_res_nsearch(res_state statp,
|
||||
* else send back meaningless H_ERRNO, that being the one from
|
||||
* the last DNSRCH we did.
|
||||
*/
|
||||
if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
}
|
||||
if (saved_herrno != -1)
|
||||
RES_SET_H_ERRNO(statp, saved_herrno);
|
||||
else if (got_nodata)
|
||||
@@ -398,7 +475,7 @@ res_nsearch(res_state statp,
|
||||
int anslen) /* size of answer */
|
||||
{
|
||||
return __libc_res_nsearch(statp, name, class, type, answer,
|
||||
anslen, NULL);
|
||||
anslen, NULL, NULL, NULL);
|
||||
}
|
||||
libresolv_hidden_def (res_nsearch)
|
||||
|
||||
@@ -408,12 +485,14 @@ libresolv_hidden_def (res_nsearch)
|
||||
*/
|
||||
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)
|
||||
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)
|
||||
{
|
||||
char nbuf[MAXDNAME];
|
||||
const char *longname = nbuf;
|
||||
@@ -450,7 +529,7 @@ __libc_res_nquerydomain(res_state statp,
|
||||
sprintf(nbuf, "%s.%s", name, domain);
|
||||
}
|
||||
return (__libc_res_nquery(statp, longname, class, type, answer,
|
||||
anslen, answerp));
|
||||
anslen, answerp, answerp2, nanswerp2));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -462,7 +541,7 @@ res_nquerydomain(res_state statp,
|
||||
int anslen) /* size of answer */
|
||||
{
|
||||
return __libc_res_nquerydomain(statp, name, domain, class, type,
|
||||
answer, anslen, NULL);
|
||||
answer, anslen, NULL, NULL, NULL);
|
||||
}
|
||||
libresolv_hidden_def (res_nquerydomain)
|
||||
|
||||
|
@@ -176,10 +176,14 @@ evNowTime(struct timespec *res) {
|
||||
/* Forward. */
|
||||
|
||||
static int send_vc(res_state, const u_char *, int,
|
||||
u_char **, int *, int *, int, u_char **);
|
||||
const u_char *, int,
|
||||
u_char **, int *, int *, int, u_char **,
|
||||
u_char **, int *, int *);
|
||||
static int send_dg(res_state, const u_char *, int,
|
||||
const u_char *, int,
|
||||
u_char **, int *, int *, int,
|
||||
int *, int *, u_char **);
|
||||
int *, int *, u_char **,
|
||||
u_char **, int *, int *);
|
||||
#ifdef DEBUG
|
||||
static void Aerror(const res_state, FILE *, const char *, int,
|
||||
const struct sockaddr *);
|
||||
@@ -334,33 +338,41 @@ libresolv_hidden_def (res_queriesmatch)
|
||||
|
||||
int
|
||||
__libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
u_char *ans, int anssiz, u_char **ansp)
|
||||
const u_char *buf2, int buflen2,
|
||||
u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
|
||||
int *nansp2)
|
||||
{
|
||||
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
|
||||
int gotsomewhere, terrno, try, v_circuit, resplen, resplen2, ns, n;
|
||||
|
||||
if (statp->nscount == 0) {
|
||||
__set_errno (ESRCH);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (anssiz < HFIXEDSZ) {
|
||||
if (anssiz < (buf2 == NULL ? 1 : 2) * 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;
|
||||
#ifdef USE_HOOKS
|
||||
if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
|
||||
if (anssiz < MAXPACKET && ansp) {
|
||||
u_char *buf = malloc (MAXPACKET);
|
||||
if (buf == NULL)
|
||||
return (-1);
|
||||
memcpy (buf, ans, HFIXEDSZ);
|
||||
*ansp = buf;
|
||||
ans = buf;
|
||||
anssiz = MAXPACKET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
|
||||
(stdout, ";; res_send()\n"), buf, buflen);
|
||||
v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
|
||||
v_circuit = ((statp->options & RES_USEVC)
|
||||
|| buflen > PACKETSZ
|
||||
|| buflen2 > PACKETSZ);
|
||||
gotsomewhere = 0;
|
||||
terrno = ETIMEDOUT;
|
||||
|
||||
@@ -442,7 +454,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
* Some resolvers want to even out the load on their nameservers.
|
||||
* Note that RES_BLAST overrides RES_ROTATE.
|
||||
*/
|
||||
if ((statp->options & RES_ROTATE) != 0 &&
|
||||
if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
|
||||
(statp->options & RES_BLAST) == 0) {
|
||||
struct sockaddr_in6 *ina;
|
||||
unsigned int map;
|
||||
@@ -479,8 +491,9 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
|
||||
if (nsap == NULL)
|
||||
goto next_ns;
|
||||
same_ns:
|
||||
if (statp->qhook) {
|
||||
same_ns:
|
||||
#ifdef USE_HOOKS
|
||||
if (__builtin_expect (statp->qhook != NULL, 0)) {
|
||||
int done = 0, loops = 0;
|
||||
|
||||
do {
|
||||
@@ -512,6 +525,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
char tmpbuf[40];
|
||||
@@ -521,29 +535,34 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
|
||||
tmpbuf, sizeof (tmpbuf))));
|
||||
|
||||
if (v_circuit) {
|
||||
if (__builtin_expect (v_circuit, 0)) {
|
||||
/* Use VC; at most one attempt per server. */
|
||||
try = statp->retry;
|
||||
n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno,
|
||||
ns, ansp);
|
||||
n = send_vc(statp, buf, buflen, buf2, buflen2,
|
||||
&ans, &anssiz, &terrno,
|
||||
ns, ansp, ansp2, nansp2, &resplen2);
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
goto next_ns;
|
||||
resplen = n;
|
||||
} else {
|
||||
/* Use datagrams. */
|
||||
n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
|
||||
ns, &v_circuit, &gotsomewhere, ansp);
|
||||
n = send_dg(statp, buf, buflen, buf2, buflen2,
|
||||
&ans, &anssiz, &terrno,
|
||||
ns, &v_circuit, &gotsomewhere, ansp,
|
||||
ansp2, nansp2, &resplen2);
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
goto next_ns;
|
||||
if (v_circuit)
|
||||
// XXX Check whether both requests failed or
|
||||
// XXX whether one have been answered successfully
|
||||
goto same_ns;
|
||||
resplen = n;
|
||||
}
|
||||
|
||||
resplen = n;
|
||||
|
||||
Dprint((statp->options & RES_DEBUG) ||
|
||||
((statp->pfcode & RES_PRF_REPLY) &&
|
||||
(statp->pfcode & RES_PRF_HEAD1)),
|
||||
@@ -553,6 +572,11 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, "%s", ""),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
if (buf2 != NULL)
|
||||
DprintQ((statp->options & RES_DEBUG) ||
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, "%s", ""),
|
||||
*ansp2, (resplen2 > *nansp2) ? *nansp2 : resplen2);
|
||||
|
||||
/*
|
||||
* If we have temporarily opened a virtual circuit,
|
||||
@@ -563,7 +587,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
(statp->options & RES_STAYOPEN) == 0) {
|
||||
__res_iclose(statp, false);
|
||||
}
|
||||
if (statp->rhook) {
|
||||
#ifdef USE_HOOKS
|
||||
if (__builtin_expect (statp->rhook, 0)) {
|
||||
int done = 0, loops = 0;
|
||||
|
||||
do {
|
||||
@@ -593,6 +618,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
} while (!done);
|
||||
|
||||
}
|
||||
#endif
|
||||
return (resplen);
|
||||
next_ns: ;
|
||||
} /*foreach ns*/
|
||||
@@ -612,7 +638,8 @@ 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);
|
||||
return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
libresolv_hidden_def (res_nsend)
|
||||
|
||||
@@ -620,17 +647,23 @@ libresolv_hidden_def (res_nsend)
|
||||
|
||||
static int
|
||||
send_vc(res_state statp,
|
||||
const u_char *buf, int buflen, u_char **ansp, int *anssizp,
|
||||
int *terrno, int ns, u_char **anscp)
|
||||
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
|
||||
u_char **ansp, int *anssizp,
|
||||
int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
|
||||
int *resplen2)
|
||||
{
|
||||
const HEADER *hp = (HEADER *) buf;
|
||||
const HEADER *hp2 = (HEADER *) buf2;
|
||||
u_char *ans = *ansp;
|
||||
int anssiz = *anssizp;
|
||||
int orig_anssizp = *anssizp;
|
||||
// XXX REMOVE
|
||||
// int anssiz = *anssizp;
|
||||
HEADER *anhp = (HEADER *) ans;
|
||||
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
|
||||
int truncating, connreset, resplen, n;
|
||||
struct iovec iov[2];
|
||||
struct iovec iov[4];
|
||||
u_short len;
|
||||
u_short len2;
|
||||
u_char *cp;
|
||||
|
||||
connreset = 0;
|
||||
@@ -677,11 +710,19 @@ send_vc(res_state statp,
|
||||
/*
|
||||
* Send length & message
|
||||
*/
|
||||
ns_put16((u_short)buflen, (u_char*)&len);
|
||||
len = htons ((u_short) buflen);
|
||||
evConsIovec(&len, INT16SZ, &iov[0]);
|
||||
evConsIovec((void*)buf, buflen, &iov[1]);
|
||||
if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2))
|
||||
!= (INT16SZ + buflen)) {
|
||||
int niov = 2;
|
||||
ssize_t explen = INT16SZ + buflen;
|
||||
if (buf2 != NULL) {
|
||||
len2 = htons ((u_short) buflen2);
|
||||
evConsIovec(&len2, INT16SZ, &iov[2]);
|
||||
evConsIovec((void*)buf2, buflen2, &iov[3]);
|
||||
niov = 4;
|
||||
explen += INT16SZ + buflen2;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
|
||||
*terrno = errno;
|
||||
Perror(statp, stderr, "write failed", errno);
|
||||
__res_iclose(statp, false);
|
||||
@@ -690,6 +731,8 @@ send_vc(res_state statp,
|
||||
/*
|
||||
* Receive length & response
|
||||
*/
|
||||
int recvresp1 = 0;
|
||||
int recvresp2 = buf2 == NULL;
|
||||
read_len:
|
||||
cp = ans;
|
||||
len = INT16SZ;
|
||||
@@ -718,30 +761,66 @@ send_vc(res_state statp,
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#ifdef _STRING_ARCH_unaligned
|
||||
resplen = ntohs (*(uint16_t *) ans);
|
||||
#else
|
||||
resplen = ns_get16(ans);
|
||||
if (resplen > anssiz) {
|
||||
#endif
|
||||
|
||||
int *thisanssizp;
|
||||
u_char **thisansp;
|
||||
int *thisresplenp;
|
||||
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
|
||||
thisanssizp = anssizp;
|
||||
thisansp = anscp ?: ansp;
|
||||
assert (anscp != NULL || ansp2 == NULL);
|
||||
thisresplenp = &resplen;
|
||||
} else {
|
||||
if (*anssizp != MAXPACKET) {
|
||||
/* No buffer allocated for the first
|
||||
reply. We can try to use the rest
|
||||
of the user-provided buffer. */
|
||||
*anssizp2 = orig_anssizp - resplen;
|
||||
*ansp2 = *ansp + resplen;
|
||||
} else {
|
||||
/* The first reply did not fit into the
|
||||
user-provided buffer. Maybe the second
|
||||
answer will. */
|
||||
*anssizp2 = orig_anssizp;
|
||||
*ansp2 = *ansp;
|
||||
}
|
||||
|
||||
thisanssizp = anssizp2;
|
||||
thisansp = ansp2;
|
||||
thisresplenp = resplen2;
|
||||
}
|
||||
anhp = (HEADER *) *thisansp;
|
||||
|
||||
*thisresplenp = resplen;
|
||||
if (resplen > *thisanssizp) {
|
||||
/* Yes, we test ANSCP here. If we have two buffers
|
||||
both will be allocatable. */
|
||||
if (anscp) {
|
||||
ans = malloc (MAXPACKET);
|
||||
if (ans == NULL) {
|
||||
u_char *newp = malloc (MAXPACKET);
|
||||
if (newp == NULL) {
|
||||
*terrno = ENOMEM;
|
||||
__res_iclose(statp, false);
|
||||
return (0);
|
||||
}
|
||||
anssiz = MAXPACKET;
|
||||
*anssizp = MAXPACKET;
|
||||
*ansp = ans;
|
||||
*anscp = ans;
|
||||
anhp = (HEADER *) ans;
|
||||
*thisanssizp = MAXPACKET;
|
||||
*thisansp = newp;
|
||||
anhp = (HEADER *) newp;
|
||||
len = resplen;
|
||||
} else {
|
||||
Dprint(statp->options & RES_DEBUG,
|
||||
(stdout, ";; response truncated\n")
|
||||
);
|
||||
truncating = 1;
|
||||
len = anssiz;
|
||||
len = *thisanssizp;
|
||||
}
|
||||
} else
|
||||
len = resplen;
|
||||
|
||||
if (len < HFIXEDSZ) {
|
||||
/*
|
||||
* Undersized message.
|
||||
@@ -752,7 +831,8 @@ send_vc(res_state statp,
|
||||
__res_iclose(statp, false);
|
||||
return (0);
|
||||
}
|
||||
cp = ans;
|
||||
|
||||
cp = *thisansp;
|
||||
while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
|
||||
cp += n;
|
||||
len -= n;
|
||||
@@ -768,7 +848,7 @@ send_vc(res_state statp,
|
||||
* Flush rest of answer so connection stays in synch.
|
||||
*/
|
||||
anhp->tc = 1;
|
||||
len = resplen - anssiz;
|
||||
len = resplen - *thisanssizp;
|
||||
while (len != 0) {
|
||||
char junk[PACKETSZ];
|
||||
|
||||
@@ -787,14 +867,25 @@ send_vc(res_state statp,
|
||||
* itself confused, then drop the packet and
|
||||
* wait for the correct one.
|
||||
*/
|
||||
if (hp->id != anhp->id) {
|
||||
if ((recvresp1 || hp->id != anhp->id)
|
||||
&& (recvresp2 || hp2->id != anhp->id)) {
|
||||
DprintQ((statp->options & RES_DEBUG) ||
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; old answer (unexpected):\n"),
|
||||
ans, (resplen > anssiz) ? anssiz: resplen);
|
||||
*thisansp,
|
||||
(resplen > *thisanssiz) ? *thisanssiz: resplen);
|
||||
goto read_len;
|
||||
}
|
||||
|
||||
/* Mark which reply we received. */
|
||||
if (recvresp1 == 0 && hp->id == anhp->id)
|
||||
recvresp1 = 1;
|
||||
else
|
||||
recvresp2 = 1;
|
||||
/* Repeat waiting if we have a second answer to arrive. */
|
||||
if ((recvresp1 & recvresp2) == 0)
|
||||
goto read_len;
|
||||
|
||||
/*
|
||||
* All is well, or the error is fatal. Signal that the
|
||||
* next nameserver ought not be tried.
|
||||
@@ -804,19 +895,20 @@ send_vc(res_state statp,
|
||||
|
||||
static int
|
||||
send_dg(res_state statp,
|
||||
const u_char *buf, int buflen, u_char **ansp, int *anssizp,
|
||||
int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp)
|
||||
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
|
||||
u_char **ansp, int *anssizp,
|
||||
int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
|
||||
u_char **ansp2, int *anssizp2, int *resplen2)
|
||||
{
|
||||
const HEADER *hp = (HEADER *) buf;
|
||||
const HEADER *hp2 = (HEADER *) buf2;
|
||||
u_char *ans = *ansp;
|
||||
int anssiz = *anssizp;
|
||||
HEADER *anhp = (HEADER *) ans;
|
||||
int orig_anssizp = *anssizp;
|
||||
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
|
||||
struct timespec now, timeout, finish;
|
||||
struct pollfd pfd[1];
|
||||
int ptimeout;
|
||||
struct sockaddr_in6 from;
|
||||
socklen_t fromlen;
|
||||
int resplen, seconds, n;
|
||||
|
||||
if (EXT(statp).nssocks[ns] == -1) {
|
||||
@@ -879,6 +971,8 @@ send_dg(res_state statp,
|
||||
evAddTime(&finish, &now, &timeout);
|
||||
int need_recompute = 0;
|
||||
int nwritten = 0;
|
||||
int recvresp1 = 0;
|
||||
int recvresp2 = buf2 == NULL;
|
||||
pfd[0].fd = EXT(statp).nssocks[ns];
|
||||
pfd[0].events = POLLOUT;
|
||||
wait:
|
||||
@@ -918,35 +1012,73 @@ send_dg(res_state statp,
|
||||
}
|
||||
__set_errno (0);
|
||||
if (pfd[0].revents & POLLOUT) {
|
||||
if (send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL) != buflen) {
|
||||
ssize_t sr;
|
||||
if (nwritten != 0)
|
||||
sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
|
||||
else
|
||||
sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
|
||||
|
||||
if (sr != buflen) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
goto recompute_resend;
|
||||
Perror(statp, stderr, "send", errno);
|
||||
goto err_out;
|
||||
}
|
||||
pfd[0].events = POLLIN;
|
||||
if (nwritten != 0 || buf2 == NULL)
|
||||
pfd[0].events = POLLIN;
|
||||
else
|
||||
pfd[0].events = POLLIN | POLLOUT;
|
||||
++nwritten;
|
||||
goto wait;
|
||||
} else if (pfd[0].revents & POLLIN) {
|
||||
fromlen = sizeof(struct sockaddr_in6);
|
||||
if (anssiz < MAXPACKET
|
||||
int *thisanssizp;
|
||||
u_char **thisansp;
|
||||
int *thisresplenp;
|
||||
|
||||
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
|
||||
thisanssizp = anssizp;
|
||||
thisansp = anscp ?: ansp;
|
||||
assert (anscp != NULL || ansp2 == NULL);
|
||||
thisresplenp = &resplen;
|
||||
} else {
|
||||
if (*anssizp != MAXPACKET) {
|
||||
/* No buffer allocated for the first
|
||||
reply. We can try to use the rest
|
||||
of the user-provided buffer. */
|
||||
*anssizp2 = orig_anssizp - resplen;
|
||||
*ansp2 = *ansp + resplen;
|
||||
} else {
|
||||
/* The first reply did not fit into the
|
||||
user-provided buffer. Maybe the second
|
||||
answer will. */
|
||||
*anssizp2 = orig_anssizp;
|
||||
*ansp2 = *ansp;
|
||||
}
|
||||
|
||||
thisanssizp = anssizp2;
|
||||
thisansp = ansp2;
|
||||
thisresplenp = resplen2;
|
||||
}
|
||||
|
||||
if (*thisanssizp < MAXPACKET
|
||||
/* Yes, we test ANSCP here. If we have two buffers
|
||||
both will be allocatable. */
|
||||
&& anscp
|
||||
&& (ioctl (pfd[0].fd, FIONREAD, &resplen) < 0
|
||||
|| anssiz < resplen)) {
|
||||
ans = malloc (MAXPACKET);
|
||||
if (ans == NULL)
|
||||
ans = *ansp;
|
||||
else {
|
||||
anssiz = MAXPACKET;
|
||||
&& (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
|
||||
|| *thisanssizp < *thisresplenp)) {
|
||||
u_char *newp = malloc (MAXPACKET);
|
||||
if (newp != NULL) {
|
||||
*anssizp = MAXPACKET;
|
||||
*ansp = ans;
|
||||
*anscp = ans;
|
||||
anhp = (HEADER *) ans;
|
||||
*thisansp = ans = newp;
|
||||
}
|
||||
}
|
||||
resplen = recvfrom(pfd[0].fd, (char*)ans, anssiz,0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (resplen <= 0) {
|
||||
HEADER *anhp = (HEADER *) *thisansp;
|
||||
socklen_t fromlen = sizeof(struct sockaddr_in6);
|
||||
assert (sizeof(from) <= fromlen);
|
||||
*thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
|
||||
*thisanssizp, 0,
|
||||
(struct sockaddr *)&from, &fromlen);
|
||||
if (*thisresplenp <= 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
need_recompute = 1;
|
||||
goto wait;
|
||||
@@ -955,17 +1087,18 @@ send_dg(res_state statp,
|
||||
goto err_out;
|
||||
}
|
||||
*gotsomewhere = 1;
|
||||
if (resplen < HFIXEDSZ) {
|
||||
if (*thisresplenp < HFIXEDSZ) {
|
||||
/*
|
||||
* Undersized message.
|
||||
*/
|
||||
Dprint(statp->options & RES_DEBUG,
|
||||
(stdout, ";; undersized: %d\n",
|
||||
resplen));
|
||||
*thisresplen));
|
||||
*terrno = EMSGSIZE;
|
||||
goto err_out;
|
||||
}
|
||||
if (hp->id != anhp->id) {
|
||||
if ((recvresp1 || hp->id != anhp->id)
|
||||
&& (recvresp2 || hp2->id != anhp->id)) {
|
||||
/*
|
||||
* response from old query, ignore it.
|
||||
* XXX - potential security hazard could
|
||||
@@ -974,7 +1107,9 @@ send_dg(res_state statp,
|
||||
DprintQ((statp->options & RES_DEBUG) ||
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; old answer:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisansp,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
goto wait;
|
||||
}
|
||||
if (!(statp->options & RES_INSECURE1) &&
|
||||
@@ -987,14 +1122,16 @@ send_dg(res_state statp,
|
||||
DprintQ((statp->options & RES_DEBUG) ||
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; not our server:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisansp,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
goto wait;
|
||||
}
|
||||
#ifdef RES_USE_EDNS0
|
||||
if (anhp->rcode == FORMERR
|
||||
&& (statp->options & RES_USE_EDNS0) != 0U) {
|
||||
/*
|
||||
* Do not retry if the server do not understand
|
||||
* Do not retry if the server does not understand
|
||||
* EDNS0. The case has to be captured here, as
|
||||
* FORMERR packet do not carry query section, hence
|
||||
* res_queriesmatch() returns 0.
|
||||
@@ -1002,15 +1139,23 @@ send_dg(res_state statp,
|
||||
DprintQ(statp->options & RES_DEBUG,
|
||||
(stdout,
|
||||
"server rejected query with EDNS0:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisans,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
/* record the error */
|
||||
statp->_flags |= RES_F_EDNS0ERR;
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
if (!(statp->options & RES_INSECURE2) &&
|
||||
!res_queriesmatch(buf, buf + buflen,
|
||||
ans, ans + anssiz)) {
|
||||
if (!(statp->options & RES_INSECURE2)
|
||||
&& (recvresp1 || !res_queriesmatch(buf, buf + buflen,
|
||||
*thisansp,
|
||||
*thisansp
|
||||
+ *thisanssizp))
|
||||
&& (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
|
||||
*thisansp,
|
||||
*thisansp
|
||||
+ *thisanssizp))) {
|
||||
/*
|
||||
* response contains wrong query? ignore it.
|
||||
* XXX - potential security hazard could
|
||||
@@ -1019,7 +1164,9 @@ send_dg(res_state statp,
|
||||
DprintQ((statp->options & RES_DEBUG) ||
|
||||
(statp->pfcode & RES_PRF_REPLY),
|
||||
(stdout, ";; wrong query name:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisansp,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
goto wait;
|
||||
}
|
||||
if (anhp->rcode == SERVFAIL ||
|
||||
@@ -1027,7 +1174,9 @@ send_dg(res_state statp,
|
||||
anhp->rcode == REFUSED) {
|
||||
DprintQ(statp->options & RES_DEBUG,
|
||||
(stdout, "server rejected query:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisansp,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
next_ns:
|
||||
__res_iclose(statp, false);
|
||||
/* don't retry if called from dig */
|
||||
@@ -1038,7 +1187,9 @@ send_dg(res_state statp,
|
||||
&& anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
|
||||
DprintQ(statp->options & RES_DEBUG,
|
||||
(stdout, "referred query:\n"),
|
||||
ans, (resplen > anssiz) ? anssiz : resplen);
|
||||
thisansp,
|
||||
(*thisresplen > *thisanssiz)
|
||||
? *thisanssiz : *thisresplen);
|
||||
goto next_ns;
|
||||
}
|
||||
if (!(statp->options & RES_IGNTC) && anhp->tc) {
|
||||
@@ -1050,8 +1201,18 @@ send_dg(res_state statp,
|
||||
(stdout, ";; truncated answer\n"));
|
||||
*v_circuit = 1;
|
||||
__res_iclose(statp, false);
|
||||
// XXX if we have received one reply we could
|
||||
// XXX use it and not repeat it over TCP...
|
||||
return (1);
|
||||
}
|
||||
/* Mark which reply we received. */
|
||||
if (recvresp1 == 0 && hp->id == anhp->id)
|
||||
recvresp1 = 1;
|
||||
else
|
||||
recvresp2 = 1;
|
||||
/* Repeat waiting if we have a second answer to arrive. */
|
||||
if ((recvresp1 & recvresp2) == 0)
|
||||
goto wait;
|
||||
/*
|
||||
* All is well, or the error is fatal. Signal that the
|
||||
* next nameserver ought not be tried.
|
||||
|
Reference in New Issue
Block a user