summaryrefslogtreecommitdiffstats
path: root/src/resolve
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2024-03-06 14:55:14 +0100
committerGitHub <noreply@github.com>2024-03-06 14:55:14 +0100
commitba6ec879bb73f36b02c73cd1a7d40fba779f3140 (patch)
tree9eb1d677aaefac245000bf628c78cc9218d3fbcf /src/resolve
parentstring-util: allow taking SIZE_MAX as size to shorten to (diff)
parentresolved: make resolved authoritative in resolveing our local host name (diff)
downloadsystemd-ba6ec879bb73f36b02c73cd1a7d40fba779f3140.tar.xz
systemd-ba6ec879bb73f36b02c73cd1a7d40fba779f3140.zip
Merge pull request #31621 from poettering/resolved-proxy-do
resolved: proxy upstream local requests to our stub with DO bit set
Diffstat (limited to 'src/resolve')
-rw-r--r--src/resolve/resolvectl.c12
-rw-r--r--src/resolve/resolved-bus.c1
-rw-r--r--src/resolve/resolved-def.h4
-rw-r--r--src/resolve/resolved-dns-query.c8
-rw-r--r--src/resolve/resolved-dns-scope.c80
-rw-r--r--src/resolve/resolved-dns-scope.h5
-rw-r--r--src/resolve/resolved-dns-stub.c7
-rw-r--r--src/resolve/resolved-dns-synthesize.c19
-rw-r--r--src/resolve/resolved-dns-synthesize.h2
-rw-r--r--src/resolve/resolved-etc-hosts.c17
-rw-r--r--src/resolve/resolved-varlink.c1
11 files changed, 136 insertions, 20 deletions
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index 405e8ec215..f2e9e7a96b 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -3342,6 +3342,7 @@ static int native_help(void) {
" --synthesize=BOOL Allow synthetic response (default: yes)\n"
" --cache=BOOL Allow response from cache (default: yes)\n"
" --stale-data=BOOL Allow response from cache with stale data (default: yes)\n"
+ " --relax-single-label=BOOL Allow single label lookups to go upstream (default: no)\n"
" --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
" records (default: yes)\n"
" --trust-anchor=BOOL Allow response from local trust anchor (default:\n"
@@ -3701,7 +3702,8 @@ static int native_parse_argv(int argc, char *argv[]) {
ARG_SEARCH,
ARG_NO_PAGER,
ARG_JSON,
- ARG_STALE_DATA
+ ARG_STALE_DATA,
+ ARG_RELAX_SINGLE_LABEL,
};
static const struct option options[] = {
@@ -3726,6 +3728,7 @@ static int native_parse_argv(int argc, char *argv[]) {
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "json", required_argument, NULL, ARG_JSON },
{ "stale-data", required_argument, NULL, ARG_STALE_DATA },
+ { "relax-single-label", required_argument, NULL, ARG_RELAX_SINGLE_LABEL },
{}
};
@@ -3912,6 +3915,13 @@ static int native_parse_argv(int argc, char *argv[]) {
SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
break;
+ case ARG_RELAX_SINGLE_LABEL:
+ r = parse_boolean_argument("--relax-single-label=", optarg, NULL);
+ if (r < 0)
+ return r;
+ SET_FLAG(arg_flags, SD_RESOLVED_RELAX_SINGLE_LABEL, r > 0);
+ break;
+
case ARG_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index f83c654558..be2fdca21f 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -373,6 +373,7 @@ static int validate_and_mangle_flags(
SD_RESOLVED_NO_TRUST_ANCHOR|
SD_RESOLVED_NO_NETWORK|
SD_RESOLVED_NO_STALE|
+ SD_RESOLVED_RELAX_SINGLE_LABEL|
ok))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h
index b7a44f9571..f702a0a0ea 100644
--- a/src/resolve/resolved-def.h
+++ b/src/resolve/resolved-def.h
@@ -73,6 +73,10 @@
/* Input: Don't answer request with stale data */
#define SD_RESOLVED_NO_STALE (UINT64_C(1) << 24)
+/* Input: Allow single-label lookups to Internet DNS servers */
+#define SD_RESOLVED_RELAX_SINGLE_LABEL \
+ (UINT64_C(1) << 25)
+
#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6)
#define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6)
#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS)
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 938dd61a6a..801bbe8007 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -672,6 +672,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC;
*state = DNS_TRANSACTION_RCODE_FAILURE;
+ log_debug("Found synthetic NXDOMAIN response.");
+
return 0;
}
if (r <= 0)
@@ -687,6 +689,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
*state = DNS_TRANSACTION_SUCCESS;
+ log_debug("Found synthetic success response.");
+
return 1;
}
@@ -741,7 +745,7 @@ int dns_query_go(DnsQuery *q) {
LIST_FOREACH(scopes, s, q->manager->dns_scopes) {
DnsScopeMatch match;
- match = dns_scope_good_domain(s, q);
+ match = dns_scope_good_domain(s, q, q->flags);
assert(match >= 0);
if (match > found) { /* Does this match better? If so, remember how well it matched, and the first one
* that matches this well */
@@ -768,7 +772,7 @@ int dns_query_go(DnsQuery *q) {
LIST_FOREACH(scopes, s, first->scopes_next) {
DnsScopeMatch match;
- match = dns_scope_good_domain(s, q);
+ match = dns_scope_good_domain(s, q, q->flags);
assert(match >= 0);
if (match < found)
continue;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index f13233c8da..80a1707407 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -12,6 +12,7 @@
#include "random-util.h"
#include "resolved-dnssd.h"
#include "resolved-dns-scope.h"
+#include "resolved-dns-synthesize.h"
#include "resolved-dns-zone.h"
#include "resolved-llmnr.h"
#include "resolved-mdns.h"
@@ -596,12 +597,13 @@ static DnsScopeMatch match_subnet_reverse_lookups(
DnsScopeMatch dns_scope_good_domain(
DnsScope *s,
- DnsQuery *q) {
+ DnsQuery *q,
+ uint64_t query_flags) {
DnsQuestion *question;
const char *domain;
uint64_t flags;
- int ifindex;
+ int ifindex, r;
/* This returns the following return values:
*
@@ -655,6 +657,15 @@ DnsScopeMatch dns_scope_good_domain(
is_dns_proxy_stub_hostname(domain))
return DNS_SCOPE_NO;
+ /* Don't look up the local host name via the network, unless user turned of local synthesis of it */
+ if (manager_is_own_hostname(s->manager, domain) && shall_synthesize_own_hostname_rrs())
+ return DNS_SCOPE_NO;
+
+ /* Never send SOA or NS or DNSSEC request to LLMNR, where they make little sense. */
+ r = dns_question_types_suitable_for_protocol(question, s->protocol);
+ if (r <= 0)
+ return DNS_SCOPE_NO;
+
switch (s->protocol) {
case DNS_PROTOCOL_DNS: {
@@ -710,7 +721,8 @@ DnsScopeMatch dns_scope_good_domain(
/* If ResolveUnicastSingleLabel=yes and the query is single-label, then bump match result
to prevent LLMNR monopoly among candidates. */
- if (s->manager->resolve_unicast_single_label && dns_name_is_single_label(domain))
+ if ((s->manager->resolve_unicast_single_label || (query_flags & SD_RESOLVED_RELAX_SINGLE_LABEL)) &&
+ dns_name_is_single_label(domain))
return DNS_SCOPE_YES_BASE + 1;
/* Let's return the number of labels in the best matching result */
@@ -1686,3 +1698,65 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) {
JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)),
JSON_BUILD_PAIR_VARIANT("cache", cache)));
}
+
+int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol) {
+
+ /* Tests whether it makes sense to route queries for the specified DNS RR types to the specified
+ * protocol. For classic DNS pretty much all RR types are suitable, but for LLMNR/mDNS let's
+ * allowlist only a few that make sense. We use this when routing queries so that we can more quickly
+ * return errors for queries that will almost certainly fail/time-out otherwise. For example, this
+ * ensures that SOA, NS, or DS/DNSKEY queries are never routed to mDNS/LLMNR where they simply make
+ * no sense. */
+
+ if (dns_type_is_obsolete(type))
+ return false;
+
+ if (!dns_type_is_valid_query(type))
+ return false;
+
+ switch (protocol) {
+
+ case DNS_PROTOCOL_DNS:
+ return true;
+
+ case DNS_PROTOCOL_LLMNR:
+ return IN_SET(type,
+ DNS_TYPE_ANY,
+ DNS_TYPE_A,
+ DNS_TYPE_AAAA,
+ DNS_TYPE_CNAME,
+ DNS_TYPE_PTR,
+ DNS_TYPE_TXT);
+
+ case DNS_PROTOCOL_MDNS:
+ return IN_SET(type,
+ DNS_TYPE_ANY,
+ DNS_TYPE_A,
+ DNS_TYPE_AAAA,
+ DNS_TYPE_CNAME,
+ DNS_TYPE_PTR,
+ DNS_TYPE_TXT,
+ DNS_TYPE_SRV,
+ DNS_TYPE_NSEC,
+ DNS_TYPE_HINFO);
+
+ default:
+ return -EPROTONOSUPPORT;
+ }
+}
+
+int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol) {
+ DnsResourceKey *key;
+ int r;
+
+ /* Tests whether the types in the specified question make any sense to be routed to the specified
+ * protocol, i.e. if dns_type_suitable_for_protocol() is true for any of the contained RR types */
+
+ DNS_QUESTION_FOREACH(key, q) {
+ r = dns_type_suitable_for_protocol(key->type, protocol);
+ if (r != 0)
+ return r;
+ }
+
+ return false;
+}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 82218e70fa..76b6ed6838 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -78,7 +78,7 @@ int dns_scope_emit_udp(DnsScope *s, int fd, int af, DnsPacket *p);
int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address);
int dns_scope_socket_udp(DnsScope *s, DnsServer *server);
-DnsScopeMatch dns_scope_good_domain(DnsScope *s, DnsQuery *q);
+DnsScopeMatch dns_scope_good_domain(DnsScope *s, DnsQuery *q, uint64_t query_flags);
bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key);
DnsServer *dns_scope_get_dns_server(DnsScope *s);
@@ -114,3 +114,6 @@ int dns_scope_remove_dnssd_services(DnsScope *scope);
bool dns_scope_is_default_route(DnsScope *scope);
int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret);
+
+int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol);
+int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 2a3c1edbba..87f7aab6e9 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -958,8 +958,8 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
log_debug("Got request to DNS proxy address 127.0.0.54, enabling bypass logic.");
bypass = true;
protocol_flags = SD_RESOLVED_DNS|SD_RESOLVED_NO_ZONE; /* Turn off mDNS/LLMNR for proxy stub. */
- } else if ((DNS_PACKET_DO(p) && DNS_PACKET_CD(p))) {
- log_debug("Got request with DNSSEC checking disabled, enabling bypass logic.");
+ } else if (DNS_PACKET_DO(p)) {
+ log_debug("Got request with DNSSEC enabled, enabling bypass logic.");
bypass = true;
}
@@ -970,7 +970,8 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
SD_RESOLVED_NO_SEARCH|
SD_RESOLVED_NO_VALIDATE|
SD_RESOLVED_REQUIRE_PRIMARY|
- SD_RESOLVED_CLAMP_TTL);
+ SD_RESOLVED_CLAMP_TTL|
+ SD_RESOLVED_RELAX_SINGLE_LABEL);
else
r = dns_query_new(m, &q, p->question, p->question, NULL, 0,
protocol_flags|
diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c
index 5bde29c704..6f483fdf0e 100644
--- a/src/resolve/resolved-dns-synthesize.c
+++ b/src/resolve/resolved-dns-synthesize.c
@@ -439,6 +439,20 @@ static int synthesize_gateway_ptr(
return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
}
+bool shall_synthesize_own_hostname_rrs(void) {
+ static int cached = -1;
+ int r;
+
+ if (cached >= 0)
+ return cached;
+
+ r = secure_getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME");
+ if (r < 0 && r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME: %m");
+
+ return (cached = r != 0);
+}
+
int dns_synthesize_answer(
Manager *m,
DnsQuestion *q,
@@ -479,8 +493,9 @@ int dns_synthesize_answer(
} else if (manager_is_own_hostname(m, name)) {
- if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
+ if (!shall_synthesize_own_hostname_rrs())
continue;
+
r = synthesize_system_hostname_rr(m, key, ifindex, &answer);
if (r < 0)
return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
@@ -530,7 +545,7 @@ int dns_synthesize_answer(
} else if (dns_name_address(name, &af, &address) > 0) {
int v, w, u;
- if (getenv_bool("SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME") == 0)
+ if (!shall_synthesize_own_hostname_rrs())
continue;
v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
diff --git a/src/resolve/resolved-dns-synthesize.h b/src/resolve/resolved-dns-synthesize.h
index bf271e862d..ca39e682b4 100644
--- a/src/resolve/resolved-dns-synthesize.h
+++ b/src/resolve/resolved-dns-synthesize.h
@@ -9,3 +9,5 @@ int dns_synthesize_family(uint64_t flags);
DnsProtocol dns_synthesize_protocol(uint64_t flags);
int dns_synthesize_answer(Manager *m, DnsQuestion *q, int ifindex, DnsAnswer **ret);
+
+bool shall_synthesize_own_hostname_rrs(void);
diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c
index 6af160a477..2d334d38dd 100644
--- a/src/resolve/resolved-etc-hosts.c
+++ b/src/resolve/resolved-etc-hosts.c
@@ -491,7 +491,7 @@ static int etc_hosts_lookup_by_name(
const char *name,
DnsAnswer **answer) {
- bool found_a = false, found_aaaa = false;
+ bool question_for_a = false, question_for_aaaa = false;
const struct in_addr_data *a;
EtcHostsItemByName *item;
DnsResourceKey *t;
@@ -513,6 +513,7 @@ static int etc_hosts_lookup_by_name(
return 0;
}
+ /* Determine whether we are looking for A and/or AAAA RRs */
DNS_QUESTION_FOREACH(t, q) {
if (!IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_TYPE_ANY))
continue;
@@ -526,20 +527,20 @@ static int etc_hosts_lookup_by_name(
continue;
if (IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_ANY))
- found_a = true;
+ question_for_a = true;
if (IN_SET(t->type, DNS_TYPE_AAAA, DNS_TYPE_ANY))
- found_aaaa = true;
+ question_for_aaaa = true;
- if (found_a && found_aaaa)
- break;
+ if (question_for_a && question_for_aaaa)
+ break; /* We are looking for both, no need to continue loop */
}
SET_FOREACH(a, item ? item->addresses : NULL) {
EtcHostsItemByAddress *item_by_addr;
const char *canonical_name;
- if ((!found_a && a->family == AF_INET) ||
- (!found_aaaa && a->family == AF_INET6))
+ if ((!question_for_a && a->family == AF_INET) ||
+ (!question_for_aaaa && a->family == AF_INET6))
continue;
item_by_addr = hashmap_get(hosts->by_address, a);
@@ -559,7 +560,7 @@ static int etc_hosts_lookup_by_name(
return r;
}
- return found_a || found_aaaa;
+ return true; /* We consider ourselves authoritative for the whole name, all RR types, not just A/AAAA */
}
int manager_etc_hosts_lookup(Manager *m, DnsQuestion *q, DnsAnswer **answer) {
diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c
index 6e6e973f94..cdd5ca41fd 100644
--- a/src/resolve/resolved-varlink.c
+++ b/src/resolve/resolved-varlink.c
@@ -162,6 +162,7 @@ static bool validate_and_mangle_flags(
SD_RESOLVED_NO_TRUST_ANCHOR|
SD_RESOLVED_NO_NETWORK|
SD_RESOLVED_NO_STALE|
+ SD_RESOLVED_RELAX_SINGLE_LABEL|
ok))
return false;