mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 05:50:14 +00:00
nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces
Introduce struct alloc_buffer to this function, and use it and struct ns_rr_cursor in gaih_getanswer_slice. Adjust gaih_getanswer and gaih_getanswer_noaaaa accordingly. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
This commit is contained in:
parent
9caf782276
commit
1d495912a7
@ -100,13 +100,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#define MAXHOSTNAMELEN 256
|
#define MAXHOSTNAMELEN 256
|
||||||
|
|
||||||
/* We need this time later. */
|
|
||||||
typedef union querybuf
|
|
||||||
{
|
|
||||||
HEADER hdr;
|
|
||||||
u_char buf[MAXPACKET];
|
|
||||||
} querybuf;
|
|
||||||
|
|
||||||
/* For historic reasons, pointers to IP addresses are char *, so use a
|
/* For historic reasons, pointers to IP addresses are char *, so use a
|
||||||
single list type for addresses and host names. */
|
single list type for addresses and host names. */
|
||||||
#define DYNARRAY_STRUCT ptrlist
|
#define DYNARRAY_STRUCT ptrlist
|
||||||
@ -125,18 +118,18 @@ static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
|
|||||||
char **hnamep, int *errnop,
|
char **hnamep, int *errnop,
|
||||||
int *h_errnop, int32_t *ttlp);
|
int *h_errnop, int32_t *ttlp);
|
||||||
|
|
||||||
static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
|
static enum nss_status gaih_getanswer (unsigned char *packet1,
|
||||||
const querybuf *answer2, int anslen2,
|
size_t packet1len,
|
||||||
const char *qname,
|
unsigned char *packet2,
|
||||||
|
size_t packet2len,
|
||||||
|
struct alloc_buffer *abuf,
|
||||||
struct gaih_addrtuple **pat,
|
struct gaih_addrtuple **pat,
|
||||||
char *buffer, size_t buflen,
|
|
||||||
int *errnop, int *h_errnop,
|
int *errnop, int *h_errnop,
|
||||||
int32_t *ttlp);
|
int32_t *ttlp);
|
||||||
static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
|
static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
|
||||||
int anslen1,
|
size_t packetlen,
|
||||||
const char *qname,
|
struct alloc_buffer *abuf,
|
||||||
struct gaih_addrtuple **pat,
|
struct gaih_addrtuple **pat,
|
||||||
char *buffer, size_t buflen,
|
|
||||||
int *errnop, int *h_errnop,
|
int *errnop, int *h_errnop,
|
||||||
int32_t *ttlp);
|
int32_t *ttlp);
|
||||||
|
|
||||||
@ -408,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
|||||||
name = cp;
|
name = cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
union
|
unsigned char dns_packet_buffer[2048];
|
||||||
{
|
unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
|
||||||
querybuf *buf;
|
|
||||||
u_char *ptr;
|
|
||||||
} host_buffer;
|
|
||||||
querybuf *orig_host_buffer;
|
|
||||||
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
|
|
||||||
u_char *ans2p = NULL;
|
u_char *ans2p = NULL;
|
||||||
int nans2p = 0;
|
int nans2p = 0;
|
||||||
int resplen2 = 0;
|
int resplen2 = 0;
|
||||||
int ans2p_malloced = 0;
|
int ans2p_malloced = 0;
|
||||||
|
struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
|
||||||
|
|
||||||
|
|
||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
@ -427,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
|||||||
if ((ctx->resp->options & RES_NOAAAA) == 0)
|
if ((ctx->resp->options & RES_NOAAAA) == 0)
|
||||||
{
|
{
|
||||||
n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
|
n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
|
||||||
host_buffer.buf->buf, 2048, &host_buffer.ptr,
|
dns_packet_buffer, sizeof (dns_packet_buffer),
|
||||||
&ans2p, &nans2p, &resplen2, &ans2p_malloced);
|
&alt_dns_packet_buffer, &ans2p, &nans2p,
|
||||||
|
&resplen2, &ans2p_malloced);
|
||||||
if (n >= 0)
|
if (n >= 0)
|
||||||
status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
|
status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
|
||||||
resplen2, name, pat, buffer, buflen,
|
&abuf, pat, errnop, herrnop, ttlp);
|
||||||
errnop, herrnop, ttlp);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = __res_context_search (ctx, name, C_IN, T_A,
|
n = __res_context_search (ctx, name, C_IN, T_A,
|
||||||
host_buffer.buf->buf, 2048, NULL,
|
dns_packet_buffer, sizeof (dns_packet_buffer),
|
||||||
NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL);
|
||||||
if (n >= 0)
|
if (n >= 0)
|
||||||
status = gaih_getanswer_noaaaa (host_buffer.buf, n,
|
status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
|
||||||
name, pat, buffer, buflen,
|
&abuf, pat, errnop, herrnop, ttlp);
|
||||||
errnop, herrnop, ttlp);
|
|
||||||
}
|
}
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
@ -473,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
|||||||
__set_errno (olderr);
|
__set_errno (olderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Implement the buffer resizing protocol. */
|
||||||
|
if (alloc_buffer_has_failed (&abuf))
|
||||||
|
{
|
||||||
|
*errnop = ERANGE;
|
||||||
|
*herrnop = NETDB_INTERNAL;
|
||||||
|
status = NSS_STATUS_TRYAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check whether ans2p was separately allocated. */
|
/* Check whether ans2p was separately allocated. */
|
||||||
if (ans2p_malloced)
|
if (ans2p_malloced)
|
||||||
free (ans2p);
|
free (ans2p);
|
||||||
|
|
||||||
if (host_buffer.buf != orig_host_buffer)
|
if (alt_dns_packet_buffer != dns_packet_buffer)
|
||||||
free (host_buffer.buf);
|
free (alt_dns_packet_buffer);
|
||||||
|
|
||||||
__resolv_context_put (ctx);
|
__resolv_context_put (ctx);
|
||||||
return status;
|
return status;
|
||||||
@ -892,259 +888,152 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
|||||||
return NSS_STATUS_TRYAGAIN;
|
return NSS_STATUS_TRYAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parses DNS data found in PACKETLEN bytes at PACKET in struct
|
||||||
|
gaih_addrtuple address tuples. The new address tuples are linked
|
||||||
|
from **TAILP, with backing store allocated from ABUF, and *TAILP is
|
||||||
|
updated to point where the next tuple pointer should be stored. If
|
||||||
|
TTLP is not null, *TTLP is updated to reflect the minimum TTL. If
|
||||||
|
STORE_CANON is true, the canonical name is stored as part of the
|
||||||
|
first address tuple being written. */
|
||||||
static enum nss_status
|
static enum nss_status
|
||||||
gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
|
gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
|
||||||
struct gaih_addrtuple ***patp,
|
struct alloc_buffer *abuf,
|
||||||
char **bufferp, size_t *buflenp,
|
struct gaih_addrtuple ***tailp,
|
||||||
int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
|
int *errnop, int *h_errnop, int32_t *ttlp,
|
||||||
|
bool store_canon)
|
||||||
{
|
{
|
||||||
char *buffer = *bufferp;
|
struct ns_rr_cursor c;
|
||||||
size_t buflen = *buflenp;
|
if (!__ns_rr_cursor_init (&c, packet, packetlen))
|
||||||
|
|
||||||
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 (__glibc_unlikely (qdcount != 1))
|
|
||||||
{
|
{
|
||||||
|
/* This should not happen because __res_context_query already
|
||||||
|
perfroms response validation. */
|
||||||
*h_errnop = NO_RECOVERY;
|
*h_errnop = NO_RECOVERY;
|
||||||
return NSS_STATUS_UNAVAIL;
|
return NSS_STATUS_UNAVAIL;
|
||||||
}
|
}
|
||||||
|
bool haveanswer = false; /* Set to true if at least one address. */
|
||||||
|
uint16_t qtype = ns_rr_cursor_qtype (&c);
|
||||||
|
int ancount = ns_rr_cursor_ancount (&c);
|
||||||
|
const unsigned char *expected_name = ns_rr_cursor_qname (&c);
|
||||||
|
/* expected_name may be updated to point into this buffer. */
|
||||||
|
unsigned char name_buffer[NS_MAXCDNAME];
|
||||||
|
|
||||||
u_char packtmp[NS_MAXCDNAME];
|
/* This is a pointer to a possibly-compressed name in the packet.
|
||||||
int n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
Eventually it is equivalent to the canonical name. If needed, it
|
||||||
packtmp, sizeof packtmp);
|
is uncompressed and translated to text form when the first
|
||||||
/* We unpack the name to check it for validity. But we do not need
|
address tuple is encountered. */
|
||||||
it later. */
|
const unsigned char *compressed_alias_name = expected_name;
|
||||||
if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
|
|
||||||
{
|
|
||||||
if (__glibc_unlikely (errno == EMSGSIZE))
|
|
||||||
{
|
|
||||||
too_small:
|
|
||||||
*errnop = ERANGE;
|
|
||||||
*h_errnop = NETDB_INTERNAL;
|
|
||||||
return NSS_STATUS_TRYAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = -1;
|
if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
|
||||||
}
|
|
||||||
|
|
||||||
if (__glibc_unlikely (n < 0))
|
|
||||||
{
|
|
||||||
*errnop = errno;
|
|
||||||
*h_errnop = NO_RECOVERY;
|
|
||||||
return NSS_STATUS_UNAVAIL;
|
|
||||||
}
|
|
||||||
if (__glibc_unlikely (__libc_res_hnok (buffer) == 0))
|
|
||||||
{
|
|
||||||
errno = EBADMSG;
|
|
||||||
*errnop = EBADMSG;
|
|
||||||
*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;
|
|
||||||
|
|
||||||
if (ancount == 0)
|
|
||||||
{
|
{
|
||||||
*h_errnop = HOST_NOT_FOUND;
|
*h_errnop = HOST_NOT_FOUND;
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ancount-- > 0 && cp < end_of_message && had_error == 0)
|
for (; ancount > -0; --ancount)
|
||||||
{
|
{
|
||||||
n = __ns_name_unpack (answer->buf, end_of_message, cp,
|
struct ns_rr_wire rr;
|
||||||
packtmp, sizeof packtmp);
|
if (!__ns_rr_cursor_next (&c, &rr))
|
||||||
if (n != -1 &&
|
|
||||||
(h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
|
|
||||||
{
|
{
|
||||||
if (__glibc_unlikely (errno == EMSGSIZE))
|
*h_errnop = NO_RECOVERY;
|
||||||
goto too_small;
|
return NSS_STATUS_UNAVAIL;
|
||||||
|
|
||||||
n = -1;
|
|
||||||
}
|
|
||||||
if (__glibc_unlikely (n < 0))
|
|
||||||
{
|
|
||||||
++had_error;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*firstp && canon == NULL && __libc_res_hnok (buffer))
|
|
||||||
{
|
|
||||||
h_name = buffer;
|
|
||||||
buffer += h_namelen;
|
|
||||||
buflen -= h_namelen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cp += n; /* name */
|
/* Update TTL for known record types. */
|
||||||
|
if ((rr.rtype == T_CNAME || rr.rtype == qtype)
|
||||||
|
&& ttlp != NULL && *ttlp > rr.ttl)
|
||||||
|
*ttlp = rr.ttl;
|
||||||
|
|
||||||
if (__glibc_unlikely (cp + 10 > end_of_message))
|
if (rr.rtype == T_CNAME)
|
||||||
{
|
{
|
||||||
++had_error;
|
/* NB: No check for owner name match, based on historic
|
||||||
continue;
|
precedent. Record the CNAME target as the new expected
|
||||||
}
|
name. */
|
||||||
|
int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
|
||||||
uint16_t type;
|
name_buffer, sizeof (name_buffer));
|
||||||
NS_GET16 (type, cp);
|
if (n < 0)
|
||||||
uint16_t class;
|
|
||||||
NS_GET16 (class, cp);
|
|
||||||
int32_t ttl;
|
|
||||||
NS_GET32 (ttl, cp);
|
|
||||||
NS_GET16 (n, cp); /* RDATA length. */
|
|
||||||
|
|
||||||
if (end_of_message - cp < n)
|
|
||||||
{
|
|
||||||
/* RDATA extends beyond the end of the packet. */
|
|
||||||
++had_error;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class != C_IN)
|
|
||||||
{
|
|
||||||
cp += n;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == T_CNAME)
|
|
||||||
{
|
|
||||||
char tbuf[MAXDNAME];
|
|
||||||
|
|
||||||
/* A CNAME could also have a TTL entry. */
|
|
||||||
if (ttlp != NULL && ttl < *ttlp)
|
|
||||||
*ttlp = ttl;
|
|
||||||
|
|
||||||
n = __libc_dn_expand (answer->buf, end_of_message, cp,
|
|
||||||
tbuf, sizeof tbuf);
|
|
||||||
if (__glibc_unlikely (n < 0))
|
|
||||||
{
|
{
|
||||||
++had_error;
|
*h_errnop = NO_RECOVERY;
|
||||||
continue;
|
return NSS_STATUS_UNAVAIL;
|
||||||
}
|
}
|
||||||
cp += n;
|
expected_name = name_buffer;
|
||||||
|
if (store_canon && __res_binary_hnok (name_buffer))
|
||||||
if (*firstp && __libc_res_hnok (tbuf))
|
/* This name can be used as a canonical name. Do not
|
||||||
|
translate to text form here to conserve buffer space.
|
||||||
|
Point to the compressed name because name_buffer can be
|
||||||
|
overwritten with an unusable name later. */
|
||||||
|
compressed_alias_name = rr.rdata;
|
||||||
|
}
|
||||||
|
else if (rr.rtype == qtype
|
||||||
|
&& __ns_samebinaryname (rr.rname, expected_name)
|
||||||
|
&& rr.rdlength == rrtype_to_rdata_length (qtype))
|
||||||
|
{
|
||||||
|
struct gaih_addrtuple *ntup
|
||||||
|
= alloc_buffer_alloc (abuf, struct gaih_addrtuple);
|
||||||
|
/* Delay error reporting to the callers (they implement the
|
||||||
|
ERANGE buffer resizing handshake). */
|
||||||
|
if (ntup != NULL)
|
||||||
{
|
{
|
||||||
/* Reclaim buffer space. */
|
ntup->next = NULL;
|
||||||
if (h_name + h_namelen == buffer)
|
if (store_canon && compressed_alias_name != NULL)
|
||||||
{
|
{
|
||||||
buffer = h_name;
|
/* This assumes that all the CNAME records come
|
||||||
buflen += h_namelen;
|
first. Use MAXHOSTNAMELEN instead of
|
||||||
|
NS_MAXCDNAME for additional length checking.
|
||||||
|
However, these checks are not expected to fail
|
||||||
|
because all size NS_MAXCDNAME names should into
|
||||||
|
the hname buffer because no escaping is
|
||||||
|
needed. */
|
||||||
|
char unsigned nbuf[NS_MAXCDNAME];
|
||||||
|
char hname[MAXHOSTNAMELEN + 1];
|
||||||
|
if (__ns_name_unpack (c.begin, c.end,
|
||||||
|
compressed_alias_name,
|
||||||
|
nbuf, sizeof (nbuf)) >= 0
|
||||||
|
&& __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0)
|
||||||
|
/* Space checking is performed by the callers. */
|
||||||
|
ntup->name = alloc_buffer_copy_string (abuf, hname);
|
||||||
|
store_canon = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ntup->name = NULL;
|
||||||
|
if (rr.rdlength == 4)
|
||||||
|
ntup->family = AF_INET;
|
||||||
|
else
|
||||||
|
ntup->family = AF_INET6;
|
||||||
|
memcpy (ntup->addr, rr.rdata, rr.rdlength);
|
||||||
|
ntup->scopeid = 0;
|
||||||
|
|
||||||
n = strlen (tbuf) + 1;
|
/* Link in the new tuple, and update the tail pointer to
|
||||||
if (__glibc_unlikely (n > buflen))
|
point to its next field. */
|
||||||
goto too_small;
|
**tailp = ntup;
|
||||||
if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
*tailp = &ntup->next;
|
||||||
{
|
|
||||||
++had_error;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
canon = buffer;
|
haveanswer = true;
|
||||||
buffer = __mempcpy (buffer, tbuf, n);
|
|
||||||
buflen -= n;
|
|
||||||
h_namelen = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop parsing if we encounter a record with incorrect RDATA
|
|
||||||
length. */
|
|
||||||
if (type == T_A || type == T_AAAA)
|
|
||||||
{
|
|
||||||
if (n != rrtype_to_rdata_length (type))
|
|
||||||
{
|
|
||||||
++had_error;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Skip unknown records. */
|
|
||||||
cp += n;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (type == T_A || type == T_AAAA);
|
|
||||||
if (*pat == NULL)
|
|
||||||
{
|
|
||||||
uintptr_t pad = (-(uintptr_t) buffer
|
|
||||||
% __alignof__ (struct gaih_addrtuple));
|
|
||||||
buffer += pad;
|
|
||||||
buflen = buflen > pad ? buflen - pad : 0;
|
|
||||||
|
|
||||||
if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple)))
|
|
||||||
goto too_small;
|
|
||||||
|
|
||||||
*pat = (struct gaih_addrtuple *) buffer;
|
|
||||||
buffer += sizeof (struct gaih_addrtuple);
|
|
||||||
buflen -= sizeof (struct gaih_addrtuple);
|
|
||||||
}
|
|
||||||
|
|
||||||
(*pat)->name = NULL;
|
|
||||||
(*pat)->next = NULL;
|
|
||||||
|
|
||||||
if (*firstp)
|
|
||||||
{
|
|
||||||
/* We compose a single hostent out of the entire chain of
|
|
||||||
entries, so the TTL of the hostent is essentially the lowest
|
|
||||||
TTL in the chain. */
|
|
||||||
if (ttlp != NULL && ttl < *ttlp)
|
|
||||||
*ttlp = ttl;
|
|
||||||
|
|
||||||
(*pat)->name = canon ?: 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)
|
if (haveanswer)
|
||||||
{
|
{
|
||||||
*patp = pat;
|
|
||||||
*bufferp = buffer;
|
|
||||||
*buflenp = buflen;
|
|
||||||
|
|
||||||
*h_errnop = NETDB_SUCCESS;
|
*h_errnop = NETDB_SUCCESS;
|
||||||
return NSS_STATUS_SUCCESS;
|
return NSS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* 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. */
|
|
||||||
if (canon != NULL)
|
|
||||||
{
|
{
|
||||||
|
/* 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. */
|
||||||
*h_errnop = HOST_NOT_FOUND;
|
*h_errnop = HOST_NOT_FOUND;
|
||||||
return NSS_STATUS_NOTFOUND;
|
return NSS_STATUS_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
*h_errnop = NETDB_INTERNAL;
|
|
||||||
return NSS_STATUS_TRYAGAIN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static enum nss_status
|
static enum nss_status
|
||||||
gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
gaih_getanswer (unsigned char *packet1, size_t packet1len,
|
||||||
int anslen2, const char *qname,
|
unsigned char *packet2, size_t packet2len,
|
||||||
struct gaih_addrtuple **pat, char *buffer, size_t buflen,
|
struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||||||
int *errnop, int *h_errnop, int32_t *ttlp)
|
int *errnop, int *h_errnop, int32_t *ttlp)
|
||||||
{
|
{
|
||||||
int first = 1;
|
|
||||||
|
|
||||||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
/* Combining the NSS status of two distinct queries requires some
|
/* Combining the NSS status of two distinct queries requires some
|
||||||
@ -1156,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
|||||||
between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
|
between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
|
||||||
A recoverable TRYAGAIN is almost always due to buffer size issues
|
A recoverable TRYAGAIN is almost always due to buffer size issues
|
||||||
and returns ERANGE in errno and the caller is expected to retry
|
and returns ERANGE in errno and the caller is expected to retry
|
||||||
with a larger buffer.
|
with a larger buffer. (The caller, _nss_dns_gethostbyname4_r,
|
||||||
|
ignores the return status if it detects that the result buffer
|
||||||
|
has been exhausted and generates a TRYAGAIN failure with an
|
||||||
|
ERANGE code.)
|
||||||
|
|
||||||
Lastly, you may be tempted to make significant changes to the
|
Lastly, you may be tempted to make significant changes to the
|
||||||
conditions in this code to bring about symmetry between responses.
|
conditions in this code to bring about symmetry between responses.
|
||||||
@ -1236,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
|||||||
is a recoverable error we now return TRYAGIN even if the first
|
is a recoverable error we now return TRYAGIN even if the first
|
||||||
response was SUCCESS. */
|
response was SUCCESS. */
|
||||||
|
|
||||||
if (anslen1 > 0)
|
if (packet1len > 0)
|
||||||
status = gaih_getanswer_slice(answer1, anslen1, qname,
|
|
||||||
&pat, &buffer, &buflen,
|
|
||||||
errnop, h_errnop, ttlp,
|
|
||||||
&first);
|
|
||||||
|
|
||||||
if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
|
|
||||||
|| (status == NSS_STATUS_TRYAGAIN
|
|
||||||
/* We want to look at the second answer in case of an
|
|
||||||
NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e.
|
|
||||||
*h_errnop is NO_RECOVERY. If not, and if the failure was due to
|
|
||||||
an insufficient buffer (ERANGE), then we need to drop the results
|
|
||||||
and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can
|
|
||||||
repeat the query with a larger buffer. */
|
|
||||||
&& (*errnop != ERANGE || *h_errnop == NO_RECOVERY)))
|
|
||||||
&& answer2 != NULL && anslen2 > 0)
|
|
||||||
{
|
{
|
||||||
enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
|
status = gaih_getanswer_slice (packet1, packet1len,
|
||||||
&pat, &buffer, &buflen,
|
abuf, &pat, errnop, h_errnop, ttlp, true);
|
||||||
errnop, h_errnop, ttlp,
|
if (alloc_buffer_has_failed (abuf))
|
||||||
&first);
|
/* Do not try parsing the second packet if a larger result
|
||||||
|
buffer is needed. The caller implements the resizing
|
||||||
|
protocol because *abuf has been exhausted. */
|
||||||
|
return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
|
||||||
|
&& packet2 != NULL && packet2len > 0)
|
||||||
|
{
|
||||||
|
enum nss_status status2
|
||||||
|
= gaih_getanswer_slice (packet2, packet2len,
|
||||||
|
abuf, &pat, errnop, h_errnop, ttlp,
|
||||||
|
/* Success means that data with a
|
||||||
|
canonical name has already been
|
||||||
|
stored. Do not store the name again. */
|
||||||
|
status != NSS_STATUS_SUCCESS);
|
||||||
/* Use the second response status in some cases. */
|
/* Use the second response status in some cases. */
|
||||||
if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
|
if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
|
||||||
status = status2;
|
status = status2;
|
||||||
/* Do not return a truncated second response (unless it was
|
|
||||||
unavoidable e.g. unrecoverable TRYAGAIN). */
|
|
||||||
if (status == NSS_STATUS_SUCCESS
|
|
||||||
&& (status2 == NSS_STATUS_TRYAGAIN
|
|
||||||
&& *errnop == ERANGE && *h_errnop != NO_RECOVERY))
|
|
||||||
status = NSS_STATUS_TRYAGAIN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -1273,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
|||||||
|
|
||||||
/* Variant of gaih_getanswer without a second (AAAA) response. */
|
/* Variant of gaih_getanswer without a second (AAAA) response. */
|
||||||
static enum nss_status
|
static enum nss_status
|
||||||
gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
|
gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
|
||||||
struct gaih_addrtuple **pat,
|
struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||||||
char *buffer, size_t buflen,
|
|
||||||
int *errnop, int *h_errnop, int32_t *ttlp)
|
int *errnop, int *h_errnop, int32_t *ttlp)
|
||||||
{
|
{
|
||||||
int first = 1;
|
|
||||||
|
|
||||||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||||
if (anslen1 > 0)
|
if (packetlen > 0)
|
||||||
status = gaih_getanswer_slice (answer1, anslen1, qname,
|
status = gaih_getanswer_slice (packet, packetlen,
|
||||||
&pat, &buffer, &buflen,
|
abuf, &pat, errnop, h_errnop, ttlp, true);
|
||||||
errnop, h_errnop, ttlp,
|
|
||||||
&first);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user