8597553f96
- Support an arbitrary number of search domains (#168253) - Detect and apply /etc/resolv.conf changes in libresolv (#1374239) - CVE-2015-5180: DNS stub resolver crash with crafted record type (#1251403)
218 lines
7.2 KiB
Diff
218 lines
7.2 KiB
Diff
commit 44500cbb25bc6e76723304b9ff39f875c04309f9
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Thu Apr 13 13:22:51 2017 +0200
|
|
|
|
resolv: Remove EDNS fallback [BZ #21369]
|
|
|
|
EDNS is disabled by default (so there is interoperability issue), and
|
|
the fallback code is problematic because it prevents an application
|
|
from obtaining DNSSEC data after a FORMERR response.
|
|
|
|
diff --git a/resolv/res_query.c b/resolv/res_query.c
|
|
index c3ebcbf6b50fcf4b..ec65bab04153c2ff 100644
|
|
--- a/resolv/res_query.c
|
|
+++ b/resolv/res_query.c
|
|
@@ -122,7 +122,6 @@ __libc_res_nquery(res_state statp,
|
|
HEADER *hp = (HEADER *) answer;
|
|
HEADER *hp2;
|
|
int n, use_malloc = 0;
|
|
- u_int oflags = statp->_flags;
|
|
|
|
size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE;
|
|
u_char *buf = alloca (bufsize);
|
|
@@ -145,8 +144,7 @@ __libc_res_nquery(res_state statp,
|
|
query1, bufsize);
|
|
if (n > 0)
|
|
{
|
|
- if ((oflags & RES_F_EDNS0ERR) == 0
|
|
- && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
|
|
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
|
|
{
|
|
/* Use RESOLV_EDNS_BUFFER_SIZE because the receive
|
|
buffer can be reallocated. */
|
|
@@ -170,7 +168,6 @@ __libc_res_nquery(res_state statp,
|
|
n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
|
|
NULL, query2, bufsize - nused);
|
|
if (n > 0
|
|
- && (oflags & RES_F_EDNS0ERR) == 0
|
|
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
|
|
/* Use RESOLV_EDNS_BUFFER_SIZE because the receive
|
|
buffer can be reallocated. */
|
|
@@ -187,7 +184,6 @@ __libc_res_nquery(res_state statp,
|
|
query1, bufsize);
|
|
|
|
if (n > 0
|
|
- && (oflags & RES_F_EDNS0ERR) == 0
|
|
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
|
|
{
|
|
/* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
|
|
@@ -215,16 +211,6 @@ __libc_res_nquery(res_state statp,
|
|
}
|
|
}
|
|
if (__glibc_unlikely (n <= 0)) {
|
|
- /* If the query choked with EDNS0, retry without EDNS0. */
|
|
- if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0
|
|
- && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
|
|
- statp->_flags |= RES_F_EDNS0ERR;
|
|
-#ifdef DEBUG
|
|
- if (statp->options & RES_DEBUG)
|
|
- printf(";; res_nquery: retry without EDNS0\n");
|
|
-#endif
|
|
- goto again;
|
|
- }
|
|
#ifdef DEBUG
|
|
if (statp->options & RES_DEBUG)
|
|
printf(";; res_query: mkquery failed\n");
|
|
diff --git a/resolv/res_send.c b/resolv/res_send.c
|
|
index 77d59dcc4e3b8d23..98968d6239d0c8f7 100644
|
|
--- a/resolv/res_send.c
|
|
+++ b/resolv/res_send.c
|
|
@@ -1321,26 +1321,6 @@ send_dg(res_state statp,
|
|
? *thisanssizp : *thisresplenp);
|
|
goto wait;
|
|
}
|
|
-#ifdef RES_USE_EDNS0
|
|
- if (anhp->rcode == FORMERR
|
|
- && (statp->options & RES_USE_EDNS0) != 0U) {
|
|
- /*
|
|
- * Do not retry if the server does not understand
|
|
- * EDNS0. The case has to be captured here, as
|
|
- * FORMERR packet do not carry query section, hence
|
|
- * res_queriesmatch() returns 0.
|
|
- */
|
|
- DprintQ(statp->options & RES_DEBUG,
|
|
- (stdout,
|
|
- "server rejected query with EDNS0:\n"),
|
|
- *thisansp,
|
|
- (*thisresplenp > *thisanssizp)
|
|
- ? *thisanssizp : *thisresplenp);
|
|
- /* record the error */
|
|
- statp->_flags |= RES_F_EDNS0ERR;
|
|
- return close_and_return_error (statp, resplen2);
|
|
- }
|
|
-#endif
|
|
if (!(statp->options & RES_INSECURE2)
|
|
&& (recvresp1 || !res_queriesmatch(buf, buf + buflen,
|
|
*thisansp,
|
|
diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c
|
|
index f17dbc3450f52b85..093a4f5f22aaaa51 100644
|
|
--- a/resolv/tst-resolv-edns.c
|
|
+++ b/resolv/tst-resolv-edns.c
|
|
@@ -115,8 +115,23 @@ response (const struct resolv_response_context *ctx,
|
|
{
|
|
TEST_VERIFY_EXIT (qname != NULL);
|
|
|
|
- /* The "tcp." prefix can be used to request TCP fallback. */
|
|
const char *qname_compare = qname;
|
|
+
|
|
+ /* The "formerr." prefix can be used to request a FORMERR response on the
|
|
+ first server. */
|
|
+ bool send_formerr;
|
|
+ if (strncmp ("formerr.", qname, strlen ("formerr.")) == 0)
|
|
+ {
|
|
+ send_formerr = true;
|
|
+ qname_compare = qname + strlen ("formerr.");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ send_formerr = false;
|
|
+ qname_compare = qname;
|
|
+ }
|
|
+
|
|
+ /* The "tcp." prefix can be used to request TCP fallback. */
|
|
bool force_tcp;
|
|
if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0)
|
|
{
|
|
@@ -132,14 +147,20 @@ response (const struct resolv_response_context *ctx,
|
|
else
|
|
{
|
|
support_record_failure ();
|
|
- printf ("error: unexpected QNAME: %s\n", qname);
|
|
+ printf ("error: unexpected QNAME: %s (reduced: %s)\n",
|
|
+ qname, qname_compare);
|
|
return;
|
|
}
|
|
TEST_VERIFY_EXIT (qclass == C_IN);
|
|
- struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp};
|
|
+ struct resolv_response_flags flags = { };
|
|
+ flags.tc = force_tcp && !ctx->tcp;
|
|
+ if (!flags.tc && send_formerr && ctx->server_index == 0)
|
|
+ /* Send a FORMERR for the first full response from the first
|
|
+ server. */
|
|
+ flags.rcode = 1; /* FORMERR */
|
|
resolv_response_init (b, flags);
|
|
resolv_response_add_question (b, qname, qclass, qtype);
|
|
- if (flags.tc)
|
|
+ if (flags.tc || flags.rcode != 0)
|
|
return;
|
|
|
|
if (test_verbose)
|
|
@@ -466,33 +487,42 @@ do_test (void)
|
|
for (int do_edns = 0; do_edns < 2; ++do_edns)
|
|
for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec)
|
|
for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
|
|
- {
|
|
- struct resolv_test *aux = resolv_test_start
|
|
- ((struct resolv_redirect_config)
|
|
- {
|
|
- .response_callback = response,
|
|
- });
|
|
-
|
|
- use_edns = do_edns;
|
|
- if (do_edns)
|
|
- _res.options |= RES_USE_EDNS0;
|
|
- use_dnssec = do_dnssec;
|
|
- if (do_dnssec)
|
|
- _res.options |= RES_USE_DNSSEC;
|
|
-
|
|
- char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
|
|
- if (do_tcp)
|
|
- {
|
|
- char *n = xasprintf ("tcp.%s", probe_name);
|
|
- free (probe_name);
|
|
- probe_name = n;
|
|
- }
|
|
+ for (int do_formerr = 0; do_formerr < 2; ++do_formerr)
|
|
+ {
|
|
+ struct resolv_test *aux = resolv_test_start
|
|
+ ((struct resolv_redirect_config)
|
|
+ {
|
|
+ .response_callback = response,
|
|
+ });
|
|
+
|
|
+ use_edns = do_edns;
|
|
+ if (do_edns)
|
|
+ _res.options |= RES_USE_EDNS0;
|
|
+ use_dnssec = do_dnssec;
|
|
+ if (do_dnssec)
|
|
+ _res.options |= RES_USE_DNSSEC;
|
|
+
|
|
+ char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
|
|
+ if (do_tcp)
|
|
+ {
|
|
+ char *n = xasprintf ("tcp.%s", probe_name);
|
|
+ free (probe_name);
|
|
+ probe_name = n;
|
|
+ }
|
|
+ if (do_formerr)
|
|
+ {
|
|
+ /* Send a garbage query in an attempt to trigger EDNS
|
|
+ fallback. */
|
|
+ char *n = xasprintf ("formerr.%s", probe_name);
|
|
+ gethostbyname (n);
|
|
+ free (n);
|
|
+ }
|
|
|
|
- run_test (probe_name);
|
|
+ run_test (probe_name);
|
|
|
|
- free (probe_name);
|
|
- resolv_test_end (aux);
|
|
- }
|
|
+ free (probe_name);
|
|
+ resolv_test_end (aux);
|
|
+ }
|
|
|
|
free_response_data ();
|
|
return 0;
|