mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
Merge pull request #16059 from keszybz/resolve-single-label-names
Optionally resolve single label names
This commit is contained in:
commit
7830b5c103
8
NEWS
8
NEWS
@ -87,6 +87,12 @@ CHANGES WITH 246 in spe:
|
||||
used, the DNS-over-TLS certificate is validated to match the
|
||||
specified hostname.
|
||||
|
||||
* systemd-resolved may be configured to forward single-label DNS names.
|
||||
This is not standard-conformant, but may make sense in setups where
|
||||
public DNS servers are not used.
|
||||
|
||||
* systemd-resolved's DNS-over-TLS support gained SNI validation.
|
||||
|
||||
* The fs.suid_dumpable sysctl is set to 2 / "suidsafe". This allows
|
||||
systemd-coredump to save core files for suid processes. When saving
|
||||
the core file, systemd-coredump will use the effective uid and gid of
|
||||
@ -538,8 +544,6 @@ CHANGES WITH 245:
|
||||
* systemd-sysusers gained support for creating users with the primary
|
||||
group named differently than the user.
|
||||
|
||||
* systemd-resolved's DNS-over-TLS support gained SNI validation.
|
||||
|
||||
* systemd-growfs (i.e. the x-systemd.growfs mount option in /etc/fstab)
|
||||
gained support for growing XFS partitions. Previously it supported
|
||||
only ext4 and btrfs partitions.
|
||||
|
@ -67,20 +67,28 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Domains=</varname></term>
|
||||
<listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving
|
||||
single-label hostnames (domain names which contain no dot), in order to qualify them into fully-qualified
|
||||
domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name
|
||||
with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search
|
||||
domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains
|
||||
are configured in it. This setting defaults to the empty list.</para>
|
||||
<listitem><para>A space-separated list of domains optionally prefixed with <literal>~</literal>,
|
||||
used for two distinct purposes described below. Defaults to the empty list.</para>
|
||||
|
||||
<para>Specified domain names may optionally be prefixed with <literal>~</literal>. In this case they do not
|
||||
define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured
|
||||
with the system <varname>DNS=</varname> setting (see above), in case additional, suitable per-link DNS servers
|
||||
are known. If no per-link DNS servers are known using the <literal>~</literal> syntax has no effect. Use the
|
||||
construct <literal>~.</literal> (which is composed of <literal>~</literal> to indicate a routing domain and
|
||||
<literal>.</literal> to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the
|
||||
system DNS server defined with <varname>DNS=</varname> preferably for all domains.</para></listitem>
|
||||
<para>Any domains <emphasis>not</emphasis> prefixed with <literal>~</literal> are used as search
|
||||
suffixes when resolving single-label hostnames (domain names which contain no dot), in order to
|
||||
qualify them into fully-qualified domain names (FQDNs). These "search domains" are strictly processed
|
||||
in the order they are specified in, until the name with the suffix appended is found. For
|
||||
compatibility reasons, if this setting is not specified, the search domains listed in
|
||||
<filename>/etc/resolv.conf</filename> with the <varname>search</varname> keyword are used instead, if
|
||||
that file exists and any domains are configured in it.</para>
|
||||
|
||||
<para>The domains prefixed with <literal>~</literal> are called "routing domains". All domains listed
|
||||
here (both search domains and routing domains after removing the <literal>~</literal> prefix) define
|
||||
a search path that preferably directs DNS queries to this inteface. This search path has an effect
|
||||
only when suitable per-link DNS servers are known. Such servers may be defined through the
|
||||
<varname>DNS=</varname> setting (see above) and dynamically at run time, for example from DHCP
|
||||
leases. If no per-link DNS servers are known, routing domains have no effect.</para>
|
||||
|
||||
<para>Use the construct <literal>~.</literal> (which is composed from <literal>~</literal> to
|
||||
indicate a routing domain and <literal>.</literal> to indicate the DNS root domain that is the
|
||||
implied suffix of all DNS domains) to use the DNS servers defined for this link preferably for all
|
||||
domains.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -258,11 +266,28 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ReadEtcHosts=</varname></term>
|
||||
<listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default), the DNS stub resolver will read
|
||||
<filename>/etc/hosts</filename>, and try to resolve hosts or address by using the entries in the file before
|
||||
sending query to DNS servers.</para></listitem>
|
||||
<listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),
|
||||
<command>systemd-resolved</command> will read <filename>/etc/hosts</filename>, and try to resolve
|
||||
hosts or address by using the entries in the file before sending query to DNS servers.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ResolveUnicastSingleLabel=</varname></term>
|
||||
<listitem><para>Takes a boolean argument. When false (the default),
|
||||
<command>systemd-resolved</command> will not resolve A and AAAA queries for single-label names over
|
||||
classic DNS. Note that such names may still be resolved if search domains are specified (see
|
||||
<varname>Domains=</varname> above), or using other mechanisms, in particular via LLMNR or from
|
||||
<filename>/etc/hosts</filename>. When true, queries for single-label names will be forwarded to
|
||||
global DNS servers even if no search domains are defined.
|
||||
</para>
|
||||
|
||||
<para>This option is provided for compatibility with configurations where <emphasis>public DNS
|
||||
servers are not used</emphasis>. Forwarding single-label names to servers not under your control is
|
||||
not standard-conformant, see <ulink
|
||||
url="https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/">IAB
|
||||
Statement</ulink>, and may create a privacy and security risk.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -135,14 +135,16 @@
|
||||
IPv6.</para></listitem>
|
||||
|
||||
<listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or
|
||||
MulticastDNS) for non-synthesized single-label names is only allowed for non-top-level domains. This
|
||||
means that such records can only be resolved when search domains are defined. For any interface which
|
||||
defines search domains, such look-ups are routed to that interface, suffixed with each of the search
|
||||
domains defined on that interface in turn. When global search domains are defined, such look-ups are
|
||||
routed to all interfaces, suffixed by each of the global search domains in turn. The details of which
|
||||
servers are queried and how the final reply is chosen are described below. Note that this means that
|
||||
address queries for single-label names are never sent out to remote DNS servers, and if no search
|
||||
domains are defined, resolution will fail.</para></listitem>
|
||||
MulticastDNS) for non-synthesized single-label names is allowed for non-top-level domains. This means
|
||||
that such records can be resolved when search domains are defined. For any interface which defines
|
||||
search domains, such look-ups are routed to that interface, suffixed with each of the search domains
|
||||
defined on that interface in turn. When global search domains are defined, such look-ups are routed to
|
||||
all interfaces, suffixed by each of the global search domains in turn. Additionally, lookup of
|
||||
single-label names via unicast DNS may be enabled with the
|
||||
<varname>ResolveUnicastSingleLabel=yes</varname> setting. The details of which servers are queried and
|
||||
how the final reply is chosen are described below. Note that this means that address queries for
|
||||
single-label names are never sent out to remote DNS servers by default, and if no search domains are
|
||||
defined, resolution will fail.</para></listitem>
|
||||
|
||||
<listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server
|
||||
configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for
|
||||
|
@ -513,7 +513,7 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
|
||||
}
|
||||
|
||||
static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
|
||||
DnsQueryCandidate *c;
|
||||
_cleanup_(dns_query_candidate_freep) DnsQueryCandidate *c = NULL;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
@ -524,24 +524,21 @@ static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
|
||||
return r;
|
||||
|
||||
/* If this a single-label domain on DNS, we might append a suitable search domain first. */
|
||||
if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 &&
|
||||
dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) {
|
||||
/* OK, we need a search domain now. Let's find one for this scope */
|
||||
if (!FLAGS_SET(q->flags, SD_RESOLVED_NO_SEARCH) &&
|
||||
dns_scope_name_wants_search_domain(s, dns_question_first_name(q->question_idna))) {
|
||||
/* OK, we want a search domain now. Let's find one for this scope */
|
||||
|
||||
r = dns_query_candidate_next_search_domain(c);
|
||||
if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
|
||||
goto fail;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dns_query_candidate_setup_transactions(c);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
TAKE_PTR(c);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dns_query_candidate_free(c);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
|
||||
|
@ -102,6 +102,8 @@ enum {
|
||||
};
|
||||
|
||||
DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_free);
|
||||
|
||||
void dns_query_candidate_notify(DnsQueryCandidate *c);
|
||||
|
||||
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, int family, uint64_t flags);
|
||||
|
@ -619,7 +619,7 @@ DnsScopeMatch dns_scope_good_domain(
|
||||
manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
|
||||
return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
|
||||
* for single-label names, i.e. one label. This is
|
||||
* particular relevant as it means a "." route on some
|
||||
* particularly relevant as it means a "." route on some
|
||||
* other scope won't pull all traffic away from
|
||||
* us. (If people actually want to pull traffic away
|
||||
* from us they should turn off LLMNR on the
|
||||
@ -651,20 +651,21 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
|
||||
|
||||
if (s->protocol == DNS_PROTOCOL_DNS) {
|
||||
|
||||
/* On classic DNS, looking up non-address RRs is always
|
||||
* fine. (Specifically, we want to permit looking up
|
||||
* DNSKEY and DS records on the root and top-level
|
||||
* domains.) */
|
||||
/* On classic DNS, looking up non-address RRs is always fine. (Specifically, we want to
|
||||
* permit looking up DNSKEY and DS records on the root and top-level domains.) */
|
||||
if (!dns_resource_key_is_address(key))
|
||||
return true;
|
||||
|
||||
/* However, we refuse to look up A and AAAA RRs on the
|
||||
* root and single-label domains, under the assumption
|
||||
* that those should be resolved via LLMNR or search
|
||||
* path only, and should not be leaked onto the
|
||||
* internet. */
|
||||
return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
|
||||
dns_name_is_root(dns_resource_key_name(key)));
|
||||
/* Unless explicitly overridden, we refuse to look up A and AAAA RRs on the root and
|
||||
* single-label domains, under the assumption that those should be resolved via LLMNR or
|
||||
* search path only, and should not be leaked onto the internet. */
|
||||
const char* name = dns_resource_key_name(key);
|
||||
|
||||
if (!s->manager->resolve_unicast_single_label &&
|
||||
dns_name_is_single_label(name))
|
||||
return false;
|
||||
|
||||
return !dns_name_is_root(name);
|
||||
}
|
||||
|
||||
/* On mDNS and LLMNR, send A and AAAA queries only on the
|
||||
@ -1169,7 +1170,7 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
|
||||
return s->manager->search_domains;
|
||||
}
|
||||
|
||||
bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
|
||||
bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) {
|
||||
assert(s);
|
||||
|
||||
if (s->protocol != DNS_PROTOCOL_DNS)
|
||||
|
@ -99,7 +99,7 @@ void dns_scope_dump(DnsScope *s, FILE *f);
|
||||
|
||||
DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s);
|
||||
|
||||
bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
|
||||
bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name);
|
||||
|
||||
bool dns_scope_network_good(DnsScope *s);
|
||||
|
||||
|
@ -18,13 +18,14 @@ struct ConfigPerfItem;
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
|
||||
Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
|
||||
Resolve.Domains, config_parse_search_domains, 0, 0
|
||||
Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
|
||||
Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
|
||||
Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
|
||||
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
|
||||
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
|
||||
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
|
||||
Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
|
||||
Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
|
||||
Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
|
||||
Resolve.Domains, config_parse_search_domains, 0, 0
|
||||
Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
|
||||
Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
|
||||
Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
|
||||
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
|
||||
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
|
||||
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
|
||||
Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
|
||||
Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
|
||||
|
@ -70,9 +70,10 @@ struct Manager {
|
||||
LIST_HEAD(DnsSearchDomain, search_domains);
|
||||
unsigned n_search_domains;
|
||||
|
||||
bool need_builtin_fallbacks:1;
|
||||
bool need_builtin_fallbacks;
|
||||
bool read_resolv_conf;
|
||||
bool resolve_unicast_single_label;
|
||||
|
||||
bool read_resolv_conf:1;
|
||||
struct stat resolv_conf_stat;
|
||||
|
||||
DnsTrustAnchor trust_anchor;
|
||||
|
@ -22,3 +22,4 @@
|
||||
#Cache=yes
|
||||
#DNSStubListener=yes
|
||||
#ReadEtcHosts=yes
|
||||
#ResolveUnicastSingleLabel=no
|
||||
|
Loading…
Reference in New Issue
Block a user