Avoid duplicate DNS query if search list contains '.'
Resolves: RHEL-153056
This commit is contained in:
parent
6a5da8faa9
commit
d58e05d599
249
glibc-RHEL-153056-1.patch
Normal file
249
glibc-RHEL-153056-1.patch
Normal file
@ -0,0 +1,249 @@
|
||||
commit 8ca2fe7e96c0ccf04d32d7002d7a6d9edcb9f8ee
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
Date: Fri Oct 10 17:15:27 2025 +0200
|
||||
|
||||
resolv: Add tests for getaddrinfo returning EAI_AGAIN [BZ #16849]
|
||||
|
||||
This patch adds two tests that verify correct behavior of getaddrinfo
|
||||
when DNS resolution fails with a temporary error. Both tests ensure
|
||||
that getaddrinfo returns EAI_AGAIN in cases where no valid address can
|
||||
be resolved due to network or resolver failure.
|
||||
|
||||
* tst-getaddrinfo-eai-again.c
|
||||
Runs inside the glibc test-container without any DNS server
|
||||
configured. The test performs queries using AF_INET, AF_INET6,
|
||||
and AF_UNSPEC and verifies that getaddrinfo returns EAI_AGAIN
|
||||
when resolution fails.
|
||||
|
||||
* tst-getaddrinfo-eai-again-timeout.c
|
||||
Runs outside of the container but uses the resolv_test framework
|
||||
to simulate network failures. The test covers two failure modes:
|
||||
- No response from the server (resolv_response_drop)
|
||||
- Zero-length reply from the server
|
||||
In both cases, getaddrinfo is expected to return EAI_AGAIN.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index f3f5c260d0b7471f..cb1ff182dfdd4572 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -80,7 +80,10 @@ routines_no_fortify += \
|
||||
# routines_no_fortify
|
||||
|
||||
tests = tst-aton tst-leaks tst-inet_ntop
|
||||
-tests-container = tst-leaks2
|
||||
+tests-container += \
|
||||
+ tst-getaddrinfo-eai-again \
|
||||
+ tst-leaks2 \
|
||||
+ # tests-container
|
||||
|
||||
tests-internal += tst-inet_aton_exact
|
||||
|
||||
@@ -136,6 +139,7 @@ tests-static += tst-ns_rr_cursor
|
||||
# These tests need libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
tests += \
|
||||
+ tst-getaddrinfo-eai-again-timeout \
|
||||
tst-resolv-ai_idn \
|
||||
tst-resolv-ai_idn-latin1 \
|
||||
tst-resolv-ai_idn-nolibidn2 \
|
||||
@@ -268,6 +272,8 @@ $(objpfx)mtrace-tst-resolv-res_ninit.out: $(objpfx)tst-resolv-res_ninit.out
|
||||
|
||||
$(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-getaddrinfo-eai-again-timeout: \
|
||||
+ $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-ai_idn: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-ai_idn-latin1: \
|
||||
$(objpfx)libresolv.so $(shared-thread-library)
|
||||
diff --git a/resolv/tst-getaddrinfo-eai-again-timeout.c b/resolv/tst-getaddrinfo-eai-again-timeout.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..ec4a6563b7b5ae51
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-getaddrinfo-eai-again-timeout.c
|
||||
@@ -0,0 +1,122 @@
|
||||
+/* Test for BZ #16849. Verify that getaddrinfo correctly returns
|
||||
+ EAI_AGAIN when DNS resolution fails due to timeout or malformed
|
||||
+ responses.
|
||||
+
|
||||
+ This test uses two simulated failure modes:
|
||||
+ - The DNS server does not respond at all (resolv_response_drop).
|
||||
+ - The DNS server responds with a zero-length packet.
|
||||
+
|
||||
+ Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+
|
||||
+/* Track whether the callbacks were actually invoked. */
|
||||
+static volatile bool response_called_drop = false;
|
||||
+static volatile bool response_called_zero_len = false;
|
||||
+
|
||||
+/* Simulate a DNS server that sends a zero-length response. */
|
||||
+static void
|
||||
+response_zero_len (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ response_called_zero_len = true;
|
||||
+ /* Do nothing — zero-length reply. */
|
||||
+}
|
||||
+
|
||||
+/* Simulate a DNS server that drops the request. */
|
||||
+static void
|
||||
+response_drop (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ response_called_drop = true;
|
||||
+ resolv_response_drop (b);
|
||||
+}
|
||||
+
|
||||
+/* Query getaddrinfo for multiple families and expect EAI_AGAIN. */
|
||||
+static void
|
||||
+query_host (const char *host_name)
|
||||
+{
|
||||
+ int family[] = { AF_INET, AF_INET6, AF_UNSPEC };
|
||||
+ const char *family_names[] = { "AF_INET", "AF_INET6", "AF_UNSPEC" };
|
||||
+
|
||||
+ for (int i = 0; i < 3; i++)
|
||||
+ {
|
||||
+ struct addrinfo hints =
|
||||
+ {
|
||||
+ .ai_socktype = 0,
|
||||
+ .ai_protocol = 0,
|
||||
+ .ai_family = family[i],
|
||||
+ .ai_flags = 0,
|
||||
+ };
|
||||
+ struct addrinfo *result;
|
||||
+ int res = getaddrinfo (host_name, NULL, &hints, &result);
|
||||
+ if (res != EAI_AGAIN)
|
||||
+ FAIL_EXIT1 ("getaddrinfo (%s, %s) returned %s, expected EAI_AGAIN",
|
||||
+ host_name, family_names[i], gai_strerror (res));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Simulate DNS server dropping all queries. */
|
||||
+static void
|
||||
+test_drop (void)
|
||||
+{
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response_drop,
|
||||
+ });
|
||||
+ /* Reduce default timeout to make the test run faster. */
|
||||
+ _res.retrans = 1;
|
||||
+ _res.retry = 1;
|
||||
+ query_host ("site.example");
|
||||
+ resolv_test_end (aux);
|
||||
+}
|
||||
+
|
||||
+/* Simulate DNS server sending zero-length responses. */
|
||||
+static void
|
||||
+test_zero_len_packet (void)
|
||||
+{
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response_zero_len,
|
||||
+ });
|
||||
+ query_host ("site.example");
|
||||
+ resolv_test_end (aux);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ test_drop ();
|
||||
+ test_zero_len_packet ();
|
||||
+
|
||||
+ if (!response_called_drop)
|
||||
+ FAIL_EXIT1 ("response_drop callback was not called");
|
||||
+ if (!response_called_zero_len)
|
||||
+ FAIL_EXIT1 ("response_zero_len callback was not called");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/resolv/tst-getaddrinfo-eai-again.c b/resolv/tst-getaddrinfo-eai-again.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..21daa6c1682d1156
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-getaddrinfo-eai-again.c
|
||||
@@ -0,0 +1,56 @@
|
||||
+/* Test for BZ #16849. Verify that getaddrinfo correctly returns
|
||||
+ EAI_AGAIN error code if DNS query fails due to a network failure.
|
||||
+
|
||||
+ Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <netdb.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Query getaddrinfo with various address families and verify that
|
||||
+ it returns EAI_AGAIN when DNS resolution fails. */
|
||||
+static void
|
||||
+query_host (const char *host_name)
|
||||
+{
|
||||
+ int family[] = { AF_INET, AF_INET6, AF_UNSPEC };
|
||||
+ const char *family_names[] = { "AF_INET", "AF_INET6", "AF_UNSPEC" };
|
||||
+
|
||||
+ for (int i = 0; i < 3; i++)
|
||||
+ {
|
||||
+ struct addrinfo hints =
|
||||
+ {
|
||||
+ .ai_socktype = 0,
|
||||
+ .ai_protocol = 0,
|
||||
+ .ai_family = family[i],
|
||||
+ .ai_flags = 0,
|
||||
+ };
|
||||
+ struct addrinfo *result;
|
||||
+ int res = getaddrinfo (host_name, NULL, &hints, &result);
|
||||
+ if (res != EAI_AGAIN)
|
||||
+ FAIL_EXIT1 ("getaddrinfo (%s, %s) returned %s, expected EAI_AGAIN",
|
||||
+ host_name, family_names[i], gai_strerror (res));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ query_host ("site.example");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
258
glibc-RHEL-153056-2.patch
Normal file
258
glibc-RHEL-153056-2.patch
Normal file
@ -0,0 +1,258 @@
|
||||
commit c995686e2cbe2a3ab2a11877a61c14a2e1fc35cb
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Mar 3 18:48:47 2026 +0100
|
||||
|
||||
support: no_override_resolv_conf_search flag for resolver test framework
|
||||
|
||||
It is required to test "search ." in /etc/resolv.conf files. The
|
||||
default is to override the search path isolate from unexpected
|
||||
settings in the test execution environment.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
resolv/Makefile
|
||||
(tst-resolv-invalid-cname dependencies were added
|
||||
in a different place on the 2.34 upstream branch)
|
||||
|
||||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||||
index cb1ff182dfdd4572..116ab6a1574eb1ff 100644
|
||||
--- a/resolv/Makefile
|
||||
+++ b/resolv/Makefile
|
||||
@@ -83,6 +83,7 @@ tests = tst-aton tst-leaks tst-inet_ntop
|
||||
tests-container += \
|
||||
tst-getaddrinfo-eai-again \
|
||||
tst-leaks2 \
|
||||
+ tst-resolv-no-search \
|
||||
# tests-container
|
||||
|
||||
tests-internal += tst-inet_aton_exact
|
||||
@@ -294,10 +295,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
-$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
-$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-no-search: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
+$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
diff --git a/resolv/tst-resolv-no-search.c b/resolv/tst-resolv-no-search.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..29701d4772507507
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-no-search.c
|
||||
@@ -0,0 +1,174 @@
|
||||
+/* Test using "search ." in /etc/resolv.conf.
|
||||
+ Copyright (C) 2026 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <netdb.h>
|
||||
+#include <resolv.h>
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/check_nss.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/resolv_test.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* Check that plain res_init loads the configuration as expected. */
|
||||
+static void
|
||||
+test_res_init (void *ignored)
|
||||
+{
|
||||
+ res_init ();
|
||||
+ TEST_COMPARE_STRING (_res.dnsrch[0], ".");
|
||||
+ TEST_COMPARE_STRING (_res.dnsrch[1], NULL);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+response (const struct resolv_response_context *ctx,
|
||||
+ struct resolv_response_builder *b,
|
||||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
+{
|
||||
+ TEST_VERIFY_EXIT (qclass == C_IN);
|
||||
+ TEST_COMPARE (ctx->server_index, 0);
|
||||
+
|
||||
+ if (strncmp (qname, "does-not-exist", strlen ("does-not-exist")) == 0)
|
||||
+ {
|
||||
+ resolv_response_init (b, (struct resolv_response_flags)
|
||||
+ { .rcode = ns_r_nxdomain });
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ resolv_response_init (b, (struct resolv_response_flags) { });
|
||||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||||
+ resolv_response_section (b, ns_s_an);
|
||||
+
|
||||
+ resolv_response_open_record (b, qname, qclass, qtype, 0);
|
||||
+ switch (qtype)
|
||||
+ {
|
||||
+ case T_A:
|
||||
+ {
|
||||
+ char ipv4[4] = {192, 0, 2, 17};
|
||||
+ resolv_response_add_data (b, &ipv4, sizeof (ipv4));
|
||||
+ }
|
||||
+ break;
|
||||
+ case T_AAAA:
|
||||
+ {
|
||||
+ char ipv6[16]
|
||||
+ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
+ resolv_response_add_data (b, &ipv6, sizeof (ipv6));
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ resolv_response_close_record (b);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+check_h (const char *name, int family, const char *expected)
|
||||
+{
|
||||
+ if (family == AF_INET)
|
||||
+ {
|
||||
+ char *query = xasprintf ("gethostbyname (\"%s\")", name);
|
||||
+ check_hostent (query, gethostbyname (name), expected);
|
||||
+ free (query);
|
||||
+ }
|
||||
+ {
|
||||
+ char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
|
||||
+ check_hostent (query, gethostbyname2 (name, family), expected);
|
||||
+ free (query);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+check_ai (const char *name, int family, const char *expected)
|
||||
+{
|
||||
+ struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM, };
|
||||
+ struct addrinfo *ai;
|
||||
+ char *query = xasprintf ("%s:80 [%d]", name, hints.ai_family);
|
||||
+ int ret = getaddrinfo (name, "80", &hints, &ai);
|
||||
+ check_addrinfo (query, ai, ret, expected);
|
||||
+ if (ret == 0)
|
||||
+ freeaddrinfo (ai);
|
||||
+ free (query);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ support_isolate_in_subprocess (test_res_init, NULL);
|
||||
+
|
||||
+ struct resolv_test *aux = resolv_test_start
|
||||
+ ((struct resolv_redirect_config)
|
||||
+ {
|
||||
+ .response_callback = response,
|
||||
+ .no_override_resolv_conf_search = true,
|
||||
+ });
|
||||
+
|
||||
+ check_h ("www.example", AF_INET,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 192.0.2.17\n");
|
||||
+ check_h ("www.example", AF_INET6,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 2001:db8::1\n");
|
||||
+ check_ai ("www.example", AF_UNSPEC,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n"
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_ai ("www.example", AF_INET,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n");
|
||||
+ check_ai ("www.example", AF_INET6,
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_h ("does-not-exist.example", AF_INET,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_h ("does-not-exist.example", AF_INET6,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_ai ("does-not-exist.example", AF_UNSPEC,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example", AF_INET,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example", AF_INET6,
|
||||
+ "error: Name or service not known\n");
|
||||
+
|
||||
+ /* With trailing dot. */
|
||||
+ check_h ("www.example.", AF_INET,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 192.0.2.17\n");
|
||||
+ check_h ("www.example.", AF_INET6,
|
||||
+ "name: www.example\n"
|
||||
+ "address: 2001:db8::1\n");
|
||||
+ check_ai ("www.example.", AF_UNSPEC,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n"
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_ai ("www.example.", AF_INET,
|
||||
+ "address: STREAM/TCP 192.0.2.17 80\n");
|
||||
+ check_ai ("www.example.", AF_INET6,
|
||||
+ "address: STREAM/TCP 2001:db8::1 80\n");
|
||||
+ check_h ("does-not-exist.example.", AF_INET,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_h ("does-not-exist.example.", AF_INET6,
|
||||
+ "error: HOST_NOT_FOUND\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_UNSPEC,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_INET,
|
||||
+ "error: Name or service not known\n");
|
||||
+ check_ai ("does-not-exist.example.", AF_INET6,
|
||||
+ "error: Name or service not known\n");
|
||||
+
|
||||
+ resolv_test_end (aux);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/resolv/tst-resolv-no-search.root/etc/resolv.conf b/resolv/tst-resolv-no-search.root/etc/resolv.conf
|
||||
new file mode 100644
|
||||
index 0000000000000000..5ace648869a31edb
|
||||
--- /dev/null
|
||||
+++ b/resolv/tst-resolv-no-search.root/etc/resolv.conf
|
||||
@@ -0,0 +1 @@
|
||||
+search .
|
||||
diff --git a/support/resolv_test.c b/support/resolv_test.c
|
||||
index 73d20572f3b843c7..7272334b78fc85f1 100644
|
||||
--- a/support/resolv_test.c
|
||||
+++ b/support/resolv_test.c
|
||||
@@ -1098,6 +1098,9 @@ resolv_test_init (void)
|
||||
static void
|
||||
set_search_path (struct resolv_redirect_config config)
|
||||
{
|
||||
+ if (config.no_override_resolv_conf_search)
|
||||
+ return;
|
||||
+
|
||||
memset (_res.defdname, 0, sizeof (_res.defdname));
|
||||
memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
|
||||
|
||||
diff --git a/support/resolv_test.h b/support/resolv_test.h
|
||||
index ddf967449e398710..e0a17ebf23c34880 100644
|
||||
--- a/support/resolv_test.h
|
||||
+++ b/support/resolv_test.h
|
||||
@@ -96,6 +96,9 @@ struct resolv_redirect_config
|
||||
domain name as well. */
|
||||
const char *search[7];
|
||||
|
||||
+ /* If true, do not override the search path loaded from /etc/resolv.conf. */
|
||||
+ bool no_override_resolv_conf_search;
|
||||
+
|
||||
/* Number of servers to activate in resolv. 0 means the default,
|
||||
resolv_max_test_servers. */
|
||||
int nscount;
|
||||
98
glibc-RHEL-153056-3.patch
Normal file
98
glibc-RHEL-153056-3.patch
Normal file
@ -0,0 +1,98 @@
|
||||
commit dc9ca785a5fe2059a9b04ab336520d463d9a715b
|
||||
Author: Carlos Peón Costa <carlospeon@gmail.com>
|
||||
Date: Tue Mar 3 18:48:47 2026 +0100
|
||||
|
||||
resolv: Avoid duplicate query if search list contains '.' (bug 33804)
|
||||
|
||||
Co-authored-by: Florian Weimer <fweimer@redhat.com>
|
||||
Signed-off-by: Florian Weimer <fweimer@redhat.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/resolv/res_query.c b/resolv/res_query.c
|
||||
index 1d2c81737bc889c9..bae7b3c23d778a7d 100644
|
||||
--- a/resolv/res_query.c
|
||||
+++ b/resolv/res_query.c
|
||||
@@ -358,7 +358,7 @@ __res_context_search (struct resolv_context *ctx,
|
||||
char tmp[NS_MAXDNAME];
|
||||
u_int dots;
|
||||
int trailing_dot, ret, saved_herrno;
|
||||
- int got_nodata = 0, got_servfail = 0, root_on_list = 0;
|
||||
+ int got_nodata = 0, got_servfail = 0;
|
||||
int tried_as_is = 0;
|
||||
int searched = 0;
|
||||
|
||||
@@ -437,8 +437,11 @@ __res_context_search (struct resolv_context *ctx,
|
||||
domain. */
|
||||
if (dname[0] == '.')
|
||||
dname++;
|
||||
- if (dname[0] == '\0')
|
||||
- root_on_list++;
|
||||
+ if (dname[0] == '\0') {
|
||||
+ if (tried_as_is)
|
||||
+ continue;
|
||||
+ tried_as_is++;
|
||||
+ }
|
||||
|
||||
ret = __res_context_querydomain
|
||||
(ctx, name, dname, class, type,
|
||||
@@ -510,7 +513,7 @@ __res_context_search (struct resolv_context *ctx,
|
||||
* unless RES_NOTLDQUERY is set and there were no dots.
|
||||
*/
|
||||
if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
|
||||
- && !(tried_as_is || root_on_list)) {
|
||||
+ && !tried_as_is) {
|
||||
ret = __res_context_querydomain
|
||||
(ctx, name, NULL, class, type,
|
||||
answer, anslen, answerp, answerp2, nanswerp2,
|
||||
diff --git a/resolv/tst-resolv-no-search.c b/resolv/tst-resolv-no-search.c
|
||||
index 29701d4772507507..7d78d4044cf50e48 100644
|
||||
--- a/resolv/tst-resolv-no-search.c
|
||||
+++ b/resolv/tst-resolv-no-search.c
|
||||
@@ -27,6 +27,11 @@
|
||||
#include <support/resolv_test.h>
|
||||
#include <support/support.h>
|
||||
|
||||
+/* Used to check for duplicated queries (bug 33804). POSIX does not
|
||||
+ explicitly say that socket calls (as used in the resolver tests)
|
||||
+ provide synchronization. */
|
||||
+static _Atomic unsigned int query_count;
|
||||
+
|
||||
/* Check that plain res_init loads the configuration as expected. */
|
||||
static void
|
||||
test_res_init (void *ignored)
|
||||
@@ -43,6 +48,7 @@ response (const struct resolv_response_context *ctx,
|
||||
{
|
||||
TEST_VERIFY_EXIT (qclass == C_IN);
|
||||
TEST_COMPARE (ctx->server_index, 0);
|
||||
+ ++query_count;
|
||||
|
||||
if (strncmp (qname, "does-not-exist", strlen ("does-not-exist")) == 0)
|
||||
{
|
||||
@@ -82,12 +88,16 @@ check_h (const char *name, int family, const char *expected)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
char *query = xasprintf ("gethostbyname (\"%s\")", name);
|
||||
+ query_count = 0;
|
||||
check_hostent (query, gethostbyname (name), expected);
|
||||
+ TEST_COMPARE (query_count, 1);
|
||||
free (query);
|
||||
}
|
||||
{
|
||||
char *query = xasprintf ("gethostbyname2 (\"%s\", %d)", name, family);
|
||||
+ query_count = 0;
|
||||
check_hostent (query, gethostbyname2 (name, family), expected);
|
||||
+ TEST_COMPARE (query_count, 1);
|
||||
free (query);
|
||||
}
|
||||
}
|
||||
@@ -98,8 +108,10 @@ check_ai (const char *name, int family, const char *expected)
|
||||
struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM, };
|
||||
struct addrinfo *ai;
|
||||
char *query = xasprintf ("%s:80 [%d]", name, hints.ai_family);
|
||||
+ query_count = 0;
|
||||
int ret = getaddrinfo (name, "80", &hints, &ai);
|
||||
check_addrinfo (query, ai, ret, expected);
|
||||
+ TEST_COMPARE (query_count, family == AF_UNSPEC ? 2 : 1);
|
||||
if (ret == 0)
|
||||
freeaddrinfo (ai);
|
||||
free (query);
|
||||
Loading…
Reference in New Issue
Block a user