mirror of
https://github.com/systemd/systemd.git
synced 2025-03-25 18:50:18 +03:00
resolved,networkd: add a per-interface DNSSEC setting
This adds a DNSSEC= setting to .network files, and makes resolved honour them.
This commit is contained in:
parent
125ae29d1b
commit
ad6c047561
@ -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>
|
||||
|
||||
|
@ -300,6 +300,24 @@
|
||||
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</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>
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -146,6 +146,7 @@ struct Network {
|
||||
|
||||
ResolveSupport llmnr;
|
||||
ResolveSupport mdns;
|
||||
DnssecMode dnssec_mode;
|
||||
|
||||
LIST_FIELDS(Network, networks);
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -69,6 +69,7 @@ struct Link {
|
||||
|
||||
ResolveSupport llmnr_support;
|
||||
ResolveSupport mdns_support;
|
||||
DnssecMode dnssec_mode;
|
||||
|
||||
DnsScope *unicast_scope;
|
||||
DnsScope *llmnr_ipv4_scope;
|
||||
|
@ -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;
|
||||
|
@ -47,6 +47,7 @@ struct Manager {
|
||||
|
||||
ResolveSupport llmnr_support;
|
||||
ResolveSupport mdns_support;
|
||||
DnssecMode dnssec_mode;
|
||||
|
||||
/* Network */
|
||||
Hashmap *links;
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user