summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-01-06 18:36:32 +0100
committerLennart Poettering <lennart@poettering.net>2016-01-06 18:36:32 +0100
commit8a516214c4412e8a40544bd725a6d499a30cbbbf (patch)
treed8e7504d9da15641f03f7b4ca82dd3fc612544ed
parentbec690501ed544199e72a292fbd6d28bc1e1727e (diff)
resolved: introduce support for per-interface negative trust anchors
-rw-r--r--man/dnssec-trust-anchors.d.xml9
-rw-r--r--man/systemd.network.xml14
-rw-r--r--src/libsystemd/sd-network/sd-network.c82
-rw-r--r--src/network/networkd-link.c15
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c55
-rw-r--r--src/network/networkd-network.h2
-rw-r--r--src/resolve/resolved-dns-transaction.c29
-rw-r--r--src/resolve/resolved-link.c43
-rw-r--r--src/resolve/resolved-link.h1
-rw-r--r--src/systemd/sd-network.h6
11 files changed, 211 insertions, 46 deletions
diff --git a/man/dnssec-trust-anchors.d.xml b/man/dnssec-trust-anchors.d.xml
index 5f15d7cd59..51271abc16 100644
--- a/man/dnssec-trust-anchors.d.xml
+++ b/man/dnssec-trust-anchors.d.xml
@@ -179,6 +179,12 @@
<para>If no negative trust anchor files are configured a built-in
set of well-known private DNS zone domains is used as negative
trust anchors.</para>
+
+ <para>It is also possibly to define per-interface negative trust
+ anchors using the <varname>DNSSECNegativeTrustAnchors=</varname>
+ setting in
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ files.</para>
</refsect1>
<refsect1>
@@ -186,7 +192,8 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 1dfa559c8b..5a6383cfc2 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -319,6 +319,20 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>DNSSECNegativeTrustAnchors=</varname></term>
+ <listitem><para>A space-separated list of DNSSEC negative
+ trust anchor domains. If specified and DNSSEC is enabled,
+ look-ups done via the interface's DNS server will be subject
+ to the list of negative trust anchors, and not require
+ authentication for the specified domains, or anything below
+ it. Use this to disable DNSSEC authentication for specific
+ private domains, that cannot be proven valid using the
+ Internet DNS hierarchy. Defaults to the empty list. 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 517b48a04f..c1f5867ee4 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -123,6 +123,40 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) {
return 0;
}
+static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
+ _cleanup_free_ char *p = NULL, *s = NULL;
+ _cleanup_strv_free_ char **a = NULL;
+ int r;
+
+ assert_return(ifindex > 0, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
+ return -ENOMEM;
+
+ r = parse_env_file(p, NEWLINE, key, &s, NULL);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+ if (isempty(s)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ a = strv_split(s, " ");
+ if (!a)
+ return -ENOMEM;
+
+ strv_uniq(a);
+ r = strv_length(a);
+
+ *ret = a;
+ a = NULL;
+
+ return r;
+}
+
_public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "ADMIN_STATE", state);
}
@@ -147,6 +181,10 @@ _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_dnssec_negative_trust_anchors(int ifindex, char ***nta) {
+ return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
+}
+
_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
_cleanup_free_ char *s = NULL, *p = NULL;
size_t size;
@@ -176,58 +214,24 @@ int sd_network_link_get_timezone(int ifindex, char **ret) {
return network_link_get_string(ifindex, "TIMEZONE", ret);
}
-static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
- _cleanup_free_ char *p = NULL, *s = NULL;
- _cleanup_strv_free_ char **a = NULL;
- int r;
-
- assert_return(ifindex > 0, -EINVAL);
- assert_return(ret, -EINVAL);
-
- if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
- return -ENOMEM;
-
- r = parse_env_file(p, NEWLINE, key, &s, NULL);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
- if (isempty(s)) {
- *ret = NULL;
- return 0;
- }
-
- a = strv_split(s, " ");
- if (!a)
- return -ENOMEM;
-
- strv_uniq(a);
- r = strv_length(a);
-
- *ret = a;
- a = NULL;
-
- return r;
-}
-
_public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
- return network_get_link_strv("DNS", ifindex, ret);
+ return network_link_get_strv(ifindex, "DNS", ret);
}
_public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
- return network_get_link_strv("NTP", ifindex, ret);
+ return network_link_get_strv(ifindex, "NTP", ret);
}
_public_ int sd_network_link_get_domains(int ifindex, char ***ret) {
- return network_get_link_strv("DOMAINS", ifindex, ret);
+ return network_link_get_strv(ifindex, "DOMAINS", ret);
}
_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
- return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret);
+ return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret);
}
_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
- return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret);
+ return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
}
_public_ int sd_network_link_get_wildcard_domain(int ifindex) {
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 18a82fdeb9..4a807bacc3 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -2875,6 +2875,20 @@ int link_save(Link *link) {
fprintf(f, "DNSSEC=%s\n",
dnssec_mode_to_string(link->network->dnssec_mode));
+ if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
+ const char *n;
+
+ fputs("DNSSEC_NTA=", f);
+ space = false;
+ SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i) {
+ if (space)
+ fputc(' ', f);
+ fputs(n, f);
+ space = true;
+ }
+ fputc('\n', f);
+ }
+
fputs("ADDRESSES=", f);
space = false;
SET_FOREACH(a, link->addresses, i) {
@@ -2887,7 +2901,6 @@ int link_save(Link *link) {
fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
space = true;
}
-
fputc('\n', f);
fputs("ROUTES=", f);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 75a2620804..2f2a36ccca 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -48,6 +48,7 @@ Network.DNS, config_parse_strv,
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.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, offsetof(Network, dnssec_negative_trust_anchors)
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 c91531ca69..c11cb3dcb3 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -32,6 +32,7 @@
#include "networkd-network.h"
#include "networkd.h"
#include "parse-util.h"
+#include "set.h"
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
@@ -277,6 +278,8 @@ void network_free(Network *network) {
free(network->dhcp_server_dns);
free(network->dhcp_server_ntp);
+ set_free_free(network->dnssec_negative_trust_anchors);
+
free(network);
}
@@ -910,3 +913,55 @@ int config_parse_dhcp_server_ntp(
n->dhcp_server_ntp = m;
}
}
+
+int config_parse_dnssec_negative_trust_anchors(
+ 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 *p = rvalue;
+ Network *n = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ r = dns_name_is_valid(w);
+ if (r <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
+ continue;
+ }
+
+ r = set_put(n->dnssec_negative_trust_anchors, w);
+ if (r < 0)
+ return log_oom();
+ if (r > 0)
+ w = NULL;
+ }
+
+ return 0;
+}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 7817b13cc4..b07fa41abc 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -147,6 +147,7 @@ struct Network {
ResolveSupport llmnr;
ResolveSupport mdns;
DnssecMode dnssec_mode;
+ Set *dnssec_negative_trust_anchors;
LIST_FIELDS(Network, networks);
};
@@ -173,6 +174,7 @@ int config_parse_hostname(const char *unit, const char *filename, unsigned line,
int config_parse_timezone(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_dhcp_server_dns(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_dhcp_server_ntp(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_negative_trust_anchors(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);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(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);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 8631afadb2..f5171a940f 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -1406,6 +1406,25 @@ static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags
return false;
}
+static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) {
+ int r;
+
+ assert(t);
+
+ /* Check whether the specified name is in the the NTA
+ * database, either in the global one, or the link-local
+ * one. */
+
+ r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, name);
+ if (r != 0)
+ return r;
+
+ if (!t->scope->link)
+ return 0;
+
+ return set_contains(t->scope->link->dnssec_negative_trust_anchors, name);
+}
+
static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) {
int r;
@@ -1422,7 +1441,7 @@ static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) {
/* Is this key explicitly listed as a negative trust anchor?
* If so, it's nothing we need to care about */
- r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -1513,7 +1532,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
continue;
/* If this RR is in the negative trust anchor, we don't need to validate it. */
- r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -1863,7 +1882,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dns_type_is_pseudo(rr->key->type))
return -EINVAL;
- r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -2066,7 +2085,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dns_type_is_pseudo(t->key->type))
return -EINVAL;
- r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -2135,7 +2154,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
* the specified RRset is authenticated (i.e. has a matching
* DS RR). */
- r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
if (r < 0)
return r;
if (r > 0)
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 50d3f9096b..30838ef8cc 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -82,6 +82,8 @@ Link *link_free(Link *l) {
dns_scope_free(l->mdns_ipv4_scope);
dns_scope_free(l->mdns_ipv6_scope);
+ set_free_free(l->dnssec_negative_trust_anchors);
+
free(l);
return NULL;
}
@@ -302,6 +304,43 @@ clear:
return r;
}
+static int link_update_dnssec_negative_trust_anchors(Link *l) {
+ _cleanup_strv_free_ char **ntas = NULL;
+ _cleanup_set_free_free_ Set *ns = NULL;
+ char **i;
+ int r;
+
+ assert(l);
+
+ r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
+ if (r == -ENODATA) {
+ r = 0;
+ goto clear;
+ }
+ if (r < 0)
+ goto clear;
+
+ ns = set_new(&dns_name_hash_ops);
+ if (!ns)
+ return -ENOMEM;
+
+ STRV_FOREACH(i, ntas) {
+ r = set_put_strdup(ns, *i);
+ if (r < 0)
+ return r;
+ }
+
+ set_free_free(l->dnssec_negative_trust_anchors);
+ l->dnssec_negative_trust_anchors = ns;
+ ns = NULL;
+
+ return 0;
+
+clear:
+ l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
+ return r;
+}
+
static int link_update_search_domains(Link *l) {
_cleanup_strv_free_ char **domains = NULL;
char **i;
@@ -365,6 +404,10 @@ int link_update_monitor(Link *l) {
if (r < 0)
log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
+ r = link_update_dnssec_negative_trust_anchors(l);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read DNSSEC negative trust anchors 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);
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index d17b57253b..db0e51da04 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -70,6 +70,7 @@ struct Link {
ResolveSupport llmnr_support;
ResolveSupport mdns_support;
DnssecMode dnssec_mode;
+ Set *dnssec_negative_trust_anchors;
DnsScope *unicast_scope;
DnsScope *llmnr_ipv4_scope;
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 00aaa102ce..653c61a162 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -126,6 +126,12 @@ int sd_network_link_get_mdns(int ifindex, char **mdns);
*/
int sd_network_link_get_dnssec(int ifindex, char **dnssec);
+/* Returns the list of per-interface DNSSEC negative trust anchors
+ * Possible return codes:
+ * -ENODATA: networkd is not aware of the link, or has no such data
+ */
+int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta);
+
int sd_network_link_get_lldp(int ifindex, char **lldp);
/* Get the DNS domain names for a given link. */