From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dormouse.elm.relay.mailchannels.net (dormouse.elm.relay.mailchannels.net [23.83.212.50]) by sourceware.org (Postfix) with ESMTPS id 83AA23858D3C for ; Mon, 22 Aug 2022 21:59:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 83AA23858D3C 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 E3376121BC7; Mon, 22 Aug 2022 21:59:08 +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 6F7B61221BA; Mon, 22 Aug 2022 21:59:08 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1661205548; a=rsa-sha256; cv=none; b=h3VmRaQs0O5mL8Wo4Z76pYjqz/kW3qaEhoIcJkesfS+/nAZkUCYC1dPX8vVlR8AedNFMO+ UNwBhBu/2d4dGIBQlFHGQONwO+0g3yJZxy8/x5HY9HBG6f97cS3XUJgPUPHp44N07dYZAm avmHaXx7GyrzcVXVC0JMizvxBHYUuIKzlrRaY3FHfgOiQhh01cXUJk4+Ab96hekZz1F4mZ nOjfXZ28j6Pkdbeg5w4voB7tP9a7rT6SJvPN9WAYDNTlHmw/kYqgsCOdjcUJkIsmNu39XE fSVb4QHub6FKCP8Y8c82eXn3FDH3h/R4t7zsrMG17nWCS7YUfdI5b01X+/5jEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1661205548; 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=9Zd+U8dP5pdv3g0yzEYTInriMS5x2i8OmVJiq854K4c=; b=WyLeVfdJRPqZycX5c+G98QpDIkNELdZVhPHzFog6LPciG+m+T05CeTFGxWcrs8PLXHwC45 SCOH3/a15JRJqRi+PQkv6KQGUtveOALgI4/NUmc9u/oExqzBQ0vUehnuFMj7WmyeU1RWZP QBoIJY8raoCbr1exFakmIVKIqhKGw1gc/lJUT1rWHLzkFAY3+tQ2XNrk5imuiEq2ICWLgy Avn8aqZ+qcQuxn3nMW3G6/Dofe55re6eN2xAG2o7VZJhoBAHhQY7oMnJDoOkNtEhNXBDbv JcXE60bN4f8oBDRXDp6MJah1wL6//fjlnoa2UsWJOwuU+2muix+lTtERSxL1RQ== ARC-Authentication-Results: i=1; rspamd-79945fd77c-qls8j; 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-Name-Trail: 5f52a6435bd8e74d_1661205548711_1247935815 X-MC-Loop-Signature: 1661205548711:132550820 X-MC-Ingress-Time: 1661205548711 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.124.238.95 (trex/6.7.1); Mon, 22 Aug 2022 21:59:08 +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) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4MBR8W6FtFz3N; Mon, 22 Aug 2022 14:59:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gotplt.org; s=dreamhost; t=1661205548; bh=9Zd+U8dP5pdv3g0yzEYTInriMS5x2i8OmVJiq854K4c=; h=Date:Subject:To:From:Content-Type:Content-Transfer-Encoding; b=Ku1uYOBgWtAIy7yTgM9HMQSgbptNBtAOlZ924iR1XWgKVFdut8TiCgp7+RKwCTYBc xnppcr1l6+FgV+EAQ2sh5x+KTZOqJJLohLt1xLdKLwWkn9AvL0QPknXyGf6/YxvKbW LibRR5dL3NfXVw1JP4QAAU0xMy0EcU+YVGEi1CC9WvbUOQM+AFH/uYviYUgA6Sxo+q KDaouzcapFFzaLTWQRlfzw0MnOmExkICk5Rvuf1IytZwEsLiEkT2XROMwft3IZyJf0 R8qcz3IBIN75CPSzGj41G8jU1t8qKuvNwF7dkShD6AGpcXzLagrBpS/ArSqTzNtOXo aUKGXBdMndaiQ== Message-ID: <37b7a758-628f-1d5e-8bf2-442b6323df14@gotplt.org> Date: Mon, 22 Aug 2022 17:59:06 -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 08/13] nss_dns: Rewrite _nss_dns_gethostbyaddr2_r and getanswer_ptr Content-Language: en-US To: Florian Weimer , libc-alpha@sourceware.org References: From: Siddhesh Poyarekar In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-3036.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_BL_SPAMCOP_NET, 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 21:59:15 -0000 On 2022-08-10 05:30, Florian Weimer via Libc-alpha wrote: > The simplification takes advantage of the split from getanswer_r. > It fixes various aliases issues, and optimizes NSS buffer usage. > The new DNS packet parsing helpers are used, too. > --- > resolv/nss_dns/dns-host.c | 405 ++++++++++---------------------------- > 1 file changed, 102 insertions(+), 303 deletions(-) > LGTM. Reviewed-by: Siddhesh Poyarekar > diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c > index d384e1f82d..cd26399b7e 100644 > --- a/resolv/nss_dns/dns-host.c > +++ b/resolv/nss_dns/dns-host.c > @@ -69,6 +69,7 @@ > * --Copyright-- > */ > > +#include > #include > #include > #include > @@ -116,10 +117,9 @@ static enum nss_status getanswer_r (struct resolv_context *ctx, > struct hostent *result, char *buffer, > size_t buflen, int *errnop, int *h_errnop, > int map, int32_t *ttlp, char **canonp); > -static enum nss_status getanswer_ptr (const querybuf *answer, int anslen, > - const char *qname, > - struct hostent *result, char *buffer, > - size_t buflen, int *errnop, > +static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, > + struct alloc_buffer *abuf, > + char **hnamep, int *errnop, > int *h_errnop, int32_t *ttlp); > > static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, > @@ -456,36 +456,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, > static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; > static const u_char v6local[] = { 0,0, 0,1 }; > const u_char *uaddr = (const u_char *)addr; > - struct host_data > - { > - char *aliases[MAX_NR_ALIASES]; > - unsigned char host_addr[16]; /* IPv4 or IPv6 */ > - char *h_addr_ptrs[MAX_NR_ADDRS + 1]; > - char linebuffer[0]; > - } *host_data = (struct host_data *) buffer; > - union > - { > - querybuf *buf; > - u_char *ptr; > - } host_buffer; > - querybuf *orig_host_buffer; > char qbuf[MAXDNAME+1], *qp = NULL; > size_t size; > int n, status; > int olderr = errno; > > - 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))) > - { > - *errnop = ERANGE; > - *h_errnop = NETDB_INTERNAL; > - return NSS_STATUS_TRYAGAIN; > - } > - > - host_data = (struct host_data *) buffer; > + /* Prepare the allocation buffer. Store the pointer array first, to > + benefit from buffer alignment. */ > + struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); > + char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); > + if (address_array == NULL) > + { > + *errnop = ERANGE; > + *h_errnop = NETDB_INTERNAL; > + return NSS_STATUS_TRYAGAIN; > + } > > struct resolv_context *ctx = __resolv_context_get (); > if (ctx == NULL) > @@ -529,8 +514,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, > return NSS_STATUS_UNAVAIL; > } > > - host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); > - > switch (af) > { > case AF_INET: > @@ -554,35 +537,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, > break; > } > > - n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, > - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); > + unsigned char dns_packet_buffer[1024]; > + unsigned char *alt_dns_packet_buffer = dns_packet_buffer; > + n = __res_context_query (ctx, qbuf, C_IN, T_PTR, > + dns_packet_buffer, sizeof (dns_packet_buffer), > + &alt_dns_packet_buffer, > + NULL, NULL, NULL, NULL); > if (n < 0) > { > *h_errnop = h_errno; > __set_errno (olderr); > - 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 errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; > } > > - status = getanswer_ptr (host_buffer.buf, n, qbuf, result, > - buffer, buflen, errnop, h_errnop, ttlp); > - if (host_buffer.buf != orig_host_buffer) > - free (host_buffer.buf); > + status = getanswer_ptr (alt_dns_packet_buffer, n, > + &abuf, &result->h_name, errnop, h_errnop, ttlp); > + > + if (alt_dns_packet_buffer != dns_packet_buffer) > + free (alt_dns_packet_buffer); > + __resolv_context_put (ctx); > + > if (status != NSS_STATUS_SUCCESS) > - { > - __resolv_context_put (ctx); > - return status; > - } > + return status; > > + /* result->h_name has already been set by getanswer_ptr. */ > result->h_addrtype = af; > result->h_length = len; > - memcpy (host_data->host_addr, addr, len); > - host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; > - host_data->h_addr_ptrs[1] = NULL; > + /* Increase the alignment to 4, in case there are applications out > + there that expect at least this level of address alignment. */ > + address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); > + alloc_buffer_copy_bytes (&abuf, uaddr, len); > + address_array[1] = NULL; > + > + /* This check also covers allocation failure in getanswer_ptr. */ > + if (alloc_buffer_has_failed (&abuf)) > + { > + *errnop = ERANGE; > + *h_errnop = NETDB_INTERNAL; > + return NSS_STATUS_TRYAGAIN; > + } > + result->h_addr_list = address_array; > + result->h_aliases = &address_array[1]; /* Points to NULL. */ > + > *h_errnop = NETDB_SUCCESS; > - __resolv_context_put (ctx); > return NSS_STATUS_SUCCESS; > } > libc_hidden_def (_nss_dns_gethostbyaddr2_r) > @@ -961,287 +961,86 @@ getanswer_r (struct resolv_context *ctx, > } > > static enum nss_status > -getanswer_ptr (const querybuf *answer, int anslen, const char *qname, > - struct hostent *result, char *buffer, size_t buflen, > +getanswer_ptr (unsigned char *packet, size_t packetlen, > + struct alloc_buffer *abuf, char **hnamep, > int *errnop, int *h_errnop, int32_t *ttlp) > { > - 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]; > - const char *tname; > - 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; > - > - tname = qname; > - 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) > + struct ns_rr_cursor c; > + if (!__ns_rr_cursor_init (&c, packet, packetlen)) > { > - if (__glibc_unlikely (errno == EMSGSIZE)) > - goto too_small; > - > - n = -1; > - } > - > - if (__glibc_unlikely (n < 0)) > - { > - *errnop = errno; > - *h_errnop = NO_RECOVERY; > - return NSS_STATUS_UNAVAIL; > - } > - if (__glibc_unlikely (__libc_res_dnok (bp) == 0)) > - { > - 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; > + 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]; > > - 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; > - > - while (ancount-- > 0 && cp < end_of_message && had_error == 0) > + while (ancount > 0) > { > - 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) > + 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 || __libc_res_dnok (bp) == 0)) > - { > - ++had_error; > - continue; > - } > - cp += n; /* name */ > - > - if (__glibc_unlikely (cp + 10 > end_of_message)) > - { > - ++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. */ > + /* Skip over records with the wrong class. */ > + if (rr.rclass != C_IN) > + continue; > > - if (end_of_message - cp < n) > - { > - /* RDATA extends beyond the end of the packet. */ > - ++had_error; > - continue; > - } > - > - if (__glibc_unlikely (class != C_IN)) > - { > - /* XXX - debug? syslog? */ > - cp += n; > - continue; /* XXX - had_error++ ? */ > - } > + /* Update TTL for known record types. */ > + if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) > + && 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; > - > - n = __libc_dn_expand (answer->buf, end_of_message, cp, > - tbuf, sizeof tbuf); > - if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) > - { > - ++had_error; > - continue; > - } > - cp += 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; > } > - tname = bp; > - bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ > - linebuflen -= n; > - continue; > + expected_name = name_buffer; > } > - > - switch (type) > + else if (rr.rtype == T_PTR > + && __ns_samebinaryname (rr.rname, expected_name)) > { > - case T_PTR: > - if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) > - { > - cp += n; > - continue; /* XXX - had_error++ ? */ > - } > - > - 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)) > + /* Decompress the target of the PTR record. This is the > + host name we are looking for. We can only use it if it > + is syntactically valid. Historically, only one host name > + is returned here. If the recursive resolver performs DNS > + record rotation, the returned host name is essentially > + random, which is why multiple PTR records are rarely > + used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for > + additional length checking. */ > + char hname[MAXHOSTNAMELEN + 1]; > + if (__ns_name_unpack (c.begin, c.end, rr.rdata, > + name_buffer, sizeof (name_buffer)) < 0 > + || !__res_binary_hnok (expected_name) > + || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) > { > - ++had_error; > - break; > + *h_errnop = NO_RECOVERY; > + return NSS_STATUS_UNAVAIL; > } > - if (ttlp != NULL && ttl < *ttlp) > - *ttlp = ttl; > - /* bind would put multiple PTR records as aliases, but we don't do > - that. */ > - result->h_name = bp; > - *h_errnop = NETDB_SUCCESS; > + /* Successful allocation is checked by the caller. */ > + *hnamep = alloc_buffer_copy_string (abuf, hname); > return NSS_STATUS_SUCCESS; > - 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; > - 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: > - cp += n; > - continue; /* XXX - had_error++ ? */ > } > - if (had_error == 0) > - ++haveanswer; > } > > - if (haveanswer > 0) > - { > - *ap = NULL; > - *hap = NULL; > - > - 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 PTR record found. */ > + if (ttlp != NULL) > + /* No caching of negative responses. */ > + *ttlp = 0; > > - *h_errnop = NETDB_SUCCESS; > - return NSS_STATUS_SUCCESS; > - } > - no_recovery: > *h_errnop = NO_RECOVERY; > *errnop = ENOENT; > return NSS_STATUS_TRYAGAIN;