From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from olivedrab.birch.relay.mailchannels.net (olivedrab.birch.relay.mailchannels.net [23.83.209.135]) by sourceware.org (Postfix) with ESMTPS id 8906A3857C4B for ; Mon, 22 Aug 2022 22:20:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8906A3857C4B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 379A66C1D18; Mon, 22 Aug 2022 22:20:54 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 96C626C1E3D; Mon, 22 Aug 2022 22:20:53 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1661206853; a=rsa-sha256; cv=none; b=VHCeMaQlcaaGCf88Arz+mO0U8BTtBjMZbjPTlZzuVRXhVQg3fWLmkX7aaz2DxTG3OQCSYo BEzj7LDCp9CbCJn7IErcnb9bjYovWEIj4nAXW0rXUpixBQpRgslv4GxIHT/Co0PONvC5pe sAwbCPQXo9llD10b/eIDgcIcEgFxmWpIoGIkbqBV1PxfxDaNgE9uA68fEJ5rQKQb+O573y fiUmrOyri2yWU6Nr5UHl5CorjCtTmY12RmelekYB/al913sYninQ1/FVqbL3qbrAS2X0tb hT6yzQYC2g7pHUKwV+YpPj7hCI0p2Ntenz/9XNVPO23oCoSgbHFGtWqA6xKexA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1661206853; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=8yKjWAv6MjO6hyZuPP5H6B5uJhGygE/oUEcOfVGSJ28=; b=hfNxu7RgqL8pbdJCGklr5pynA+TMNAsky6Vxu0hlBQSeZjB9DlyTFU22Fd0r9ZaB0v4FeS NY6/ul/e4rGZBXyLfzZGZtXoufECOhEK35xZ7lNDA6RWdIKewU/6cbTOsi29HowG9oOIdO 80zge5Jhe8QPg6DTNMtRP02jxJXUIR58c3thwkFpBACqFJiUNitol+ZgkREMXnta0olqL7 Zx0kXC/aRwEpeB3qQfWAYXgC6z21gL9LNndPevOjOGrgSZ++yyhQVrfDwLV/Aa51cQgGuG i4MyX2Q2sWGXIvnHn+FF9V3Au30+OV67oNg4bF8skYdSFhyRrlYmPM9Nme2ayw== ARC-Authentication-Results: i=1; rspamd-79945fd77c-87bwl; auth=pass smtp.auth=dreamhost smtp.mailfrom=siddhesh@gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Lonely-Reaction: 3c7d731449698691_1661206853921_2133383468 X-MC-Loop-Signature: 1661206853921:893153815 X-MC-Ingress-Time: 1661206853921 Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.121.210.153 (trex/6.7.1); Mon, 22 Aug 2022 22:20:53 +0000 Received: from [192.168.0.182] (bras-vprn-toroon4834w-lp130-16-184-147-84-238.dsl.bell.ca [184.147.84.238]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4MBRdd0GCvzPW; Mon, 22 Aug 2022 15:20:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gotplt.org; s=dreamhost; t=1661206853; bh=8yKjWAv6MjO6hyZuPP5H6B5uJhGygE/oUEcOfVGSJ28=; h=Date:Subject:To:From:Content-Type:Content-Transfer-Encoding; b=GJNIiRPQEx6y/airzCF57/V1Ul+8D5yjSJTAPx3qjAZCmuJBUDcy5BX4cYgeSC1cq bNmD/m4pDPs3yiSoQCdaP0I3Xl04fghgo2Kei6IrRngIbIWkHSg8URURICkC825YlX 3fkDjpcNrnCKT9ZCzgfq0fK93WxKqJUkKyei2U5954Je2Q3SGq7qmvP/Gf7CinJADB iNEoPx8M9kCsvWLPQ1qn0G4/U+DBrKXIZCd48YttxuqjpHtboNbhqY8ZtOj3hlaXD5 AwHuAitHwq2hZW0dV51uBBvTzAMcm/E5cItipmCi+6FJGZhi2fY3zvE0M4CR4UbTVq pYtsofzpxs3cw== Message-ID: <6a0e7965-896f-fa58-42dd-ba8c1b122d39@gotplt.org> Date: Mon, 22 Aug 2022 18:20:51 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.12.0 Subject: Re: [PATCH 10/13] nss_dns: Rewrite getanswer_r to match getanswer_ptr (bug 12154, bug 29305) Content-Language: en-US To: Florian Weimer , libc-alpha@sourceware.org References: <0654c03b786e9d05b8d732254c2caf017ecb044c.1660123636.git.fweimer@redhat.com> From: Siddhesh Poyarekar In-Reply-To: <0654c03b786e9d05b8d732254c2caf017ecb044c.1660123636.git.fweimer@redhat.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-3038.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Aug 2022 22:20:58 -0000 On 2022-08-10 05:30, Florian Weimer via Libc-alpha wrote: > Allocate the pointer arrays only at the end, when their sizes > are known. This addresses bug 29305. > > Skip over invalid names instead of failing lookups. This partially > fixes bug 12154 (for gethostbyname, fixing getaddrinfo requires > different changes). > --- > resolv/nss_dns/dns-host.c | 478 ++++++++++++++------------------------ > 1 file changed, 180 insertions(+), 298 deletions(-) OK except for a very tiny typo below. Reviewed-by: Siddhesh Poyarekar > > diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c > index 8e38583e15..0e7eef6889 100644 > --- a/resolv/nss_dns/dns-host.c > +++ b/resolv/nss_dns/dns-host.c > @@ -107,12 +107,19 @@ typedef union querybuf > u_char buf[MAXPACKET]; > } querybuf; > > -static enum nss_status getanswer_r (struct resolv_context *ctx, > - const querybuf *answer, int anslen, > - const char *qname, int qtype, > - struct hostent *result, char *buffer, > - size_t buflen, int *errnop, int *h_errnop, > - int32_t *ttlp, char **canonp); > +/* For historic reasons, pointers to IP addresses are char *, so use a > + single list type for addresses and host names. */ > +#define DYNARRAY_STRUCT ptrlist > +#define DYNARRAY_ELEMENT char * > +#define DYNARRAY_PREFIX ptrlist_ > +#include > + > +static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, > + uint16_t qtype, struct alloc_buffer *abuf, > + struct ptrlist *addresses, > + struct ptrlist *aliases, > + int *errnop, int *h_errnop, int32_t *ttlp); > +static void addrsort (struct resolv_context *ctx, char **ap, int num); > static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, > struct alloc_buffer *abuf, > char **hnamep, int *errnop, > @@ -184,12 +191,6 @@ gethostbyname3_context (struct resolv_context *ctx, > char *buffer, size_t buflen, int *errnop, > int *h_errnop, int32_t *ttlp, char **canonp) > { > - union > - { > - querybuf *buf; > - u_char *ptr; > - } host_buffer; > - querybuf *orig_host_buffer; > char tmp[NS_MAXDNAME]; > int size, type, n; > const char *cp; > @@ -223,10 +224,12 @@ gethostbyname3_context (struct resolv_context *ctx, > && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) > name = cp; > > - host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); > + unsigned char dns_packet_buffer[1024]; > + unsigned char *alt_dns_packet_buffer = dns_packet_buffer; > > - n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, > - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); > + n = __res_context_search (ctx, name, C_IN, type, > + dns_packet_buffer, sizeof (dns_packet_buffer), > + &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); > if (n < 0) > { > switch (errno) > @@ -255,12 +258,77 @@ gethostbyname3_context (struct resolv_context *ctx, > __set_errno (olderr); > } > else > - status = getanswer_r > - (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, > - errnop, h_errnop, ttlp, canonp); > + { > + struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); > > - if (host_buffer.buf != orig_host_buffer) > - free (host_buffer.buf); > + struct ptrlist addresses; > + ptrlist_init (&addresses); > + struct ptrlist aliases; > + ptrlist_init (&aliases); > + > + status = getanswer_r (alt_dns_packet_buffer, n, type, > + &abuf, &addresses, &aliases, > + errnop, h_errnop, ttlp); > + if (status == NSS_STATUS_SUCCESS) > + { > + if (ptrlist_has_failed (&addresses) > + || ptrlist_has_failed (&aliases)) > + { > + /* malloc failure. Do not retry using the ERANGE protocol. */ > + *errnop = ENOMEM; > + *h_errnop = NETDB_INTERNAL; > + status = NSS_STATUS_UNAVAIL; > + } > + > + /* Reserve the address and alias arrays in the result > + buffer. Both are NULL-terminated, but the first element > + of the alias array is stored in h_name, so no extra space > + for the nULL terminator is needed there. */ s/nULL/NULL/ > + result->h_addr_list > + = alloc_buffer_alloc_array (&abuf, char *, > + ptrlist_size (&addresses) + 1); > + result->h_aliases > + = alloc_buffer_alloc_array (&abuf, char *, > + ptrlist_size (&aliases)); > + if (alloc_buffer_has_failed (&abuf)) > + { > + /* Retry using the ERANGE protocol. */ > + *errnop = ERANGE; > + *h_errnop = NETDB_INTERNAL; > + status = NSS_STATUS_TRYAGAIN; > + } > + else > + { > + /* Copy the address list and NULL-terminate it. */ > + memcpy (result->h_addr_list, ptrlist_begin (&addresses), > + ptrlist_size (&addresses) * sizeof (char *)); > + result->h_addr_list[ptrlist_size (&addresses)] = NULL; > + > + /* Sort the address list if requested. */ > + if (type == T_A && __resolv_context_sort_count (ctx) > 0) > + addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); > + > + /* Copy the aliases, excluding the last one. */ > + memcpy (result->h_aliases, ptrlist_begin (&aliases), > + (ptrlist_size (&aliases) - 1) * sizeof (char *)); > + result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; > + > + /* The last alias goes into h_name. */ > + assert (ptrlist_size (&aliases) >= 1); > + result->h_name = ptrlist_end (&aliases)[-1]; > + > + /* This is also the canonical name. */ > + if (canonp != NULL) > + *canonp = result->h_name; > + } > + } > + > + ptrlist_free (&aliases); > + ptrlist_free (&addresses); > + } > + > + if (alt_dns_packet_buffer != dns_packet_buffer) > + free (alt_dns_packet_buffer); > return status; > } > > @@ -614,314 +682,128 @@ addrsort (struct resolv_context *ctx, char **ap, int num) > break; > } > > -static enum nss_status > -getanswer_r (struct resolv_context *ctx, > - const querybuf *answer, int anslen, const char *qname, int qtype, > - struct hostent *result, char *buffer, size_t buflen, > - int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) > +/* Convert the uncompressed, binary domain name CDNAME into its > + textual representation and add it to the end of ALIASES, allocating > + space for a copy of the name from ABUF. Skip adding the name if it > + is not a valid host name, and return false in that case, otherwise > + true. */ > +static bool > +getanswer_r_store_alias (const unsigned char *cdname, > + struct alloc_buffer *abuf, > + struct ptrlist *aliases) > { > - struct host_data > - { > - char *aliases[MAX_NR_ALIASES]; > - unsigned char host_addr[16]; /* IPv4 or IPv6 */ > - char *h_addr_ptrs[0]; > - } *host_data; > - int linebuflen; > - const HEADER *hp; > - const u_char *end_of_message, *cp; > - int n, ancount, qdcount; > - int haveanswer, had_error; > - char *bp, **ap, **hap; > - char tbuf[MAXDNAME]; > - u_char packtmp[NS_MAXCDNAME]; > - uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); > - buffer += pad; > - buflen = buflen > pad ? buflen - pad : 0; > - if (__glibc_unlikely (buflen < sizeof (struct host_data))) > - { > - /* The buffer is too small. */ > - too_small: > - *errnop = ERANGE; > - *h_errnop = NETDB_INTERNAL; > - return NSS_STATUS_TRYAGAIN; > - } > - host_data = (struct host_data *) buffer; > - linebuflen = buflen - sizeof (struct host_data); > - if (buflen - sizeof (struct host_data) != linebuflen) > - linebuflen = INT_MAX; > - > - result->h_name = NULL; > - end_of_message = answer->buf + anslen; > - > - /* > - * find first satisfactory answer > - */ > - hp = &answer->hdr; > - ancount = ntohs (hp->ancount); > - qdcount = ntohs (hp->qdcount); > - cp = answer->buf + HFIXEDSZ; > - if (__glibc_unlikely (qdcount != 1)) > - { > - *h_errnop = NO_RECOVERY; > - return NSS_STATUS_UNAVAIL; > - } > - if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) > - goto too_small; > - bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; > - linebuflen -= (ancount + 1) * sizeof (char *); > - > - n = __ns_name_unpack (answer->buf, end_of_message, cp, > - packtmp, sizeof packtmp); > - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) > - { > - if (__glibc_unlikely (errno == EMSGSIZE)) > - goto too_small; > - > - n = -1; > - } > + /* Filter out domain names that are not host names. */ > + if (!__res_binary_hnok (cdname)) > + return false; > + > + /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks > + for length. */ > + char dname[MAXHOSTNAMELEN + 1]; > + if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) > + return false; > + /* Do not report an error on allocation failure, instead store NULL > + or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS > + and detect the memory allocation failure or buffer space > + exhaustion, and report it accordingly. */ > + ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); > + return true; > +} > > - if (__glibc_unlikely (n < 0)) > - { > - *errnop = errno; > - *h_errnop = NO_RECOVERY; > - return NSS_STATUS_UNAVAIL; > - } > - if (__glibc_unlikely (__libc_res_hnok (bp) == 0)) > +static enum nss_status __attribute__ ((noinline)) > +getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, > + struct alloc_buffer *abuf, > + struct ptrlist *addresses, struct ptrlist *aliases, > + int *errnop, int *h_errnop, int32_t *ttlp) > +{ > + struct ns_rr_cursor c; > + if (!__ns_rr_cursor_init (&c, packet, packetlen)) > { > - errno = EBADMSG; > - *errnop = EBADMSG; > + /* This should not happen because __res_context_query already > + perfroms response validation. */ > *h_errnop = NO_RECOVERY; > return NSS_STATUS_UNAVAIL; > } > - cp += n + QFIXEDSZ; > > - if (qtype == T_A || qtype == T_AAAA) > + /* Treat the QNAME just like an alias. Error out if it is not a > + valid host name. */ > + if (ns_rr_cursor_rcode (&c) == NXDOMAIN > + || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) > { > - /* res_send() has already verified that the query name is the > - * same as the one we sent; this just gets the expanded name > - * (i.e., with the succeeding search-domain tacked on). > - */ > - n = strlen (bp) + 1; /* for the \0 */ > - if (n >= MAXHOSTNAMELEN) > - { > - *h_errnop = NO_RECOVERY; > - *errnop = ENOENT; > - return NSS_STATUS_TRYAGAIN; > - } > - result->h_name = bp; > - bp += n; > - linebuflen -= n; > - if (linebuflen < 0) > - goto too_small; > - /* The qname can be abbreviated, but h_name is now absolute. */ > - qname = result->h_name; > + if (ttlp != NULL) > + /* No negative caching. */ > + *ttlp = 0; > + *h_errnop = HOST_NOT_FOUND; > + *errnop = ENOENT; > + return NSS_STATUS_NOTFOUND; > } > > - ap = host_data->aliases; > - *ap = NULL; > - result->h_aliases = host_data->aliases; > - hap = host_data->h_addr_ptrs; > - *hap = NULL; > - result->h_addr_list = host_data->h_addr_ptrs; > - haveanswer = 0; > - had_error = 0; > + 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]; > > - while (ancount-- > 0 && cp < end_of_message && had_error == 0) > + for (; ancount > 0; --ancount) > { > - int type, class; > - > - n = __ns_name_unpack (answer->buf, end_of_message, cp, > - packtmp, sizeof packtmp); > - if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) > - { > - if (__glibc_unlikely (errno == EMSGSIZE)) > - goto too_small; > - > - n = -1; > - } > - > - if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) > - { > - ++had_error; > - continue; > - } > - cp += n; /* name */ > - > - if (__glibc_unlikely (cp + 10 > end_of_message)) > + struct ns_rr_wire rr; > + if (!__ns_rr_cursor_next (&c, &rr)) > { > - ++had_error; > - continue; > + *h_errnop = NO_RECOVERY; > + return NSS_STATUS_UNAVAIL; > } > > - NS_GET16 (type, cp); > - 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; > - } > + /* Skip over records with the wrong class. */ > + if (rr.rclass != C_IN) > + continue; > > - if (__glibc_unlikely (class != C_IN)) > - { > - /* XXX - debug? syslog? */ > - cp += n; > - continue; /* XXX - had_error++ ? */ > - } > + /* Update TTL for recognized record types. */ > + if ((rr.rtype == T_CNAME || rr.rtype == qtype) > + && ttlp != NULL && *ttlp > rr.ttl) > + *ttlp = rr.ttl; > > - if (type == T_CNAME) > + if (rr.rtype == T_CNAME) > { > - /* A CNAME could also have a TTL entry. */ > - if (ttlp != NULL && ttl < *ttlp) > - *ttlp = ttl; > - > - if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) > - continue; > - n = __libc_dn_expand (answer->buf, end_of_message, cp, > - tbuf, sizeof tbuf); > - if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) > - { > - ++had_error; > - continue; > - } > - cp += n; > - /* Store alias. */ > - *ap++ = bp; > - n = strlen (bp) + 1; /* For the \0. */ > - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) > - { > - ++had_error; > - continue; > - } > - bp += n; > - linebuflen -= n; > - /* Get canonical name. */ > - n = strlen (tbuf) + 1; /* For the \0. */ > - if (__glibc_unlikely (n > linebuflen)) > - goto too_small; > - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) > + /* 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; > } > - result->h_name = bp; > - bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ > - linebuflen -= n; > - continue; > + /* And store the new name as an alias. */ > + getanswer_r_store_alias (name_buffer, abuf, aliases); > + expected_name = name_buffer; > } > - > - if (__glibc_unlikely (type != qtype)) > + else if (rr.rtype == qtype > + && __ns_samebinaryname (rr.rname, expected_name) > + && rr.rdlength == rrtype_to_rdata_length (qtype)) > { > - cp += n; > - continue; /* XXX - had_error++ ? */ > + /* Make a copy of the address and store it. Increase the > + alignment to 4, in case there are applications out there > + that expect at least this level of address alignment. */ > + ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); > + alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); > } > - > - switch (type) > - { > - case T_A: > - case T_AAAA: > - if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) > - { > - cp += n; > - continue; /* XXX - had_error++ ? */ > - } > - > - /* Stop parsing at a record whose length is incorrect. */ > - if (n != rrtype_to_rdata_length (type)) > - { > - ++had_error; > - break; > - } > - > - /* Skip records of the wrong type. */ > - if (n != result->h_length) > - { > - cp += n; > - continue; > - } > - if (!haveanswer) > - { > - int nn; > - > - /* 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; > - if (canonp != NULL) > - *canonp = bp; > - result->h_name = bp; > - nn = strlen (bp) + 1; /* for the \0 */ > - bp += nn; > - linebuflen -= nn; > - } > - > - /* Provide sufficient alignment for both address > - families. */ > - enum { align = 4 }; > - _Static_assert ((align % __alignof__ (struct in_addr)) == 0, > - "struct in_addr alignment"); > - _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, > - "struct in6_addr alignment"); > - { > - char *new_bp = PTR_ALIGN_UP (bp, align); > - linebuflen -= new_bp - bp; > - bp = new_bp; > - } > - > - if (__glibc_unlikely (n > linebuflen)) > - goto too_small; > - bp = __mempcpy (*hap++ = bp, cp, n); > - cp += n; > - linebuflen -= n; > - break; > - default: > - abort (); > - } > - if (had_error == 0) > - ++haveanswer; > } > > - if (haveanswer > 0) > + if (ptrlist_size (addresses) == 0) > { > - *ap = NULL; > - *hap = NULL; > - /* > - * Note: we sort even if host can take only one address > - * in its return structures - should give it the "best" > - * address in that case, not some random one > - */ > - if (haveanswer > 1 && qtype == T_A > - && __resolv_context_sort_count (ctx) > 0) > - addrsort (ctx, host_data->h_addr_ptrs, haveanswer); > - > - if (result->h_name == NULL) > - { > - n = strlen (qname) + 1; /* For the \0. */ > - if (n > linebuflen) > - goto too_small; > - if (n >= MAXHOSTNAMELEN) > - goto no_recovery; > - result->h_name = bp; > - bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ > - linebuflen -= n; > - } > + /* No address record found. */ > + if (ttlp != NULL) > + /* No caching of negative responses. */ > + *ttlp = 0; > > + *h_errnop = NO_RECOVERY; > + *errnop = ENOENT; > + return NSS_STATUS_TRYAGAIN; > + } > + else > + { > *h_errnop = NETDB_SUCCESS; > return NSS_STATUS_SUCCESS; > } > - no_recovery: > - *h_errnop = NO_RECOVERY; > - *errnop = ENOENT; > - /* 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 ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases > - ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); > } > > static enum nss_status