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);