From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from bumble.birch.relay.mailchannels.net (bumble.birch.relay.mailchannels.net [23.83.209.25]) by sourceware.org (Postfix) with ESMTPS id B553D385AC0A for ; Mon, 29 Aug 2022 20:01:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B553D385AC0A 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 55A9722F1C; Mon, 29 Aug 2022 20:01:14 +0000 (UTC) Received: from pdx1-sub0-mail-a305 (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id BF5E723796; Mon, 29 Aug 2022 20:01:13 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1661803273; a=rsa-sha256; cv=none; b=7GQzwXg2QUsY30vPpmhBQXAeA0a4A/TgmpdzpLwqGj1xymcwWNsoNKDRryT2KZrQ0xy2LL hc37wdfP1aZHKY688KBf7XFS0uboLkD8iQZmWlr2gjPb6vNb1qcSAPxITEa6qOie1bqxOy kmhdLIXaXJrYjkKZBJkLwx67S4FxIuhUcUjgbH9hVaKv4hmjxu/SmdC9ytkKUVNTHDVcjF pvz7DczDMJ2ZSBvH6a12+0GQSQjgUiq3+qvoBT31IKw2Z6gNb1ked68uU+amE4u4mNubf2 DuQgawv1Ua4uaBN3Cz/sBBSu+gTMm50Szd+K9gWRSG3VRNPOgNP+D5/GnCOZHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1661803273; 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=peXYjTkNdrqEh/ZbRN1t2tOB+1FZVxrdl3s7ZrDFK6g=; b=r94KB6DdScGd60/bxfP7xk4P197IUvq26sDh/+gJTS916AlA8rBUzxZ2AaaKPXBYqyF8gb HPxkv97hamtMrVoX+ZLCtwYVC0aKihGDLk1x9JccZkvTeNIMiy1Io3fjuIapB2VTrwt0Ta JkL29K5X40+v7MaFOUiG8WZGMChV/DhIxjTfxw3Tyi4FTU39XOWopwh/vQVMnX+5YF2jtN UsAJaLLPxgM7BQFN3cwqUtsnGJB8IrqhbZeKE/TiJaXTn9fLv/brxVoaVWVrzUgn+YFeVK Z/py+WxY/MRak5L6lBQOsg6KI3gr9aQDdoR+1HcgaCcrG5nIOXrveKLUa8Btvg== ARC-Authentication-Results: i=1; rspamd-64cc6f7466-v6pqq; 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-Keen-Stupid: 1646599c328d55fb_1661803274073_420678970 X-MC-Loop-Signature: 1661803274073:2295545616 X-MC-Ingress-Time: 1661803274073 Received: from pdx1-sub0-mail-a305 (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.238.66 (trex/6.7.1); Mon, 29 Aug 2022 20:01:14 +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 (Postfix) with ESMTPSA id 4MGhCD6jnPzVw; Mon, 29 Aug 2022 13:01:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gotplt.org; s=dreamhost; t=1661803273; bh=peXYjTkNdrqEh/ZbRN1t2tOB+1FZVxrdl3s7ZrDFK6g=; h=Date:Subject:To:From:Content-Type:Content-Transfer-Encoding; b=R9Sna/B2HQx7Pdy6/UR9ZOf1djR07uQ2O5NOAhPenowTDrfZJM+npbqrPKfefuJUG duT/A3+HbT3l6IuicRirXSIv/uAH3oyJATq9T3AX4II2WP+rRx0kGIUucr1Hh5IFAz CQ8p7MG3AonkdhuTK9r+a8brsrY35S1kiGr5KFVM4v99FhVWh8lMOgrloEZBRsm4of Ifybzm2Wm8XIkgxdfV91qoOV2ciCC5GIPkbv+bA2YXqeUOh7qI87lmgsy1r7wtytzl oO2RwlYjIrokp3Jgii/ccsfdW2ZLnE5pnKeF7WhOqg9ly9mta5AxFHiDsaWXK2zMrJ WMBpb0LuZJsAg== Message-ID: <23937e11-a581-f306-64d4-aa6251e1336e@gotplt.org> Date: Mon, 29 Aug 2022 16:01:11 -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 v2 13/13] nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces Content-Language: en-US To: Florian Weimer , libc-alpha@sourceware.org References: <53c1f496ecde3b2cceabe82c8191f51104ed6f88.1661509943.git.fweimer@redhat.com> From: Siddhesh Poyarekar In-Reply-To: <53c1f496ecde3b2cceabe82c8191f51104ed6f88.1661509943.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 List-Id: On 2022-08-26 06:34, Florian Weimer via Libc-alpha wrote: > 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. > --- > resolv/nss_dns/dns-host.c | 443 ++++++++++++++------------------------ > 1 file changed, 162 insertions(+), 281 deletions(-) LGTM. Reviewed-by: Siddhesh Poyarekar > > diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c > index bea505d697..9fa81f23c8 100644 > --- a/resolv/nss_dns/dns-host.c > +++ b/resolv/nss_dns/dns-host.c > @@ -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)) > - { > - *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 (__glibc_unlikely (errno == EMSGSIZE)) > - { > - too_small: > - *errnop = ERANGE; > - *h_errnop = NETDB_INTERNAL; > - return NSS_STATUS_TRYAGAIN; > - } > - > - 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)) > + 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; > + 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]; > > - int haveanswer = 0; > - int had_error = 0; > - char *canon = NULL; > - char *h_name = NULL; > - int h_namelen = 0; > + /* 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; > > - 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) > - { > - 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; > - } > - > - cp += n; /* name */ > - > - if (__glibc_unlikely (cp + 10 > end_of_message)) > - { > - ++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) > + struct ns_rr_wire rr; > + if (!__ns_rr_cursor_next (&c, &rr)) > { > - /* RDATA extends beyond the end of the packet. */ > - ++had_error; > - continue; > + *h_errnop = NO_RECOVERY; > + return NSS_STATUS_UNAVAIL; > } > > - if (class != C_IN) > - { > - cp += n; > - continue; > - } > + /* Update TTL for known 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) > { > - 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; > - continue; > - } > - cp += n; > - > - if (*firstp && __libc_res_hnok (tbuf)) > + /* 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) > { > - /* Reclaim buffer space. */ > - if (h_name + h_namelen == buffer) > - { > - buffer = h_name; > - buflen += h_namelen; > - } > - > - n = strlen (tbuf) + 1; > - if (__glibc_unlikely (n > buflen)) > - goto too_small; > - if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) > - { > - ++had_error; > - continue; > - } > - > - canon = buffer; > - buffer = __mempcpy (buffer, tbuf, n); > - buflen -= n; > - h_namelen = 0; > + *h_errnop = NO_RECOVERY; > + return NSS_STATUS_UNAVAIL; > } > - continue; > + 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; > } > - > - /* Stop parsing if we encounter a record with incorrect RDATA > - length. */ > - if (type == T_A || type == T_AAAA) > + else if (rr.rtype == qtype > + && __ns_samebinaryname (rr.rname, expected_name) > + && rr.rdlength == rrtype_to_rdata_length (qtype)) > { > - if (n != rrtype_to_rdata_length (type)) > + 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) > { > - ++had_error; > - continue; > + ntup->next = NULL; > + if (store_canon && compressed_alias_name != NULL) > + { > + /* 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; > + > + /* Link in the new tuple, and update the tail pointer to > + point to its next field. */ > + **tailp = ntup; > + *tailp = &ntup->next; > + > + 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; > }