diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index b3d37525f4..f0822d1f72 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -70,15 +70,12 @@ int dns_server_new( s->n_ref = 1; s->manager = m; - s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; - s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST; - s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC; - s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX; s->type = type; s->family = family; s->address = *in_addr; s->ifindex = ifindex; - s->resend_timeout = DNS_TIMEOUT_MIN_USEC; + + dns_server_reset_features(s); switch (type) { @@ -828,6 +825,34 @@ void dns_server_flush_cache(DnsServer *s) { dns_cache_flush(&scope->cache); } +void dns_server_reset_features(DnsServer *s) { + assert(s); + + s->max_rtt = 0; + s->resend_timeout = DNS_TIMEOUT_MIN_USEC; + + s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST; + + s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX; + + s->packet_bad_opt = false; + s->packet_rrsig_missing = false; + + s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC; + + s->warned_downgrade = false; + + dns_server_reset_counters(s); +} + +void dns_server_reset_features_all(DnsServer *s) { + DnsServer *i; + + LIST_FOREACH(servers, i, s) + dns_server_reset_features(i); +} + static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = { [DNS_SERVER_SYSTEM] = "system", [DNS_SERVER_FALLBACK] = "fallback", diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index bc95d53c6a..a5a82f7b76 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -151,3 +151,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref); extern const struct hash_ops dns_server_hash_ops; void dns_server_flush_cache(DnsServer *s); + +void dns_server_reset_features(DnsServer *s); +void dns_server_reset_features_all(DnsServer *s); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 21fd8465e6..3d26831b06 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -111,13 +111,30 @@ Link *link_free(Link *l) { } void link_allocate_scopes(Link *l) { + bool unicast_relevant; int r; assert(l); - if (link_relevant(l, AF_UNSPEC, false) && - l->dns_servers) { + /* If a link that used to be relevant is no longer, or a link that did not use to be relevant now becomes + * relevant, let's reinit the learnt global DNS server information, since we might talk to different servers + * now, even if they have the same addresses as before. */ + + unicast_relevant = link_relevant(l, AF_UNSPEC, false); + if (unicast_relevant != l->unicast_relevant) { + l->unicast_relevant = unicast_relevant; + + dns_server_reset_features_all(l->manager->fallback_dns_servers); + dns_server_reset_features_all(l->manager->dns_servers); + } + + /* And now, allocate all scopes that makes sense now if we didn't have them yet, and drop those which we don't + * need anymore */ + + if (unicast_relevant && l->dns_servers) { if (!l->unicast_scope) { + dns_server_reset_features_all(l->dns_servers); + r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) log_warning_errno(r, "Failed to allocate DNS scope: %m"); diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index 55a56b7906..c20b8b6d29 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -88,6 +88,8 @@ struct Link { bool loaded; char *state_file; + + bool unicast_relevant; }; int link_new(Manager *m, Link **ret, int ifindex); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 58fe572d3b..3765d74cee 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1396,6 +1396,19 @@ void manager_flush_caches(Manager *m) { log_info("Flushed all caches."); } +void manager_reset_server_features(Manager *m) { + Iterator i; + Link *l; + + dns_server_reset_features_all(m->dns_servers); + dns_server_reset_features_all(m->fallback_dns_servers); + + HASHMAP_FOREACH(l, m->links, i) + dns_server_reset_features_all(l->dns_servers); + + log_info("Resetting learnt feature levels on all servers."); +} + void manager_cleanup_saved_user(Manager *m) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 97c52b7729..bb45ecc1d6 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -184,5 +184,6 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource bool manager_routable(Manager *m, int family); void manager_flush_caches(Manager *m); +void manager_reset_server_features(Manager *m); void manager_cleanup_saved_user(Manager *m); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 2af77b3407..e3d6a33409 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -26,6 +26,7 @@ #include "fileio.h" #include "ordered-set.h" #include "resolved-conf.h" +#include "resolved-dns-server.h" #include "resolved-resolv-conf.h" #include "string-util.h" #include "strv.h" @@ -136,6 +137,11 @@ int manager_read_resolv_conf(Manager *m) { if (m->unicast_scope) dns_cache_flush(&m->unicast_scope->cache); + /* If /etc/resolv.conf changed, make sure to forget everything we learned about the DNS servers. After all we + * might now talk to a very different DNS server that just happens to have the same IP address as an old one + * (think 192.168.1.1). */ + dns_server_reset_features_all(m->dns_servers); + return 0; clear: