From nobody Fri Mar 28 21:37:50 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4ZPYlz0MMCz5rT4F; Fri, 28 Mar 2025 21:37:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZPYly5SVGz44HG; Fri, 28 Mar 2025 21:37:50 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743197870; 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; bh=30/zQYxOMQ/i/I9gU1LT6/C58WdupP5XFSint7OvE/M=; b=pUwqPWNdX+Akzgt9OTu054qa+HnbALXc7Ox2Znpn+t0DrAEHmAp6o1j0+uf67E2P+ZwSiU hgwCa6DPRmos2twp943SQNokv501rJtQp5DAWosWlB0UdWsShPKtNt+HV6OrXh7gRaW53n sAoCYUyvZJ4ZUt8fJmq9kZI+bvN2oGdoyvvVtEKZ0qIRgfSdIBkclZJDgFdQ9SUB7wSIXL u1jCgliF4BOEk+6Qh86O2Z9HHn0za7PcVpZ4sFUIlBvzEtEkOSQfzKSxU4ytRPtKzMGnID pt4PmceOEaz8fQbxF6nia89Md/xJvcskDdfrNSy7APchaAks+VG9PlqES9vozg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1743197870; a=rsa-sha256; cv=none; b=w0KQM9tuJ+UNpnmqsI9GZijYfztgweEbGA+EzKDVDMJquSkhcS4IZiS59VtewbEN7ocTha WM4fwpB5hcNsT02XqXFdLDvFjyT7GrX70HW0O4sARhd5+586PW+2bmUiYZ7d5pNsq6es3U EPsKCvTEKzCeNkPmyY/sYlp20evmFYmRgrRxLvi4i10aUtc36zHxosrhM7AB4M18XrkZ3P 75BHD5xnjkBKhRqNKZJE9vFVF0wUE/ssKCp2Pt6m/FREhOCCZLlT+Sf4Lr92VYfCzMiT4s rscDbShZRlLRx7p/nVyOtNtHR0AmD913gTTyAZ3EOoDXl9ziBcrGzfaFIJchVg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1743197870; 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; bh=30/zQYxOMQ/i/I9gU1LT6/C58WdupP5XFSint7OvE/M=; b=lABRpOPj4pAcniWfqCLIRlBLcwO70n8B5FNWSHAWVQqwcdmJgtHGDb40XLbSNltKIEw2QX QALSVIerqNxp8x2l0nI0k1WmeVfeRvXBpVhw/EgWCuyktOjn/AM1XK2uBnXgkXK/uDDEoM /ObdAssBV2JZuqrx8a/gZQiQlCzS7NqGiK7jM+OfJ7Umf35KTdRfE03oM4VshrBtjC10nE 4Eo9+0NasjBkbmynyie8VOB8CRVWnkavZdHcCPBx1KFOJ0h7nNItt9YNE3bSF2VVSNt4ei mqW1VRY+1VctSWGp3qbhQHMHHqhZDpjrYXafTBZOtVmVg3o9PvmRFXSrAAYeOA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ZPYly540Tz10m2; Fri, 28 Mar 2025 21:37:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 52SLboVf003527; Fri, 28 Mar 2025 21:37:50 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 52SLbogV003524; Fri, 28 Mar 2025 21:37:50 GMT (envelope-from git) Date: Fri, 28 Mar 2025 21:37:50 GMT Message-Id: <202503282137.52SLbogV003524@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: d803854bccb9 - main - libc/getaddrinfo(2): return EAI_AGAIN on nameserver timeout List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d803854bccb9ea527c1769ac403e011ff0e121e5 Auto-Submitted: auto-generated The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=d803854bccb9ea527c1769ac403e011ff0e121e5 commit d803854bccb9ea527c1769ac403e011ff0e121e5 Author: Gleb Smirnoff AuthorDate: 2025-03-28 21:35:35 +0000 Commit: Gleb Smirnoff CommitDate: 2025-03-28 21:36:40 +0000 libc/getaddrinfo(2): return EAI_AGAIN on nameserver timeout A nameserver timeout is a soft failure, future attempts may succeed. Returning EAI_AGAIN is crucial for API users to tell a soft name resolution failure from negative resolution result. Before the change we would return EAI_ADDRFAMILY, which I believe, is a regression from 144361386696, and before that revision we used to return EAI_NONAME in most of the cases. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D49411 --- lib/libc/net/getaddrinfo.c | 58 +++++++++++++++++++++------- lib/libc/tests/net/getaddrinfo/getaddrinfo.c | 53 ++++++++++++------------- 2 files changed, 67 insertions(+), 44 deletions(-) diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index 2b9499d5099b..b8af23ebe8da 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -2341,9 +2341,14 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) if (res_searchN(hostname, &q, res) < 0) { free(buf); free(buf2); - if (res->res_h_errno == NO_DATA) + switch (res->res_h_errno) { + case NO_DATA: return (NS_ADDRFAMILY); - return (NS_NOTFOUND); + case TRY_AGAIN: + return (NS_TRYAGAIN); + default: + return (NS_NOTFOUND); + } } /* prefer IPv6 */ if (q.next) { @@ -2705,9 +2710,18 @@ res_queryN(const char *name, struct res_target *target, res_state res) int n; u_int oflags; struct res_target *t; - int rcode; + u_int rcode; int ancount; + /* + * Extend rcode values in the scope of this function. The DNS header + * rcode we use in this function (hp->rcode) is limited by 4 bits, so + * anything starting from 16 is safe wrt aliasing. However, nameser.h + * already has extended enum __ns_rcode, so for future safety let's use + * even larger values. + */ +#define RCODE_UNREACH 32 +#define RCODE_TIMEDOUT 33 rcode = NOERROR; ancount = 0; @@ -2768,7 +2782,29 @@ again: printf(";; res_nquery: retry without EDNS0\n"); goto again; } - rcode = hp->rcode; /* record most recent error */ + /* + * Historically if a DNS server replied with ICMP port + * unreach res_nsend() would signal that with + * ECONNREFUSED and the upper layers would convert that + * into TRY_AGAIN. See 3a0b3b673936b and deeper. + * Also, res_nsend() may set errno to ECONNREFUSED due + * to internal failures. This may not be intentional, + * but we also treat that as soft failures. + * + * A more practical case is when a DNS server(s) were + * queried and didn't respond anything, which usually + * indicates a soft network failure. + */ + switch (errno) { + case ECONNREFUSED: + rcode = RCODE_UNREACH; + break; + case ETIMEDOUT: + rcode = RCODE_TIMEDOUT; + break; + default: + rcode = hp->rcode; + } #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; res_query: send error\n"); @@ -2800,6 +2836,8 @@ again: case NXDOMAIN: RES_SET_H_ERRNO(res, HOST_NOT_FOUND); break; + case RCODE_UNREACH: + case RCODE_TIMEDOUT: case SERVFAIL: RES_SET_H_ERRNO(res, TRY_AGAIN); break; @@ -2862,10 +2900,6 @@ res_searchN(const char *name, struct res_target *target, res_state res) ret = res_querydomainN(name, NULL, target, res); if (ret > 0 || trailing_dot) return (ret); - if (errno == ECONNREFUSED) { - RES_SET_H_ERRNO(res, TRY_AGAIN); - return (-1); - } switch (res->res_h_errno) { case NO_DATA: case HOST_NOT_FOUND: @@ -2906,7 +2940,6 @@ res_searchN(const char *name, struct res_target *target, res_state res) ret = res_querydomainN(name, *domain, target, res); if (ret > 0) return (ret); - /* * If no server present, give up. * If name isn't found in this domain, @@ -2920,11 +2953,6 @@ res_searchN(const char *name, struct res_target *target, res_state res) * but try the input name below in case it's * fully-qualified. */ - if (errno == ECONNREFUSED) { - RES_SET_H_ERRNO(res, TRY_AGAIN); - return (-1); - } - switch (res->res_h_errno) { case NO_DATA: got_nodata++; @@ -2933,8 +2961,8 @@ res_searchN(const char *name, struct res_target *target, res_state res) /* keep trying */ break; case TRY_AGAIN: - got_servfail++; if (hp->rcode == SERVFAIL) { + got_servfail++; /* try next search element, if any */ break; } diff --git a/lib/libc/tests/net/getaddrinfo/getaddrinfo.c b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c index 9d8575232d2a..022405f464ce 100644 --- a/lib/libc/tests/net/getaddrinfo/getaddrinfo.c +++ b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c @@ -122,19 +122,14 @@ ATF_TC_BODY(timeout, tc) resconf = badresolvconf; rv = getaddrinfo(goodname, NULL, &hints, &res); - /* - * XXXGL: EAI_ADDRFAMILY is most likely a regression from 144361386696. - * Error code on timeout used to be EAI_NONAME for many years and IMHO - * this is not correct either. Should be EAI_AGAIN. - */ - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); rv = getaddrinfo(goodname_dot, NULL, &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); } ATF_TC_WITHOUT_HEAD(timeout_specific); @@ -150,14 +145,14 @@ ATF_TC_BODY(timeout_specific, tc) resconf = badresolvconf; rv = getaddrinfo(goodname, "666", &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); rv = getaddrinfo(goodname_dot, "666", &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); } ATF_TC_WITHOUT_HEAD(timeout2); @@ -172,14 +167,14 @@ ATF_TC_BODY(timeout2, tc) resconf = badresolvconf2; rv = getaddrinfo(goodname, NULL, &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); rv = getaddrinfo(goodname_dot, NULL, &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); } /* @@ -197,14 +192,14 @@ ATF_TC_BODY(netdown, tc) send_error = ENETDOWN; rv = getaddrinfo(goodname, NULL, &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_NONAME, - "Expected %d (EAI_NONAME), got %d (%s)", - EAI_NONAME, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); rv = getaddrinfo(goodname_dot, NULL, &hints, &res); - ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY, - "Expected %d (EAI_ADDRFAMILY), got %d (%s)", - EAI_ADDRFAMILY, rv, gai_strerror(rv)); + ATF_REQUIRE_MSG(rv == EAI_AGAIN, + "Expected %d (EAI_AGAIN), got %d (%s)", + EAI_AGAIN, rv, gai_strerror(rv)); } /*