summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-11-05 17:00:20 +0100
committerLennart Poettering <lennart@poettering.net>2021-02-15 21:59:05 +0100
commit5e8bc852d538544a2285ced429e3a805f13ea260 (patch)
tree9a1035166393b2fa79fc4da3fad48ba3a394aba3 /src
parentc78735eb795f1377d8d08bc57401efe742d9ec19 (diff)
downloadsystemd-5e8bc852d538544a2285ced429e3a805f13ea260.tar.gz
resolved: don't redundantly switch DNS servers because of transaction failures
When a transaction fails and we decide to switch DNS servers, don#t do so unconditionally. Check if the current DNS server is still the same as when the transaction was initiated. And if not, do not do anything. That should reduce the number of redundant DNS server switches if many parallel transactions fail simultaneously (which is pretty likely if DNSSEC is on). Fixes: #17040
Diffstat (limited to 'src')
-rw-r--r--src/resolve/resolved-dns-scope.c9
-rw-r--r--src/resolve/resolved-dns-scope.h2
-rw-r--r--src/resolve/resolved-dns-server.c16
-rw-r--r--src/resolve/resolved-dns-server.h2
-rw-r--r--src/resolve/resolved-dns-transaction.c6
-rw-r--r--src/resolve/resolved-link.c14
-rw-r--r--src/resolve/resolved-link.h2
7 files changed, 32 insertions, 19 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 245f9bfce8..c962af9aba 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -153,16 +153,19 @@ unsigned dns_scope_get_n_dns_servers(DnsScope *s) {
return n;
}
-void dns_scope_next_dns_server(DnsScope *s) {
+void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) {
assert(s);
if (s->protocol != DNS_PROTOCOL_DNS)
return;
+ /* Changes to the next DNS server in the list. If 'if_current' is passed will do so only if the
+ * current DNS server still matches it. */
+
if (s->link)
- link_next_dns_server(s->link);
+ link_next_dns_server(s->link, if_current);
else
- manager_next_dns_server(s->manager);
+ manager_next_dns_server(s->manager, if_current);
}
void dns_scope_packet_received(DnsScope *s, usec_t rtt) {
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 532f4d6b80..7e863d3f66 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -80,7 +80,7 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key);
DnsServer *dns_scope_get_dns_server(DnsScope *s);
unsigned dns_scope_get_n_dns_servers(DnsScope *s);
-void dns_scope_next_dns_server(DnsScope *s);
+void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current);
int dns_scope_llmnr_membership(DnsScope *s, bool b);
int dns_scope_mdns_membership(DnsScope *s, bool b);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 541266ff9d..585bfee2d1 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -771,23 +771,25 @@ DnsServer *manager_get_dns_server(Manager *m) {
return m->current_dns_server;
}
-void manager_next_dns_server(Manager *m) {
+void manager_next_dns_server(Manager *m, DnsServer *if_current) {
assert(m);
- /* If there's currently no DNS server set, then the next
- * manager_get_dns_server() will find one */
+ /* If the DNS server is already a different one than the one specified in 'if_current' don't do anything */
+ if (if_current && m->current_dns_server != if_current)
+ return;
+
+ /* If there's currently no DNS server set, then the next manager_get_dns_server() will find one */
if (!m->current_dns_server)
return;
- /* Change to the next one, but make sure to follow the linked
- * list only if the server is still linked. */
+ /* Change to the next one, but make sure to follow the linked list only if the server is still
+ * linked. */
if (m->current_dns_server->linked && m->current_dns_server->servers_next) {
manager_set_dns_server(m, m->current_dns_server->servers_next);
return;
}
- /* If there was no next one, then start from the beginning of
- * the list */
+ /* If there was no next one, then start from the beginning of the list */
if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
manager_set_dns_server(m, m->fallback_dns_servers);
else
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index e4664c883a..96e46226ee 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -143,7 +143,7 @@ DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t);
DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
DnsServer *manager_get_dns_server(Manager *m);
-void manager_next_dns_server(Manager *m);
+void manager_next_dns_server(Manager *m, DnsServer *if_current);
DnssecMode dns_server_get_dnssec_mode(DnsServer *s);
DnsOverTlsMode dns_server_get_dns_over_tls_mode(DnsServer *s);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 1ef1900b7b..bd73aa5451 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -484,7 +484,7 @@ static void dns_transaction_retry(DnsTransaction *t, bool next_server) {
/* Before we try again, switch to a new server. */
if (next_server)
- dns_scope_next_dns_server(t->scope);
+ dns_scope_next_dns_server(t->scope, t->server);
r = dns_transaction_go(t);
if (r < 0)
@@ -1859,7 +1859,7 @@ int dns_transaction_go(DnsTransaction *t) {
/* One of our own stub listeners */
log_debug_errno(r, "Detected that specified DNS server is our own extra listener, switching DNS servers.");
- dns_scope_next_dns_server(t->scope);
+ dns_scope_next_dns_server(t->scope, t->server);
if (dns_scope_get_dns_server(t->scope) == t->server) {
log_debug_errno(r, "Still pointing to extra listener after switching DNS servers, refusing operation.");
@@ -1890,7 +1890,7 @@ int dns_transaction_go(DnsTransaction *t) {
return r;
/* Couldn't send? Try immediately again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_scope_next_dns_server(t->scope, t->server);
return dns_transaction_go(t);
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 3a549691c8..9778ebfff7 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -731,19 +731,27 @@ DnsServer *link_get_dns_server(Link *l) {
return l->current_dns_server;
}
-void link_next_dns_server(Link *l) {
+void link_next_dns_server(Link *l, DnsServer *if_current) {
assert(l);
+ /* If the current server of the transaction is specified, and we already are at a different one,
+ * don't do anything */
+ if (if_current && l->current_dns_server != if_current)
+ return;
+
+ /* If currently have no DNS server, then don't do anything, we'll pick it lazily the next time a DNS
+ * server is needed. */
if (!l->current_dns_server)
return;
- /* Change to the next one, but make sure to follow the linked
- * list only if this server is actually still linked. */
+ /* Change to the next one, but make sure to follow the linked list only if this server is actually
+ * still linked. */
if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
link_set_dns_server(l, l->current_dns_server->servers_next);
return;
}
+ /* Pick the first one again, after we reached the end */
link_set_dns_server(l, l->dns_servers);
}
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index 26b0d13127..2be724376e 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -91,7 +91,7 @@ void link_allocate_scopes(Link *l);
DnsServer* link_set_dns_server(Link *l, DnsServer *s);
DnsServer* link_get_dns_server(Link *l);
-void link_next_dns_server(Link *l);
+void link_next_dns_server(Link *l, DnsServer *if_current);
DnssecMode link_get_dnssec_mode(Link *l);
bool link_dnssec_supported(Link *l);