diff options
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 43 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-link.c | 34 | ||||
-rw-r--r-- | src/resolve/resolved-link.h | 2 | ||||
-rw-r--r-- | src/resolve/resolved-resolv-conf.c | 8 |
5 files changed, 66 insertions, 23 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index be4548599..972e661d7 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -554,9 +554,8 @@ DnsScopeMatch dns_scope_good_domain( return DNS_SCOPE_YES_BASE + n_best; } - /* If the DNS server has route-only domains, don't send other requests to it. This would be a privacy - * violation, will most probably fail anyway, and adds unnecessary load. */ - if (dns_scope_has_route_only_domains(s)) + /* See if this scope is suitable as default route. */ + if (!dns_scope_is_default_route(s)) return DNS_SCOPE_NO; /* Exclude link-local IP ranges */ @@ -1392,15 +1391,17 @@ int dns_scope_remove_dnssd_services(DnsScope *scope) { return 0; } -bool dns_scope_has_route_only_domains(DnsScope *scope) { +static bool dns_scope_has_route_only_domains(DnsScope *scope) { DnsSearchDomain *domain, *first; bool route_only = false; - /* Check if the scope has any route-only domains except for "~.", i. e. whether it should only be - * used for particular domains */ + assert(scope); + assert(scope->protocol == DNS_PROTOCOL_DNS); - if (scope->protocol != DNS_PROTOCOL_DNS) - return false; + /* Returns 'true' if this scope is suitable for queries to specific domains only. For that we check + * if there are any route-only domains on this interface, as a heuristic to discern VPN-style links + * from non-VPN-style links. Returns 'false' for all other cases, i.e. if the scope is intended to + * take queries to arbitrary domains, i.e. has no routing domains set. */ if (scope->link) first = scope->link->search_domains; @@ -1408,7 +1409,10 @@ bool dns_scope_has_route_only_domains(DnsScope *scope) { first = scope->manager->search_domains; LIST_FOREACH(domains, domain, first) { - /* "." means "any domain", thus the interface takes any kind of traffic. */ + /* "." means "any domain", thus the interface takes any kind of traffic. Thus, we exit early + * here, as it doesn't really matter whether this link has any route-only domains or not, + * "~." really trumps everything and clearly indicates that this interface shall receive all + * traffic it can get. */ if (dns_name_is_root(DNS_SEARCH_DOMAIN_NAME(domain))) return false; @@ -1418,3 +1422,24 @@ bool dns_scope_has_route_only_domains(DnsScope *scope) { return route_only; } + +bool dns_scope_is_default_route(DnsScope *scope) { + assert(scope); + + /* Only use DNS scopes as default routes */ + if (scope->protocol != DNS_PROTOCOL_DNS) + return false; + + /* The global DNS scope is always suitable as default route */ + if (!scope->link) + return true; + + /* Honour whatever is explicitly configured. This is really the best approach, and trumps any + * automatic logic. */ + if (scope->link->default_route >= 0) + return scope->link->default_route; + + /* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not + * volunteer as default route. */ + return !dns_scope_has_route_only_domains(scope); +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 6f47a5593..f4b45c4f2 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -109,4 +109,4 @@ int dns_scope_announce(DnsScope *scope, bool goodbye); int dns_scope_add_dnssd_services(DnsScope *scope); int dns_scope_remove_dnssd_services(DnsScope *scope); -bool dns_scope_has_route_only_domains(DnsScope *scope); +bool dns_scope_is_default_route(DnsScope *scope); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 0f9a0e942..351d51a30 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -30,16 +30,19 @@ int link_new(Manager *m, Link **ret, int ifindex) { if (r < 0) return r; - l = new0(Link, 1); + l = new(Link, 1); if (!l) return -ENOMEM; - l->ifindex = ifindex; - l->llmnr_support = RESOLVE_SUPPORT_YES; - l->mdns_support = RESOLVE_SUPPORT_NO; - l->dnssec_mode = _DNSSEC_MODE_INVALID; - l->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID; - l->operstate = IF_OPER_UNKNOWN; + *l = (Link) { + .ifindex = ifindex, + .default_route = -1, + .llmnr_support = RESOLVE_SUPPORT_YES, + .mdns_support = RESOLVE_SUPPORT_NO, + .dnssec_mode = _DNSSEC_MODE_INVALID, + .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID, + .operstate = IF_OPER_UNKNOWN, + }; if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0) return -ENOMEM; @@ -60,6 +63,7 @@ int link_new(Manager *m, Link **ret, int ifindex) { void link_flush_settings(Link *l) { assert(l); + l->default_route = -1; l->llmnr_support = RESOLVE_SUPPORT_YES; l->mdns_support = RESOLVE_SUPPORT_NO; l->dnssec_mode = _DNSSEC_MODE_INVALID; @@ -1120,6 +1124,9 @@ static bool link_needs_save(Link *l) { if (!set_isempty(l->dnssec_negative_trust_anchors)) return true; + if (l->default_route >= 0) + return true; + return false; } @@ -1162,6 +1169,9 @@ int link_save_user(Link *l) { if (v) fprintf(f, "DNSSEC=%s\n", v); + if (l->default_route >= 0) + fprintf(f, "DEFAULT_ROUTE=%s\n", yes_no(l->default_route)); + if (l->dns_servers) { DnsServer *server; @@ -1243,7 +1253,8 @@ int link_load_user(Link *l) { *dnssec = NULL, *servers = NULL, *domains = NULL, - *ntas = NULL; + *ntas = NULL, + *default_route = NULL; ResolveSupport s; const char *p; @@ -1266,7 +1277,8 @@ int link_load_user(Link *l) { "DNSSEC", &dnssec, "SERVERS", &servers, "DOMAINS", &domains, - "NTAS", &ntas); + "NTAS", &ntas, + "DEFAULT_ROUTE", &default_route); if (r == -ENOENT) return 0; if (r < 0) @@ -1283,6 +1295,10 @@ int link_load_user(Link *l) { if (s >= 0) l->mdns_support = s; + r = parse_boolean(default_route); + if (r >= 0) + l->default_route = r; + /* If we can't recognize the DNSSEC setting, then set it to invalid, so that the daemon default is used. */ l->dnssec_mode = dnssec_mode_from_string(dnssec); diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index 81ab2056a..f95ea37a4 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -51,6 +51,8 @@ struct Link { LIST_HEAD(DnsSearchDomain, search_domains); unsigned n_search_domains; + int default_route; + ResolveSupport llmnr_support; ResolveSupport mdns_support; DnsOverTlsMode dns_over_tls_mode; diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 832251b61..5205071d3 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -228,11 +228,11 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { return; } - /* Check if the scope this DNS server belongs to is limited to particular domains; resolv.conf does not have a - * syntax to express that, so it must not appear as a global name server to avoid routing unrelated domains to - * it (which is a privacy violation, will most probably fail anyway, and adds unnecessary load) */ + /* Check if the scope this DNS server belongs to is suitable as 'default' route for lookups; resolv.conf does + * not have a syntax to express that, so it must not appear as a global name server to avoid routing unrelated + * domains to it (which is a privacy violation, will most probably fail anyway, and adds unnecessary load) */ scope = dns_server_scope(s); - if (scope && dns_scope_has_route_only_domains(scope)) { + if (scope && !dns_scope_is_default_route(scope)) { log_debug("Scope of DNS server %s has only route-only domains, not using as global name server", dns_server_string(s)); return; } |