From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from fish.tulip.relay.mailchannels.net (fish.tulip.relay.mailchannels.net [23.83.218.251]) by sourceware.org (Postfix) with ESMTPS id 7E4DE3858D32 for ; Tue, 23 Aug 2022 12:49:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7E4DE3858D32 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 C9021122F8D; Tue, 23 Aug 2022 12:49:40 +0000 (UTC) Received: from pdx1-sub0-mail-a306.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id DB9F012306C; Tue, 23 Aug 2022 12:49:39 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1661258979; a=rsa-sha256; cv=none; b=TlzJ6QR27wbr5NkRVad+C2YbZRMNm3tEiybIlPETYzY9tPPiXcFTtRLLTSCzaSkRbeKo8g MRKqje3MZsJWAOkPGntz19iFAIKqfFXwtpFCgJ5WnYqRRBU/86D605gS6r7gX2aVeOQ36M 0jeZhLjKWuQQsAGUOaSbH8RMEbMaUIeIjCmYQwn0KBdlBwouuOn45kvikgmiOvVztnESh+ +Y6v/eVUNhVfbCXsrqIAFHeku+Jv2KTqGywvQpVWYtlJagYVYwTDPh4Vd5OHv8Rc82OJMP WT+sYEJMmTdc2/CXnvGSpY3hPZLKH5nCGiG6rioQpawCDsPCdIZVoEZYPTQTJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1661258979; 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=KzrqS3u/62LeG954GCDjKbKNrWg5F+ohFON8QBgp/io=; b=eTUqgvIKOXQgmOPdXdm6T1ZQdni4FnGQVeP+3UhHbBeoJO+yjSI5s8LyiVYOcV+emm63EZ vorqGerthMboXDtDLiRJ9c9+9KAAnurT0598tDQjYjtvg0X1aCuyrRcERIhjefDyTwbYEa WRZIA1BKaqyKGRLNKMsJnvtFlsVy+xbt4X0OAC80883WPNMVTVQ1dNUJqOwpdwtK9LUCAl vaN5Qv1FoSOBqnSU1YmnDI+gXBUacBU7d4bAuO7F0DmRqUhlbUN5VhyLDPWB1CfteCXXpz 5eQARO11lWJYa/LBfB0h7Gm77seRuYEvZHKgfoow4R3eFSWikCvDYNdsGyUf/g== ARC-Authentication-Results: i=1; rspamd-79945fd77c-qjrzx; 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-Stupid-Keen: 7b1b678a3f3f6ea0_1661258980158_42618161 X-MC-Loop-Signature: 1661258980158:3751884265 X-MC-Ingress-Time: 1661258980158 Received: from pdx1-sub0-mail-a306.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.112.55.195 (trex/6.7.1); Tue, 23 Aug 2022 12:49:40 +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-a306.dreamhost.com (Postfix) with ESMTPSA id 4MBpw32Qb7zB8; Tue, 23 Aug 2022 05:49:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gotplt.org; s=dreamhost; t=1661258979; bh=KzrqS3u/62LeG954GCDjKbKNrWg5F+ohFON8QBgp/io=; h=Date:Subject:To:From:Content-Type:Content-Transfer-Encoding; b=QBsGCgwDzsU61JjlYCo9EhCPo4KJU8BNl15XequP8iBYcYZTl994ubKMskpPKD1Lm Uk/sF5sHwB8YiAnB0JqsphJsvFWLz+8cRlrPngRbTQi5iWckcuvFU4dYztyoch5hIs XdrYKwI1kxkkDVKObMua1fusyTtLG930Rj4bEjWU7DBPmVIniUr+3cBba5ppdMbklc ZTvtAajO0j94FT9JMkjPeUCDxXZaboeCgFQfpgF0kSSXoqMcakB3Zi26yxncruLwB3 ihghUGfoieGDAvD2YoXv75VHYfRv7zi2zw012+9rrI2OoyFu9yj9Q0mBxJ/z+lpzJ5 6xBzUCny+J4Hg== Message-ID: <3cf51cb4-c01e-7fee-509a-2e58c3e616d3@gotplt.org> Date: Tue, 23 Aug 2022 08:49:37 -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 13/13] nss_dns: Rewrite _nss_dns_gethostbyname4_r using current interfaces Content-Language: en-US To: Florian Weimer , libc-alpha@sourceware.org References: <2a52948e0655cd2c5a81ea654259b6303aefe3c0.1660123636.git.fweimer@redhat.com> From: Siddhesh Poyarekar In-Reply-To: <2a52948e0655cd2c5a81ea654259b6303aefe3c0.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: Tue, 23 Aug 2022 12:49:48 -0000 On 2022-08-10 05:31, 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 | 441 ++++++++++++++------------------------ > 1 file changed, 161 insertions(+), 280 deletions(-) > > diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c > index 809a269a7c..5166e5d254 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,153 @@ 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); Could you please add a comment on why a barrier is needed here? > + asm ("":::"memory"); > + 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 > @@ -1236,36 +1126,32 @@ 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. */ NSS_STATUS_TRYAGAIN? It does the right thing in the caller eventually, but this doesn't seem semantically correct. > + return NSS_STATUS_SUCCESS; > + } > + > + 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); > + if (alloc_buffer_has_failed (abuf)) > + /* Let the caller implement the buffer resizing protocol. */ > + return NSS_STATUS_SUCCESS; Same, wouldn't NSS_STATUS_TRYAGAIN be more correct here? > /* 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; > }