mirror of
https://github.com/systemd/systemd.git
synced 2025-03-28 02:50:16 +03:00
resolved: introduce support for per-interface negative trust anchors
This commit is contained in:
parent
bec690501e
commit
8a516214c4
@ -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>
|
||||
|
||||
|
@ -318,6 +318,20 @@
|
||||
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</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>
|
||||
|
@ -123,60 +123,7 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
|
||||
return network_link_get_string(ifindex, "ADMIN_STATE", state);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
|
||||
return network_link_get_string(ifindex, "NETWORK_FILE", filename);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
|
||||
return network_link_get_string(ifindex, "OPER_STATE", state);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
|
||||
return network_link_get_string(ifindex, "LLMNR", llmnr);
|
||||
}
|
||||
|
||||
_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;
|
||||
int r;
|
||||
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(lldp, -EINVAL);
|
||||
|
||||
if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file(p, &s, &size);
|
||||
if (r == -ENOENT)
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (size <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
*lldp = s;
|
||||
s = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
@ -210,24 +157,81 @@ static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
|
||||
return network_link_get_string(ifindex, "ADMIN_STATE", state);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
|
||||
return network_link_get_string(ifindex, "NETWORK_FILE", filename);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
|
||||
return network_link_get_string(ifindex, "OPER_STATE", state);
|
||||
}
|
||||
|
||||
_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
|
||||
return network_link_get_string(ifindex, "LLMNR", llmnr);
|
||||
}
|
||||
|
||||
_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_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;
|
||||
int r;
|
||||
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(lldp, -EINVAL);
|
||||
|
||||
if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file(p, &s, &size);
|
||||
if (r == -ENOENT)
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (size <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
*lldp = s;
|
||||
s = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_network_link_get_timezone(int ifindex, char **ret) {
|
||||
return network_link_get_string(ifindex, "TIMEZONE", ret);
|
||||
}
|
||||
|
||||
_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) {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user