1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-27 18:55:40 +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:
Lennart Poettering 2016-01-05 19:57:33 +01:00
parent 125ae29d1b
commit ad6c047561
20 changed files with 143 additions and 77 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -146,6 +146,7 @@ struct Network {
ResolveSupport llmnr;
ResolveSupport mdns;
DnssecMode dnssec_mode;
LIST_FIELDS(Network, networks);
};

View File

@ -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;

View File

@ -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",

View File

@ -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_;

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -69,6 +69,7 @@ struct Link {
ResolveSupport llmnr_support;
ResolveSupport mdns_support;
DnssecMode dnssec_mode;
DnsScope *unicast_scope;
DnsScope *llmnr_ipv4_scope;

View File

@ -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;

View File

@ -47,6 +47,7 @@ struct Manager {
ResolveSupport llmnr_support;
ResolveSupport mdns_support;
DnssecMode dnssec_mode;
/* Network */
Hashmap *links;

View File

@ -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");

View File

@ -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);

View File

@ -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_;

View File

@ -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. */