diff options
-rw-r--r-- | man/resolved.conf.xml | 10 | ||||
-rw-r--r-- | man/systemd.network.xml | 18 | ||||
-rw-r--r-- | src/libsystemd/sd-network/sd-network.c | 4 | ||||
-rw-r--r-- | src/network/networkd-link.c | 4 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 1 | ||||
-rw-r--r-- | src/network/networkd-network.c | 1 | ||||
-rw-r--r-- | src/network/networkd-network.h | 1 | ||||
-rw-r--r-- | src/resolve/resolved-conf.c | 35 | ||||
-rw-r--r-- | src/resolve/resolved-dns-dnssec.c | 7 | ||||
-rw-r--r-- | src/resolve/resolved-dns-dnssec.h | 21 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 17 | ||||
-rw-r--r-- | src/resolve/resolved-gperf.gperf | 12 | ||||
-rw-r--r-- | src/resolve/resolved-link.c | 34 | ||||
-rw-r--r-- | src/resolve/resolved-link.h | 1 | ||||
-rw-r--r-- | src/resolve/resolved-manager.c | 6 | ||||
-rw-r--r-- | src/resolve/resolved-manager.h | 1 | ||||
-rw-r--r-- | src/resolve/resolved.c | 6 | ||||
-rw-r--r-- | src/shared/resolve-util.c | 8 | ||||
-rw-r--r-- | src/shared/resolve-util.h | 23 | ||||
-rw-r--r-- | src/systemd/sd-network.h | 10 |
20 files changed, 143 insertions, 77 deletions
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index c2c277b606..3209f73bc1 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -194,6 +194,16 @@ happen regularly. On other systems it is recommended to set <varname>DNSSEC=</varname> to <literal>allow-downgrade</literal>.</para> + + <para>In addition to this global DNSSEC setting + <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> + also maintains per-interface DNSSEC settings. For system DNS + servers (see above), only the global DNSSEC setting is in + effect. For per-interface DNS servers the per-interface + setting is in effect, unless it is unset in which case the + global setting is used instead.</para> + + <para>Defaults to off.</para> </listitem> </varlistentry> diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 36172ae8b5..1dfa559c8b 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -301,6 +301,24 @@ </listitem> </varlistentry> <varlistentry> + <term><varname>DNSSEC=</varname></term> + <listitem> + <para>A boolean or + <literal>allow-downgrade</literal>. When true, enables + <ulink + url="https://tools.ietf.org/html/rfc4033">DNSSEC</ulink> + DNS validation support on the link. When set to + <literal>allow-downgrade</literal>, compatibility with + non-DNSSEC capable networks is increased, by automatically + turning off DNSEC in this case. This option defines a + per-interface setting for + <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>'s + global <varname>DNSSEC=</varname> option. Defaults to + false. This setting is read by + <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> + </listitem> + </varlistentry> + <varlistentry> <term><varname>LLDP=</varname></term> <listitem> <para>A boolean. When true, enables LLDP link receive support. diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index a63ff46c68..517b48a04f 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -143,6 +143,10 @@ _public_ int sd_network_link_get_mdns(int ifindex, char **mdns) { return network_link_get_string(ifindex, "MDNS", mdns); } +_public_ int sd_network_link_get_dnssec(int ifindex, char **dnssec) { + return network_link_get_string(ifindex, "DNSSEC", dnssec); +} + _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { _cleanup_free_ char *s = NULL, *p = NULL; size_t size; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2013a8eae7..18a82fdeb9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2871,6 +2871,10 @@ int link_save(Link *link) { fprintf(f, "MDNS=%s\n", resolve_support_to_string(link->network->mdns)); + if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID) + fprintf(f, "DNSSEC=%s\n", + dnssec_mode_to_string(link->network->dnssec_mode)); + fputs("ADDRESSES=", f); space = false; SET_FOREACH(a, link->addresses, i) { diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index c66ca3c1cc..75a2620804 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -47,6 +47,7 @@ Network.Domains, config_parse_domains, Network.DNS, config_parse_strv, 0, offsetof(Network, dns) Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr) Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns) +Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode) Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 7544280a7a..c91531ca69 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -122,6 +122,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->llmnr = RESOLVE_SUPPORT_YES; network->mdns = RESOLVE_SUPPORT_NO; + network->dnssec_mode = _DNSSEC_MODE_INVALID; network->link_local = ADDRESS_FAMILY_IPV6; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 91e90e6d74..7817b13cc4 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -146,6 +146,7 @@ struct Network { ResolveSupport llmnr; ResolveSupport mdns; + DnssecMode dnssec_mode; LIST_FIELDS(Network, networks); }; diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 6afa61fa56..88df7534c4 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -200,41 +200,6 @@ int config_parse_search_domains( return 0; } -int config_parse_dnssec( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Manager *m = data; - DnssecMode mode; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - - mode = dnssec_mode_from_string(rvalue); - if (mode < 0) { - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNSSEC mode '%s'. Ignoring.", rvalue); - return 0; - } - - mode = r ? DNSSEC_YES : DNSSEC_NO; - } - - m->unicast_scope->dnssec_mode = mode; - return 0; -} - int manager_parse_config_file(Manager *m) { int r; diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index ff571986c0..edbd83ce05 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -1566,13 +1566,6 @@ int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r return 0; } -static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = { - [DNSSEC_NO] = "no", - [DNSSEC_ALLOW_DOWNGRADE] = "allow-downgrade", - [DNSSEC_YES] = "yes", -}; -DEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode); - static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = { [DNSSEC_VALIDATED] = "validated", [DNSSEC_INVALID] = "invalid", diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h index d818d1a906..6977faca75 100644 --- a/src/resolve/resolved-dns-dnssec.h +++ b/src/resolve/resolved-dns-dnssec.h @@ -28,24 +28,6 @@ typedef enum DnssecResult DnssecResult; #include "resolved-dns-answer.h" #include "resolved-dns-rr.h" -enum DnssecMode { - /* No DNSSEC validation is done */ - DNSSEC_NO, - - /* Validate locally, if the server knows DO, but if not, - * don't. Don't trust the AD bit. If the server doesn't do - * DNSSEC properly, downgrade to non-DNSSEC operation. Of - * course, we then are vulnerable to a downgrade attack, but - * that's life and what is configured. */ - DNSSEC_ALLOW_DOWNGRADE, - - /* Insist on DNSSEC server support, and rather fail than downgrading. */ - DNSSEC_YES, - - _DNSSEC_MODE_MAX, - _DNSSEC_MODE_INVALID = -1 -}; - enum DnssecResult { /* These four are returned by dnssec_verify_rrset() */ DNSSEC_VALIDATED, @@ -101,8 +83,5 @@ typedef enum DnssecNsecResult { int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl); -const char* dnssec_mode_to_string(DnssecMode m) _const_; -DnssecMode dnssec_mode_from_string(const char *s) _pure_; - const char* dnssec_result_to_string(DnssecResult m) _const_; DnssecResult dnssec_result_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 13be2a3792..c96bed04b0 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -57,6 +57,23 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int s->family = family; s->resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC; + s->dnssec_mode = _DNSSEC_MODE_INVALID; + + if (protocol == DNS_PROTOCOL_DNS) { + /* Copy DNSSEC mode from the link if it is set there, + * otherwise take the manager's DNSSEC mode. Note that + * we copy this only at scope creation time, and do + * not update it from the on, even if the setting + * changes. */ + + if (l) + s->dnssec_mode = l->dnssec_mode; + if (s->dnssec_mode == _DNSSEC_MODE_INVALID) + s->dnssec_mode = m->dnssec_mode; + if (s->dnssec_mode == _DNSSEC_MODE_INVALID) + s->dnssec_mode = DNSSEC_NO; + } + LIST_PREPEND(scopes, m->dns_scopes, s); dns_scope_llmnr_membership(s, true); diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index fb3fe9cfb1..c5ad04afd7 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -14,9 +14,9 @@ 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, 0, 0 +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) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 8785079de8..50d3f9096b 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -47,6 +47,8 @@ int link_new(Manager *m, Link **ret, int ifindex) { l->ifindex = ifindex; l->llmnr_support = RESOLVE_SUPPORT_YES; + l->mdns_support = RESOLVE_SUPPORT_NO; + l->dnssec_mode = _DNSSEC_MODE_INVALID; r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) @@ -273,6 +275,33 @@ clear: return r; } +static int link_update_dnssec_mode(Link *l) { + _cleanup_free_ char *m = NULL; + int r; + + assert(l); + + r = sd_network_link_get_dnssec(l->ifindex, &m); + if (r == -ENODATA) { + r = 0; + goto clear; + } + if (r < 0) + goto clear; + + l->dnssec_mode = dnssec_mode_from_string(m); + if (l->dnssec_mode < 0) { + r = -EINVAL; + goto clear; + } + + return 0; + +clear: + l->dnssec_mode = _DNSSEC_MODE_INVALID; + return r; +} + static int link_update_search_domains(Link *l) { _cleanup_strv_free_ char **domains = NULL; char **i; @@ -332,12 +361,15 @@ int link_update_monitor(Link *l) { if (r < 0) log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name); - link_allocate_scopes(l); + r = link_update_dnssec_mode(l); + if (r < 0) + log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name); r = link_update_search_domains(l); if (r < 0) log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name); + link_allocate_scopes(l); link_add_rrs(l, false); return 0; diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index bb3fe8ebff..d17b57253b 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -69,6 +69,7 @@ struct Link { ResolveSupport llmnr_support; ResolveSupport mdns_support; + DnssecMode dnssec_mode; DnsScope *unicast_scope; DnsScope *llmnr_ipv4_scope; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index ed1ac8286f..b32bad456b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -477,6 +477,8 @@ int manager_new(Manager **ret) { m->hostname_fd = -1; m->llmnr_support = RESOLVE_SUPPORT_YES; + m->mdns_support = RESOLVE_SUPPORT_NO; + m->dnssec_mode = DNSSEC_NO; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; @@ -484,6 +486,10 @@ int manager_new(Manager **ret) { if (r < 0) return r; + r = manager_parse_config_file(m); + if (r < 0) + return r; + r = sd_event_default(&m->event); if (r < 0) return r; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index d61804fff2..1907d2e1bc 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -47,6 +47,7 @@ struct Manager { ResolveSupport llmnr_support; ResolveSupport mdns_support; + DnssecMode dnssec_mode; /* Network */ Hashmap *links; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index be406b71fe..472bb32764 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -81,12 +81,6 @@ int main(int argc, char *argv[]) { goto finish; } - r = manager_parse_config_file(m); - if (r < 0) { - log_error_errno(r, "Failed to parse configuration file: %m"); - goto finish; - } - r = manager_start(m); if (r < 0) { log_error_errno(r, "Failed to start manager: %m"); diff --git a/src/shared/resolve-util.c b/src/shared/resolve-util.c index 487de3e077..bf6fc26841 100644 --- a/src/shared/resolve-util.c +++ b/src/shared/resolve-util.c @@ -24,6 +24,7 @@ #include "string-table.h" DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_support, resolve_support, ResolveSupport, "Failed to parse resolve support setting"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_dnssec_mode, dnssec_mode, DnssecMode, "Failed to parse DNSSEC mode setting"); static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { [RESOLVE_SUPPORT_NO] = "no", @@ -31,3 +32,10 @@ static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { [RESOLVE_SUPPORT_RESOLVE] = "resolve", }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(resolve_support, ResolveSupport, RESOLVE_SUPPORT_YES); + +static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = { + [DNSSEC_NO] = "no", + [DNSSEC_ALLOW_DOWNGRADE] = "allow-downgrade", + [DNSSEC_YES] = "yes", +}; +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dnssec_mode, DnssecMode, DNSSEC_YES); diff --git a/src/shared/resolve-util.h b/src/shared/resolve-util.h index e585c5024f..fd93a13f73 100644 --- a/src/shared/resolve-util.h +++ b/src/shared/resolve-util.h @@ -24,6 +24,7 @@ #include "macro.h" typedef enum ResolveSupport ResolveSupport; +typedef enum DnssecMode DnssecMode; enum ResolveSupport { RESOLVE_SUPPORT_NO, @@ -33,7 +34,29 @@ enum ResolveSupport { _RESOLVE_SUPPORT_INVALID = -1 }; +enum DnssecMode { + /* No DNSSEC validation is done */ + DNSSEC_NO, + + /* Validate locally, if the server knows DO, but if not, + * don't. Don't trust the AD bit. If the server doesn't do + * DNSSEC properly, downgrade to non-DNSSEC operation. Of + * course, we then are vulnerable to a downgrade attack, but + * that's life and what is configured. */ + DNSSEC_ALLOW_DOWNGRADE, + + /* Insist on DNSSEC server support, and rather fail than downgrading. */ + DNSSEC_YES, + + _DNSSEC_MODE_MAX, + _DNSSEC_MODE_INVALID = -1 +}; + int config_parse_resolve_support(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dnssec_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); const char* resolve_support_to_string(ResolveSupport p) _const_; ResolveSupport resolve_support_from_string(const char *s) _pure_; + +const char* dnssec_mode_to_string(DnssecMode p) _const_; +DnssecMode dnssec_mode_from_string(const char *s) _pure_; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 6765be041b..00aaa102ce 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -111,13 +111,21 @@ int sd_network_link_get_ntp(int ifindex, char ***addr); */ int sd_network_link_get_llmnr(int ifindex, char **llmnr); -/* Indicates whether or not MDNS should be enabled for the link +/* Indicates whether or not MulticastDNS should be enabled for the + * link. * Possible levels of support: yes, no, resolve * Possible return codes: * -ENODATA: networkd is not aware of the link */ int sd_network_link_get_mdns(int ifindex, char **mdns); +/* Indicates whether or not DNSSEC should be enabled for the link + * Possible levels of support: yes, no, allow-downgrade + * Possible return codes: + * -ENODATA: networkd is not aware of the link + */ +int sd_network_link_get_dnssec(int ifindex, char **dnssec); + int sd_network_link_get_lldp(int ifindex, char **lldp); /* Get the DNS domain names for a given link. */ |