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
|
||||
#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
|
||||
single list type for addresses and host names. */
|
||||
#define DYNARRAY_STRUCT ptrlist
|
||||
@ -125,18 +118,18 @@ static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||||
char **hnamep, int *errnop,
|
||||
int *h_errnop, int32_t *ttlp);
|
||||
|
||||
static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
|
||||
const querybuf *answer2, int anslen2,
|
||||
const char *qname,
|
||||
static enum nss_status gaih_getanswer (unsigned char *packet1,
|
||||
size_t packet1len,
|
||||
unsigned char *packet2,
|
||||
size_t packet2len,
|
||||
struct alloc_buffer *abuf,
|
||||
struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp);
|
||||
static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1,
|
||||
int anslen1,
|
||||
const char *qname,
|
||||
static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet,
|
||||
size_t packetlen,
|
||||
struct alloc_buffer *abuf,
|
||||
struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
int32_t *ttlp);
|
||||
|
||||
@ -408,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||||
name = cp;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
querybuf *buf;
|
||||
u_char *ptr;
|
||||
} host_buffer;
|
||||
querybuf *orig_host_buffer;
|
||||
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
|
||||
unsigned char dns_packet_buffer[2048];
|
||||
unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
|
||||
u_char *ans2p = NULL;
|
||||
int nans2p = 0;
|
||||
int resplen2 = 0;
|
||||
int ans2p_malloced = 0;
|
||||
struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
|
||||
host_buffer.buf->buf, 2048, &host_buffer.ptr,
|
||||
&ans2p, &nans2p, &resplen2, &ans2p_malloced);
|
||||
dns_packet_buffer, sizeof (dns_packet_buffer),
|
||||
&alt_dns_packet_buffer, &ans2p, &nans2p,
|
||||
&resplen2, &ans2p_malloced);
|
||||
if (n >= 0)
|
||||
status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
|
||||
resplen2, name, pat, buffer, buflen,
|
||||
errnop, herrnop, ttlp);
|
||||
status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
|
||||
&abuf, pat, errnop, herrnop, ttlp);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = __res_context_search (ctx, name, C_IN, T_A,
|
||||
host_buffer.buf->buf, 2048, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
dns_packet_buffer, sizeof (dns_packet_buffer),
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
if (n >= 0)
|
||||
status = gaih_getanswer_noaaaa (host_buffer.buf, n,
|
||||
name, pat, buffer, buflen,
|
||||
errnop, herrnop, ttlp);
|
||||
status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
|
||||
&abuf, pat, errnop, herrnop, ttlp);
|
||||
}
|
||||
if (n < 0)
|
||||
{
|
||||
@ -473,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
|
||||
__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. */
|
||||
if (ans2p_malloced)
|
||||
free (ans2p);
|
||||
|
||||
if (host_buffer.buf != orig_host_buffer)
|
||||
free (host_buffer.buf);
|
||||
if (alt_dns_packet_buffer != dns_packet_buffer)
|
||||
free (alt_dns_packet_buffer);
|
||||
|
||||
__resolv_context_put (ctx);
|
||||
return status;
|
||||
@ -892,259 +888,152 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||||
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
|
||||
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)
|
||||
gaih_getanswer_slice (unsigned char *packet, size_t packetlen,
|
||||
struct alloc_buffer *abuf,
|
||||
struct gaih_addrtuple ***tailp,
|
||||
int *errnop, int *h_errnop, int32_t *ttlp,
|
||||
bool store_canon)
|
||||
{
|
||||
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 (__glibc_unlikely (qdcount != 1))
|
||||
struct ns_rr_cursor c;
|
||||
if (!__ns_rr_cursor_init (&c, packet, packetlen))
|
||||
{
|
||||
/* This should not happen because __res_context_query already
|
||||
perfroms response validation. */
|
||||
*h_errnop = NO_RECOVERY;
|
||||
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];
|
||||
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 (__glibc_unlikely (errno == EMSGSIZE))
|
||||
{
|
||||
too_small:
|
||||
*errnop = ERANGE;
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
/* This is a pointer to a possibly-compressed name in the packet.
|
||||
Eventually it is equivalent to the canonical name. If needed, it
|
||||
is uncompressed and translated to text form when the first
|
||||
address tuple is encountered. */
|
||||
const unsigned char *compressed_alias_name = expected_name;
|
||||
|
||||
n = -1;
|
||||
}
|
||||
|
||||
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)
|
||||
if (ancount == 0 || !__res_binary_hnok (compressed_alias_name))
|
||||
{
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
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,
|
||||
packtmp, sizeof packtmp);
|
||||
if (n != -1 &&
|
||||
(h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
|
||||
struct ns_rr_wire rr;
|
||||
if (!__ns_rr_cursor_next (&c, &rr))
|
||||
{
|
||||
if (__glibc_unlikely (errno == EMSGSIZE))
|
||||
goto too_small;
|
||||
|
||||
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;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t type;
|
||||
NS_GET16 (type, cp);
|
||||
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))
|
||||
/* NB: No check for owner name match, based on historic
|
||||
precedent. Record the CNAME target as the new expected
|
||||
name. */
|
||||
int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
|
||||
name_buffer, sizeof (name_buffer));
|
||||
if (n < 0)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
cp += n;
|
||||
|
||||
if (*firstp && __libc_res_hnok (tbuf))
|
||||
expected_name = name_buffer;
|
||||
if (store_canon && __res_binary_hnok (name_buffer))
|
||||
/* 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. */
|
||||
if (h_name + h_namelen == buffer)
|
||||
ntup->next = NULL;
|
||||
if (store_canon && compressed_alias_name != NULL)
|
||||
{
|
||||
buffer = h_name;
|
||||
buflen += h_namelen;
|
||||
/* This assumes that all the CNAME records come
|
||||
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;
|
||||
if (__glibc_unlikely (n > buflen))
|
||||
goto too_small;
|
||||
if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
}
|
||||
/* Link in the new tuple, and update the tail pointer to
|
||||
point to its next field. */
|
||||
**tailp = ntup;
|
||||
*tailp = &ntup->next;
|
||||
|
||||
canon = buffer;
|
||||
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;
|
||||
haveanswer = true;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
*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. */
|
||||
if (canon != NULL)
|
||||
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. */
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
gaih_getanswer (unsigned char *packet1, size_t packet1len,
|
||||
unsigned char *packet2, size_t packet2len,
|
||||
struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||||
int *errnop, int *h_errnop, int32_t *ttlp)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* 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).
|
||||
A recoverable TRYAGAIN is almost always due to buffer size issues
|
||||
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
|
||||
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
|
||||
response was SUCCESS. */
|
||||
|
||||
if (anslen1 > 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)
|
||||
if (packet1len > 0)
|
||||
{
|
||||
enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp,
|
||||
&first);
|
||||
status = gaih_getanswer_slice (packet1, packet1len,
|
||||
abuf, &pat, errnop, h_errnop, ttlp, true);
|
||||
if (alloc_buffer_has_failed (abuf))
|
||||
/* 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. */
|
||||
if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
|
||||
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;
|
||||
@ -1273,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||||
|
||||
/* Variant of gaih_getanswer without a second (AAAA) response. */
|
||||
static enum nss_status
|
||||
gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname,
|
||||
struct gaih_addrtuple **pat,
|
||||
char *buffer, size_t buflen,
|
||||
gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen,
|
||||
struct alloc_buffer *abuf, struct gaih_addrtuple **pat,
|
||||
int *errnop, int *h_errnop, int32_t *ttlp)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||
if (anslen1 > 0)
|
||||
status = gaih_getanswer_slice (answer1, anslen1, qname,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp,
|
||||
&first);
|
||||
if (packetlen > 0)
|
||||
status = gaih_getanswer_slice (packet, packetlen,
|
||||
abuf, &pat, errnop, h_errnop, ttlp, true);
|
||||
return status;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user