aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/resolve/resolved-dns-scope.c43
-rw-r--r--src/resolve/resolved-dns-scope.h2
-rw-r--r--src/resolve/resolved-link.c34
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-resolv-conf.c8
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;
}