diff --git a/glibc-RHEL-50662-1.patch b/glibc-RHEL-50662-1.patch new file mode 100644 index 0000000..3e429ae --- /dev/null +++ b/glibc-RHEL-50662-1.patch @@ -0,0 +1,58 @@ +commit 868ab8923a2ec977faafec97ecafac0c3159c1b2 +Author: Florian Weimer +Date: Thu Jun 13 18:56:30 2024 +0200 + + resolv: Track single-request fallback via _res._flags (bug 31476) + + This avoids changing _res.options, which inteferes with change + detection as part of automatic reloading of /etc/resolv.conf. + + Reviewed-by: DJ Delorie + +diff -Nrup a/resolv/res_send.c b/resolv/res_send.c +--- a/resolv/res_send.c 2024-10-20 19:06:22.807194569 -0400 ++++ b/resolv/res_send.c 2024-10-20 19:05:56.917074062 -0400 +@@ -947,9 +947,11 @@ send_dg(res_state statp, + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; +- bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0; +- bool single_request = (((statp->options & RES_SNGLKUP) != 0) +- | single_request_reopen); ++ bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP) ++ || (statp->_flags & RES_F_SNGLKUPREOP)); ++ bool single_request = ((statp->options & RES_SNGLKUP) ++ || (statp->_flags & RES_F_SNGLKUP) ++ || single_request_reopen); + int save_gotsomewhere = *gotsomewhere; + + int retval; +@@ -1006,14 +1008,14 @@ send_dg(res_state statp, + have received the first answer. */ + if (!single_request) + { +- statp->options |= RES_SNGLKUP; ++ statp->_flags |= RES_F_SNGLKUP; + single_request = true; + *gotsomewhere = save_gotsomewhere; + goto retry; + } + else if (!single_request_reopen) + { +- statp->options |= RES_SNGLKUPREOP; ++ statp->_flags |= RES_F_SNGLKUPREOP; + single_request_reopen = true; + *gotsomewhere = save_gotsomewhere; + __res_iclose (statp, false); +diff -Nrup a/resolv/resolv-internal.h b/resolv/resolv-internal.h +--- a/resolv/resolv-internal.h 2024-10-20 19:06:22.807194569 -0400 ++++ b/resolv/resolv-internal.h 2024-10-20 19:07:31.700515224 -0400 +@@ -26,6 +26,8 @@ + #define RES_F_VC 0x00000001 /* Socket is TCP. */ + #define RES_F_CONN 0x00000002 /* Socket is connected. */ + #define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors. */ ++#define RES_F_SNGLKUP 0x00200000 /* Private version of RES_SNGLKUP. */ ++#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP. */ + + /* Legacy function. This needs to be removed once all NSS modules + have been adjusted. */ diff --git a/glibc-RHEL-50662-2.patch b/glibc-RHEL-50662-2.patch new file mode 100644 index 0000000..2f35180 --- /dev/null +++ b/glibc-RHEL-50662-2.patch @@ -0,0 +1,200 @@ +commit 691a3b2e9bfaba842e46a5ccb7f5e6ea144c3ade +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Allow short error responses to match any query (bug 31890) + + Reviewed-by: DJ Delorie + +diff --git a/resolv/Makefile b/resolv/Makefile +index 5f44f5896b..d927e337d9 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -106,6 +106,7 @@ tests += \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-short-response \ + tst-resolv-trailing \ + + # This test calls __res_context_send directly, which is not exported +@@ -299,6 +300,8 @@ $(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) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-threads: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \ +diff --git a/resolv/res_send.c b/resolv/res_send.c +index ea7cf192b2..572e72c32f 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1199,19 +1199,30 @@ send_dg(res_state statp, + } + + /* Check for the correct header layout and a matching +- question. */ ++ question. Some recursive resolvers send REFUSED ++ without copying back the question section ++ (producing a response that is only HFIXEDSZ bytes ++ long). Skip query matching in this case. */ ++ bool thisansp_error = (anhp->rcode == SERVFAIL || ++ anhp->rcode == NOTIMP || ++ anhp->rcode == REFUSED); ++ bool skip_query_match = (*thisresplenp == HFIXEDSZ ++ && ntohs (anhp->qdcount) == 0 ++ && thisansp_error); + int matching_query = 0; /* Default to no matching query. */ + if (!recvresp1 + && anhp->id == hp->id +- && __libc_res_queriesmatch (buf, buf + buflen, +- *thisansp, +- *thisansp + *thisanssizp)) ++ && (skip_query_match ++ || __libc_res_queriesmatch (buf, buf + buflen, ++ *thisansp, ++ *thisansp + *thisanssizp))) + matching_query = 1; + if (!recvresp2 + && anhp->id == hp2->id +- && __libc_res_queriesmatch (buf2, buf2 + buflen2, +- *thisansp, +- *thisansp + *thisanssizp)) ++ && (skip_query_match ++ || __libc_res_queriesmatch (buf2, buf2 + buflen2, ++ *thisansp, ++ *thisansp + *thisanssizp))) + matching_query = 2; + if (matching_query == 0) + /* Spurious UDP packet. Drop it and continue +@@ -1221,9 +1232,7 @@ send_dg(res_state statp, + goto wait; + } + +- if (anhp->rcode == SERVFAIL || +- anhp->rcode == NOTIMP || +- anhp->rcode == REFUSED) { ++ if (thisansp_error) { + next_ns: + if (recvresp1 || (buf2 != NULL && recvresp2)) { + *resplen2 = 0; +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +new file mode 100644 +index 0000000000..cf1e39876f +--- /dev/null ++++ b/resolv/tst-resolv-short-response.c +@@ -0,0 +1,112 @@ ++/* Test for spurious timeouts with short 12-byte responses (bug 31890). ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* The rcode in the initial response. */ ++static volatile int rcode; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ switch (ctx->server_index) ++ { ++ case 0: ++ /* First server times out. */ ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ break; ++ case 1: ++ /* Second server sends reply. */ ++ 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; ++ default: ++ FAIL_EXIT1 ("unexpected TYPE%d query", qtype); ++ } ++ resolv_response_close_record (b); ++ break; ++ default: ++ FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index); ++ } ++} ++ ++static void ++check_one (void) ++{ ++ ++ /* The buggy 1-second query timeout results in 30 seconds of delay, ++ which triggers a test timeout failure. */ ++ for (int i = 0; i < 10; ++i) ++ { ++ check_hostent ("www.example", gethostbyname ("www.example"), ++ "name: www.example\n" ++ "address: 192.0.2.17\n"); ++ check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), ++ "name: www.example\n" ++ "address: 2001:db8::1\n"); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ _res.options |= RES_SNGLKUP; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ ++ resolv_test_end (aux); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-50662-3.patch b/glibc-RHEL-50662-3.patch new file mode 100644 index 0000000..6524bce --- /dev/null +++ b/glibc-RHEL-50662-3.patch @@ -0,0 +1,208 @@ +commit af625987d619388a100b153520d3ee308bda9889 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Do not wait for non-existing second DNS response after error (bug 30081) + + In single-request mode, there is no second response after an error + because the second query has not been sent yet. Waiting for it + introduces an unnecessary timeout. + + Reviewed-by: DJ Delorie + +diff --git a/resolv/Makefile b/resolv/Makefile +index d927e337d9..abff7fc007 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -106,6 +106,7 @@ tests += \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ ++ tst-resolv-semi-failure \ + tst-resolv-short-response \ + tst-resolv-trailing \ + +@@ -300,6 +301,8 @@ $(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) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-semi-failure: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 572e72c32f..9c77613f37 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1238,7 +1238,7 @@ send_dg(res_state statp, + *resplen2 = 0; + return resplen; + } +- if (buf2 != NULL) ++ if (buf2 != NULL && !single_request) + { + /* No data from the first reply. */ + resplen = 0; +diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +new file mode 100644 +index 0000000000..aa9798b5a7 +--- /dev/null ++++ b/resolv/tst-resolv-semi-failure.c +@@ -0,0 +1,133 @@ ++/* Test parallel failure/success responses (bug 30081). ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* The rcode in the initial response. */ ++static volatile int rcode; ++ ++/* Whether to fail the initial A query (!fail_aaaa) or the initial ++ AAAA query (fail_aaaa). */ ++static volatile bool fail_aaaa; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* Handle the failing query. */ ++ if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0) ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ return; ++ } ++ ++ /* Otherwise produce a response. */ ++ 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; ++ default: ++ FAIL_EXIT1 ("unexpected TYPE%d query", qtype); ++ } ++ resolv_response_close_record (b); ++} ++ ++static void ++check_one (void) ++{ ++ ++ /* The buggy 1-second query timeout results in 30 seconds of delay, ++ which triggers are test timeout failure. */ ++ for (int i = 0; i < 30; ++i) ++ { ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ const char *expected; ++ if (ret == 0 && ai->ai_next != NULL) ++ expected = ("address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ else ++ /* Only one response because the AAAA lookup failure is ++ treated as an ignoreable error. */ ++ expected = "address: STREAM/TCP 192.0.2.17 80\n"; ++ check_addrinfo ("www.example", ai, ret, expected); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; ++ ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; ++ ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); ++ ++ rcode = 4; /* NOTIMP. */ ++ check_one (); ++ ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } ++ ++ resolv_test_end (aux); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +index cf1e39876f..be354ae1c7 100644 +--- a/resolv/tst-resolv-short-response.c ++++ b/resolv/tst-resolv-short-response.c +@@ -81,6 +81,18 @@ check_one (void) + check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6), + "name: www.example\n" + "address: 2001:db8::1\n"); ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo ("www.example", "80", &hints, &ai); ++ check_addrinfo ("www.example", ai, ret, ++ "address: STREAM/TCP 192.0.2.17 80\n" ++ "address: STREAM/TCP 2001:db8::1 80\n"); ++ if (ret == 0) ++ freeaddrinfo (ai); + } + } + diff --git a/glibc-RHEL-50662-4.patch b/glibc-RHEL-50662-4.patch new file mode 100644 index 0000000..db465d8 --- /dev/null +++ b/glibc-RHEL-50662-4.patch @@ -0,0 +1,83 @@ +commit 95f61610f3e481d191b6184432342236fd59186d +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Support clearing option flags with a “-” prefix (bug 14799) + + I think using a “-” prefix is less confusing than introducing + double-negation construct (“no-no-tld-query”). + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS + (Dropped) + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 263263d474..243532b3ad 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -682,27 +682,29 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { + char str[22]; + uint8_t len; +- uint8_t clear; + unsigned long int flag; + } options[] = { + #define STRnLEN(str) str, sizeof (str) - 1 +- { STRnLEN ("rotate"), 0, RES_ROTATE }, +- { STRnLEN ("edns0"), 0, RES_USE_EDNS0 }, +- { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP }, +- { STRnLEN ("single-request"), 0, RES_SNGLKUP }, +- { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, +- { STRnLEN ("no-reload"), 0, RES_NORELOAD }, +- { STRnLEN ("use-vc"), 0, RES_USEVC }, +- { STRnLEN ("trust-ad"), 0, RES_TRUSTAD }, +- { STRnLEN ("no-aaaa"), 0, RES_NOAAAA }, ++ { STRnLEN ("rotate"), RES_ROTATE }, ++ { STRnLEN ("edns0"), RES_USE_EDNS0 }, ++ { STRnLEN ("single-request-reopen"), RES_SNGLKUPREOP }, ++ { STRnLEN ("single-request"), RES_SNGLKUP }, ++ { STRnLEN ("no_tld_query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-tld-query"), RES_NOTLDQUERY }, ++ { STRnLEN ("no-reload"), RES_NORELOAD }, ++ { STRnLEN ("use-vc"), RES_USEVC }, ++ { STRnLEN ("trust-ad"), RES_TRUSTAD }, ++ { STRnLEN ("no-aaaa"), RES_NOAAAA }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) ++ bool negate_option = *cp == '-'; ++ if (negate_option) ++ ++cp; + for (int i = 0; i < noptions; ++i) + if (strncmp (cp, options[i].str, options[i].len) == 0) + { +- if (options[i].clear) +- parser->template.options &= options[i].flag; ++ if (negate_option) ++ parser->template.options &= ~options[i].flag; + else + parser->template.options |= options[i].flag; + break; +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index 6bef62cde2..d3a19eb305 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -679,6 +679,16 @@ struct test_case test_cases[] = + "; nameserver[0]: [192.0.2.1]:53\n", + .res_options = "attempts:5 ndots:3 edns0 ", + }, ++ {.name = "RES_OPTIONS can clear flags", ++ .conf = "options ndots:2 use-vc no-aaaa edns0\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options ndots:3 use-vc\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n", ++ .res_options = "ndots:3 -edns0 -no-aaaa", ++ }, + {.name = "many search list entries (bug 19569)", + .conf = "nameserver 192.0.2.1\n" + "search corp.example.com support.example.com" diff --git a/glibc-RHEL-50662-5.patch b/glibc-RHEL-50662-5.patch new file mode 100644 index 0000000..c3722c2 --- /dev/null +++ b/glibc-RHEL-50662-5.patch @@ -0,0 +1,208 @@ +commit 765325951ac5c7d072278c9424930b29657e9758 +Author: Florian Weimer +Date: Wed Jul 24 12:06:47 2024 +0200 + + resolv: Implement strict-error stub resolver option (bug 27929) + + For now, do not enable this mode by default due to the potential + impact on compatibility with existing deployments. + + Reviewed-by: DJ Delorie + +Conflicts: + NEWS + (Dropped) + +diff --git a/resolv/res_init.c b/resolv/res_init.c +index 243532b3ad..b838dc7064 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -695,6 +695,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { STRnLEN ("use-vc"), RES_USEVC }, + { STRnLEN ("trust-ad"), RES_TRUSTAD }, + { STRnLEN ("no-aaaa"), RES_NOAAAA }, ++ { STRnLEN ("strict-error"), RES_STRICTERR }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) + bool negate_option = *cp == '-'; +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 9c77613f37..9a284ed44a 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -1234,21 +1234,38 @@ send_dg(res_state statp, + + if (thisansp_error) { + next_ns: +- if (recvresp1 || (buf2 != NULL && recvresp2)) { +- *resplen2 = 0; +- return resplen; +- } +- if (buf2 != NULL && !single_request) ++ /* Outside of strict-error mode, use the first ++ response even if the second response is an ++ error. This allows parallel resolution to ++ succeed even if the recursive resolver ++ always answers with SERVFAIL for AAAA ++ queries (which still happens in practice ++ unfortunately). ++ ++ In strict-error mode, always switch to the ++ next server and try to get a response from ++ there. */ ++ if ((statp->options & RES_STRICTERR) == 0) + { +- /* No data from the first reply. */ +- resplen = 0; +- /* We are waiting for a possible second reply. */ +- if (matching_query == 1) +- recvresp1 = 1; +- else +- recvresp2 = 1; +- +- goto wait; ++ if (recvresp1 || (buf2 != NULL && recvresp2)) ++ { ++ *resplen2 = 0; ++ return resplen; ++ } ++ ++ if (buf2 != NULL && !single_request) ++ { ++ /* No data from the first reply. */ ++ resplen = 0; ++ /* We are waiting for a possible ++ second reply. */ ++ if (matching_query == 1) ++ recvresp1 = 1; ++ else ++ recvresp2 = 1; ++ ++ goto wait; ++ } + } + + /* don't retry if called from dig */ +diff --git a/resolv/resolv.h b/resolv/resolv.h +index f40d6c58ce..b8a0f66a5f 100644 +--- a/resolv/resolv.h ++++ b/resolv/resolv.h +@@ -133,6 +133,7 @@ struct res_sym { + #define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */ + #define RES_TRUSTAD 0x04000000 /* Request AD bit, keep it in responses. */ + #define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */ ++#define RES_STRICTERR 0x10000000 /* Report more DNS errors as errors. */ + + #define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH) + +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index d3a19eb305..e41bcebd9d 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -129,6 +129,7 @@ print_resp (FILE *fp, res_state resp) + print_option_flag (fp, &options, RES_NORELOAD, "no-reload"); + print_option_flag (fp, &options, RES_TRUSTAD, "trust-ad"); + print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa"); ++ print_option_flag (fp, &options, RES_STRICTERR, "strict-error"); + fputc ('\n', fp); + if (options != 0) + fprintf (fp, "; error: unresolved option bits: 0x%x\n", options); +@@ -741,6 +742,15 @@ struct test_case test_cases[] = + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, ++ {.name = "strict-error flag", ++ .conf = "options strict-error\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options strict-error\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, + { NULL } + }; + +diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c +index aa9798b5a7..b7681210f4 100644 +--- a/resolv/tst-resolv-semi-failure.c ++++ b/resolv/tst-resolv-semi-failure.c +@@ -67,6 +67,9 @@ response (const struct resolv_response_context *ctx, + resolv_response_close_record (b); + } + ++/* Set to 1 if strict error checking is enabled. */ ++static int do_strict_error; ++ + static void + check_one (void) + { +@@ -83,7 +86,10 @@ check_one (void) + struct addrinfo *ai; + int ret = getaddrinfo ("www.example", "80", &hints, &ai); + const char *expected; +- if (ret == 0 && ai->ai_next != NULL) ++ /* In strict-error mode, a switch to the second name server ++ happens, and both responses are received, so a single ++ response is a bug. */ ++ if (do_strict_error || (ret == 0 && ai->ai_next != NULL)) + expected = ("address: STREAM/TCP 192.0.2.17 80\n" + "address: STREAM/TCP 2001:db8::1 80\n"); + else +@@ -99,33 +105,36 @@ check_one (void) + static int + do_test (void) + { +- for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) +- { +- struct resolv_test *aux = resolv_test_start +- ((struct resolv_redirect_config) +- { +- .response_callback = response, +- }); ++ for (do_strict_error = 0; do_strict_error < 2; ++do_strict_error) ++ for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); + +- if (do_single_lookup) +- _res.options |= RES_SNGLKUP; ++ if (do_strict_error) ++ _res.options |= RES_STRICTERR; ++ if (do_single_lookup) ++ _res.options |= RES_SNGLKUP; + +- for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) +- { +- fail_aaaa = do_fail_aaaa; ++ for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa) ++ { ++ fail_aaaa = do_fail_aaaa; + +- rcode = 2; /* SERVFAIL. */ +- check_one (); ++ rcode = 2; /* SERVFAIL. */ ++ check_one (); + +- rcode = 4; /* NOTIMP. */ +- check_one (); ++ rcode = 4; /* NOTIMP. */ ++ check_one (); + +- rcode = 5; /* REFUSED. */ +- check_one (); +- } ++ rcode = 5; /* REFUSED. */ ++ check_one (); ++ } + +- resolv_test_end (aux); +- } ++ resolv_test_end (aux); ++ } + + return 0; + } diff --git a/glibc-RHEL-50662-6.patch b/glibc-RHEL-50662-6.patch new file mode 100644 index 0000000..d14093c --- /dev/null +++ b/glibc-RHEL-50662-6.patch @@ -0,0 +1,28 @@ +commit ec119972cb2598c04ec7d4219e20506006836f64 +Author: Florian Weimer +Date: Thu Aug 1 10:46:10 2024 +0200 + + resolv: Fix tst-resolv-short-response for older GCC (bug 32042) + + Previous GCC versions do not support the C23 change that + allows labels on declarations. + + Reviewed-by: Adhemerval Zanella + +diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c +index be354ae1c7..9b06b0c176 100644 +--- a/resolv/tst-resolv-short-response.c ++++ b/resolv/tst-resolv-short-response.c +@@ -33,8 +33,10 @@ response (const struct resolv_response_context *ctx, + { + case 0: + /* First server times out. */ +- struct resolv_response_flags flags = {.rcode = rcode}; +- resolv_response_init (b, flags); ++ { ++ struct resolv_response_flags flags = {.rcode = rcode}; ++ resolv_response_init (b, flags); ++ } + break; + case 1: + /* Second server sends reply. */ diff --git a/glibc.spec b/glibc.spec index e4a15ad..628227b 100644 --- a/glibc.spec +++ b/glibc.spec @@ -157,7 +157,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 134%{?dist} +Release: 135%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -903,6 +903,12 @@ Patch664: glibc-RHEL-50545-11.patch Patch665: glibc-RHEL-50545-12.patch Patch666: glibc-RHEL-50545-13.patch Patch667: glibc-RHEL-50545-14.patch +Patch668: glibc-RHEL-50662-1.patch +Patch669: glibc-RHEL-50662-2.patch +Patch670: glibc-RHEL-50662-3.patch +Patch671: glibc-RHEL-50662-4.patch +Patch672: glibc-RHEL-50662-5.patch +Patch673: glibc-RHEL-50662-6.patch ############################################################################## # Continued list of core "glibc" package information: @@ -3062,6 +3068,10 @@ update_gconv_modules_cache () %endif %changelog +* Wed Nov 06 2024 Patsy Griffin - 2.34-135 +- Support clearing options in /etc/resolv.conf, RES_OPTIONS with a - prefix +- Introduce the strict-error/RES_STRICTERR stub resolver option (RHEL-50662) + * Wed Oct 23 2024 DJ Delorie - 2.34-134 - Test Implementation to verify mkstemp behavior, with FUSE support (RHEL-50545)