summaryrefslogtreecommitdiff
path: root/src/resolve
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve')
-rw-r--r--src/resolve/resolved-bus.c10
-rw-r--r--src/resolve/resolved-conf.c20
-rw-r--r--src/resolve/resolved-dns-dnssec.c12
-rw-r--r--src/resolve/resolved-dns-query.c13
-rw-r--r--src/resolve/resolved-dns-search-domain.c3
-rw-r--r--src/resolve/resolved-dns-search-domain.h1
-rw-r--r--src/resolve/resolved-dns-transaction.c72
-rw-r--r--src/resolve/resolved-link-bus.c52
-rw-r--r--src/resolve/resolved-link.c56
-rw-r--r--src/resolve/resolved-manager.c6
-rw-r--r--src/resolve/resolved-manager.h1
11 files changed, 167 insertions, 79 deletions
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index d8e8638327..834ae837de 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1217,19 +1217,19 @@ static int bus_property_get_search_domains(
assert(reply);
assert(m);
- r = sd_bus_message_open_container(reply, 'a', "(is)");
+ r = sd_bus_message_open_container(reply, 'a', "(isb)");
if (r < 0)
return r;
LIST_FOREACH(domains, d, m->search_domains) {
- r = sd_bus_message_append(reply, "(is)", 0, d->name);
+ r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only);
if (r < 0)
return r;
}
HASHMAP_FOREACH(l, m->links, i) {
LIST_FOREACH(domains, d, l->search_domains) {
- r = sd_bus_message_append(reply, "is", l->ifindex, d->name);
+ r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only);
if (r < 0)
return r;
}
@@ -1450,7 +1450,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
- SD_BUS_PROPERTY("Domains", "a(is)", bus_property_get_search_domains, 0, 0),
+ SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0),
SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
@@ -1463,7 +1463,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
- SD_BUS_METHOD("SetLinkDomains", "ias", NULL, bus_method_set_link_search_domains, 0),
+ SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0),
SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 88df7534c4..6d8c35164e 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -80,20 +80,34 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con
int manager_add_search_domain_by_string(Manager *m, const char *domain) {
DnsSearchDomain *d;
+ bool route_only;
int r;
assert(m);
assert(domain);
+ route_only = *domain == '~';
+ if (route_only)
+ domain++;
+
+ if (dns_name_is_root(domain) || streq(domain, "*")) {
+ route_only = true;
+ domain = ".";
+ }
+
r = dns_search_domain_find(m->search_domains, domain, &d);
if (r < 0)
return r;
- if (r > 0) {
+ if (r > 0)
dns_search_domain_move_back_and_unmark(d);
- return 0;
+ else {
+ r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
+ if (r < 0)
+ return r;
}
- return dns_search_domain_new(m, NULL, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
+ d->route_only = route_only;
+ return 0;
}
int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 8e3c78e7bf..76c801cce8 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -28,18 +28,6 @@
#include "resolved-dns-packet.h"
#include "string-table.h"
-/* Open question:
- *
- * How does the DNSSEC canonical form of a hostname with a label
- * containing a dot look like, the way DNS-SD does it?
- *
- * TODO:
- *
- * - enable by default
- * - Allow clients to request DNSSEC even if DNSSEC is off
- * - make sure when getting an NXDOMAIN response through CNAME, we still process the first CNAMEs in the packet
- * */
-
#define VERIFY_RRS_MAX 256
#define MAX_KEY_SIZE (32*1024)
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index ef977b0948..a00851658e 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -93,17 +93,20 @@ static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
assert(c);
- if (c->search_domain && c->search_domain->linked) {
+ if (c->search_domain && c->search_domain->linked)
next = c->search_domain->domains_next;
+ else
+ next = dns_scope_get_search_domains(c->scope);
+ for (;;) {
if (!next) /* We hit the end of the list */
return 0;
- } else {
- next = dns_scope_get_search_domains(c->scope);
+ if (!next->route_only)
+ break;
- if (!next) /* OK, there's nothing. */
- return 0;
+ /* Skip over route-only domains */
+ next = next->domains_next;
}
dns_search_domain_unref(c->search_domain);
diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c
index f9d966abb1..356c05b9a4 100644
--- a/src/resolve/resolved-dns-search-domain.c
+++ b/src/resolve/resolved-dns-search-domain.c
@@ -42,9 +42,6 @@ int dns_search_domain_new(
if (r < 0)
return r;
- if (dns_name_is_root(normalized))
- return -EINVAL;
-
if (l) {
if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
return -E2BIG;
diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h
index 2e0af31dda..c1903b334f 100644
--- a/src/resolve/resolved-dns-search-domain.h
+++ b/src/resolve/resolved-dns-search-domain.h
@@ -44,6 +44,7 @@ struct DnsSearchDomain {
char *name;
bool marked:1;
+ bool route_only:1;
bool linked:1;
LIST_FIELDS(DnsSearchDomain, domains);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 77f9ef0a83..802ad860a4 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -732,6 +732,55 @@ fail:
dns_transaction_complete(t, DNS_TRANSACTION_ERRNO);
}
+static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
+ int r;
+
+ assert(t);
+
+ /* Checks whether the answer is positive, i.e. either a direct
+ * answer to the question, or a CNAME/DNAME for it */
+
+ r = dns_answer_match_key(t->answer, t->key, flags);
+ if (r != 0)
+ return r;
+
+ r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags);
+ if (r != 0)
+ return r;
+
+ return false;
+}
+
+static int dns_transaction_fix_rcode(DnsTransaction *t) {
+ int r;
+
+ assert(t);
+
+ /* Fix up the RCODE to SUCCESS if we get at least one matching RR in a response. Note that this contradicts the
+ * DNS RFCs a bit. Specifically, RFC 6604 Section 3 clarifies that the RCODE shall say something about a
+ * CNAME/DNAME chain element coming after the last chain element contained in the message, and not the first
+ * one included. However, it also indicates that not all DNS servers implement this correctly. Moreover, when
+ * using DNSSEC we usually only can prove the first element of a CNAME/DNAME chain anyway, hence let's settle
+ * on always processing the RCODE as referring to the immediate look-up we do, i.e. the first element of a
+ * CNAME/DNAME chain. This way, we uniformly handle CNAME/DNAME chains, regardless if the DNS server
+ * incorrectly implements RCODE, whether DNSSEC is in use, or whether the DNS server only supplied us with an
+ * incomplete CNAME/DNAME chain.
+ *
+ * Or in other words: if we get at least one positive reply in a message we patch NXDOMAIN to become SUCCESS,
+ * and then rely on the CNAME chasing logic to figure out that there's actually a CNAME error with a new
+ * lookup. */
+
+ if (t->answer_rcode != DNS_RCODE_NXDOMAIN)
+ return 0;
+
+ r = dns_transaction_has_positive_answer(t, NULL);
+ if (r <= 0)
+ return r;
+
+ t->answer_rcode = DNS_RCODE_SUCCESS;
+ return 0;
+}
+
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
usec_t ts;
int r;
@@ -923,6 +972,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
t->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
t->answer_authenticated = false;
+ r = dns_transaction_fix_rcode(t);
+ if (r < 0)
+ goto fail;
+
/* Block GC while starting requests for additional DNSSEC RRs */
t->block_gc++;
r = dns_transaction_request_dnssec_keys(t);
@@ -1635,25 +1688,6 @@ static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *
return 1;
}
-static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
- int r;
-
- assert(t);
-
- /* Checks whether the answer is positive, i.e. either a direct
- * answer to the question, or a CNAME/DNAME for it */
-
- r = dns_answer_match_key(t->answer, t->key, flags);
- if (r != 0)
- return r;
-
- r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags);
- if (r != 0)
- return r;
-
- return false;
-}
-
static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) {
int r;
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 2ca7ece851..e6b087f412 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -75,12 +75,12 @@ static int property_get_domains(
assert(reply);
assert(l);
- r = sd_bus_message_open_container(reply, 'a', "s");
+ r = sd_bus_message_open_container(reply, 'a', "(sb)");
if (r < 0)
return r;
LIST_FOREACH(domains, d, l->search_domains) {
- r = sd_bus_message_append(reply, "s", d->name);
+ r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
if (r < 0)
return r;
}
@@ -242,47 +242,71 @@ clear:
}
int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char **domains = NULL;
Link *l = userdata;
- char **i;
int r;
assert(message);
assert(l);
- r = sd_bus_message_read_strv(message, &domains);
+ r = sd_bus_message_enter_container(message, 'a', "(sb)");
if (r < 0)
return r;
- STRV_FOREACH(i, domains) {
+ for (;;) {
+ const char *name;
+ int route_only;
- r = dns_name_is_valid(*i);
+ r = sd_bus_message_read(message, "(sb)", &name, &route_only);
if (r < 0)
return r;
if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", *i);
- if (dns_name_is_root(*i))
+ break;
+
+ r = dns_name_is_valid(name);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
+ if (!route_only && dns_name_is_root(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
}
dns_search_domain_mark_all(l->search_domains);
- STRV_FOREACH(i, domains) {
+ r = sd_bus_message_rewind(message, false);
+ if (r < 0)
+ return r;
+
+ for (;;) {
DnsSearchDomain *d;
+ const char *name;
+ int route_only;
- r = dns_search_domain_find(l->search_domains, *i, &d);
+ r = sd_bus_message_read(message, "(sb)", &name, &route_only);
+ if (r < 0)
+ goto clear;
+ if (r == 0)
+ break;
+
+ r = dns_search_domain_find(l->search_domains, name, &d);
if (r < 0)
goto clear;
if (r > 0)
dns_search_domain_move_back_and_unmark(d);
else {
- r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
+ r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
if (r < 0)
goto clear;
}
+
+ d->route_only = route_only;
}
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ goto clear;
+
dns_search_domain_unlink_marked(l->search_domains);
return sd_bus_reply_method_return(message, NULL);
@@ -430,7 +454,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
- SD_BUS_PROPERTY("Domains", "as", property_get_domains, 0, 0),
+ SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0),
SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
@@ -438,7 +462,7 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0),
SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
- SD_BUS_METHOD("SetDomains", "as", NULL, bus_link_method_set_search_domains, 0),
+ SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0),
SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index e2f9c8b400..37dd4a6e78 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -377,38 +377,60 @@ clear:
return r;
}
+static int link_update_search_domain_one(Link *l, const char *name, bool route_only) {
+ DnsSearchDomain *d;
+ int r;
+
+ r = dns_search_domain_find(l->search_domains, name, &d);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ dns_search_domain_move_back_and_unmark(d);
+ else {
+ r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
+ if (r < 0)
+ return r;
+ }
+
+ d->route_only = route_only;
+ return 0;
+}
+
static int link_update_search_domains(Link *l) {
- _cleanup_strv_free_ char **domains = NULL;
+ _cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL;
char **i;
- int r;
+ int r, q;
assert(l);
- r = sd_network_link_get_domains(l->ifindex, &domains);
- if (r == -ENODATA) {
+ r = sd_network_link_get_search_domains(l->ifindex, &sdomains);
+ if (r < 0 && r != -ENODATA)
+ goto clear;
+
+ q = sd_network_link_get_route_domains(l->ifindex, &rdomains);
+ if (q < 0 && q != -ENODATA) {
+ r = q;
+ goto clear;
+ }
+
+ if (r == -ENODATA && q == -ENODATA) {
/* networkd knows nothing about this interface, and that's fine. */
r = 0;
goto clear;
}
- if (r < 0)
- goto clear;
dns_search_domain_mark_all(l->search_domains);
- STRV_FOREACH(i, domains) {
- DnsSearchDomain *d;
-
- r = dns_search_domain_find(l->search_domains, *i, &d);
+ STRV_FOREACH(i, sdomains) {
+ r = link_update_search_domain_one(l, *i, false);
if (r < 0)
goto clear;
+ }
- if (r > 0)
- dns_search_domain_move_back_and_unmark(d);
- else {
- r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
- if (r < 0)
- goto clear;
- }
+ STRV_FOREACH(i, rdomains) {
+ r = link_update_search_domain_one(l, *i, true);
+ if (r < 0)
+ goto clear;
}
dns_search_domain_unlink_marked(l->search_domains);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 704f012c37..4306403834 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -206,7 +206,7 @@ static int manager_rtnl_listen(Manager *m) {
if (r < 0)
return r;
- r = sd_netlink_attach_event(m->rtnl, m->event, 0);
+ r = sd_netlink_attach_event(m->rtnl, m->event, SD_EVENT_PRIORITY_IMPORTANT);
if (r < 0)
return r;
@@ -314,6 +314,10 @@ static int manager_network_monitor_listen(Manager *m) {
if (r < 0)
return r;
+ r = sd_event_source_set_priority(m->network_event_source, SD_EVENT_PRIORITY_IMPORTANT+5);
+ if (r < 0)
+ return r;
+
(void) sd_event_source_set_description(m->network_event_source, "network-monitor");
return 0;
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index a4291d57ff..1af49c8fb9 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -74,6 +74,7 @@ struct Manager {
LIST_HEAD(DnsSearchDomain, search_domains);
unsigned n_search_domains;
+ bool permit_domain_search;
bool need_builtin_fallbacks:1;