From 61ecb465b1c803316cb55bae0c2d7cf3c0008589 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 18:40:02 +0100 Subject: resolved: turn on DNSSEC by default, unless configured otherwise Let's make sure DNSSEC gets more testing, by defaulting DNSSEC to "allow-downgrade" mode. Since distros should probably not ship DNSSEC enabled by default add a configure switch to disable this again. DNSSEC in "allow-downgrade" mode should mostly work without affecting user experience. There's one exception: some captive portal systems rewrite DNS in order to redirect HTTP traffic to the captive portal. If these systems implement DNS servers that are otherwise DNSSEC-capable (which in fact is pretty unlikely, but still...), then this will result in the captive portal being inaccessible. To fix this support in NetworkManager (or any other network management solution that does captive portal detection) is required, which simply turns off DNSSEC during the captive portal detection, and resets it back to the default (i.e. on) after captive portal authentication is complete. --- Makefile.am | 1 + NEWS | 17 +++++++++++++++++ configure.ac | 19 +++++++++++++++++-- src/resolve/resolved-manager.c | 2 +- src/resolve/resolved.conf.in | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 9bc0bf2c05..8c151f538f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5759,6 +5759,7 @@ substitutions = \ '|PYTHON=$(PYTHON)|' \ '|NTP_SERVERS=$(NTP_SERVERS)|' \ '|DNS_SERVERS=$(DNS_SERVERS)|' \ + '|DEFAULT_DNSSEC_MODE=$(DEFAULT_DNSSEC_MODE)|' \ '|systemuidmax=$(SYSTEM_UID_MAX)|' \ '|systemgidmax=$(SYSTEM_GID_MAX)|' \ '|TTY_GID=$(TTY_GID)|' \ diff --git a/NEWS b/NEWS index 80e59c53d3..0cce79443b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,23 @@ systemd System and Service Manager CHANGES WITH 230 in spe: + * DNSSEC is now turned on by default in systemd-resolved (in + "allow-downgrade" mode), but may be turned off during compile time by + passing "--with-default-dnssec=no" to "configure" (and of course, + during runtime with DNSSEC= in resolved.conf). We recommend + downstreams to leave this on at least during development cycles and + report any issues with the DNSSEC logic upstream. We are very + interested in collecting feedback about the DNSSEC validator and its + limitations in the wild. Note however, that DNSSEC support is + probably nothing downstreams should turn on in stable distros just + yet, as it might create incompabilities with a few DNS servers and + networks. We tried hard to make sure we downgrade to non-DNSSEC mode + automatically whenever we detect such incompatible setups, but there + might be systems we do not cover yet. Hence: please help us testing + the DNSSEC code, leave this on where you can, report back, but then + again don't consider turning this on in your stable, LTS or + production release just yet. + * Testing tool /usr/lib/systemd/systemd-activate is renamed to systemd-socket-activate and installed into /usr/bin. It is now fully supported. diff --git a/configure.ac b/configure.ac index 262f9e4fff..e72470a199 100644 --- a/configure.ac +++ b/configure.ac @@ -1128,6 +1128,20 @@ AC_ARG_WITH(dns-servers, AC_DEFINE_UNQUOTED(DNS_SERVERS, ["$DNS_SERVERS"], [Default DNS Servers]) AC_SUBST(DNS_SERVERS) +AC_ARG_WITH(default-dnssec, + AS_HELP_STRING([--with-default-dnssec=MODE], + [Default DNSSEC mode, defaults to "allow-downgrade"]), + [DEFAULT_DNSSEC_MODE="$withval"], + [DEFAULT_DNSSEC_MODE="allow-downgrade"]) + +AS_CASE("x${DEFAULT_DNSSEC_MODE}", + [xno], [mode=DNSSEC_NO], + [xyes], [mode=DNSSEC_YES], + [xallow-downgrade], [mode=DNSSEC_ALLOW_DOWNGRADE], + AC_MSG_ERROR(Bad DNSSEC mode ${DEFAULT_DNSSEC_MODE})) +AC_DEFINE_UNQUOTED(DEFAULT_DNSSEC_MODE, [$mode], [Default DNSSEC mode]) +AC_SUBST(DEFAULT_DNSSEC_MODE) + # ------------------------------------------------------------------------------ have_networkd=no AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd])) @@ -1559,12 +1573,13 @@ AC_MSG_RESULT([ hostnamed: ${have_hostnamed} timedated: ${have_timedated} timesyncd: ${have_timesyncd} - default NTP servers: ${NTP_SERVERS} + Default NTP servers: ${NTP_SERVERS} time epoch: ${TIME_EPOCH} localed: ${have_localed} networkd: ${have_networkd} resolved: ${have_resolved} - default DNS servers: ${DNS_SERVERS} + Default DNS servers: ${DNS_SERVERS} + Default DNSSEC mode: ${DEFAULT_DNSSEC_MODE} coredump: ${have_coredump} polkit: ${have_polkit} efi: ${have_efi} diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index bf5efe4cfa..09e15fa230 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -485,7 +485,7 @@ int manager_new(Manager **ret) { m->llmnr_support = RESOLVE_SUPPORT_YES; m->mdns_support = RESOLVE_SUPPORT_NO; - m->dnssec_mode = DNSSEC_NO; + m->dnssec_mode = DEFAULT_DNSSEC_MODE; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index efc9c6733a..a288588924 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -16,4 +16,4 @@ #FallbackDNS=@DNS_SERVERS@ #Domains= #LLMNR=yes -#DNSSEC=no +#DNSSEC=@DEFAULT_DNSSEC_MODE@ -- cgit v1.2.3-54-g00ecf From de085700502b372767fa4c83b91a02522e198897 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 19:06:01 +0100 Subject: build-sys: fix type detection Before this patch existence of char16_t, char32_t, key_serial_t was checked with AC_CHECK_DECLS() which doesn't actually work for types. Correct this to use AC_CHECK_TYPES() instead. Also, while we are at it, change the check for memfd_create() to use AC_CHECK_DECLS() instead of AC_CHECK_FUNCS(). This is a better choice, since a couple of syscalls are defined by glibc but not exported in the header files (pivot_root() for example), and we hence should probably be more picky with memfd_create() too, which glibc might decide to expose one day, but not necessarily in the headers too. --- configure.ac | 9 ++++++--- src/basic/missing.h | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index e72470a199..614f0553b8 100644 --- a/configure.ac +++ b/configure.ac @@ -295,10 +295,8 @@ CAP_LIBS="$LIBS" LIBS="$save_LIBS" AC_SUBST(CAP_LIBS) -AC_CHECK_FUNCS([memfd_create]) AC_CHECK_FUNCS([__secure_getenv secure_getenv]) -AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, - kcmp, keyctl, key_serial_t, char16_t, char32_t, LO_FLAGS_PARTSCAN], +AC_CHECK_DECLS([memfd_create, gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, LO_FLAGS_PARTSCAN], [], [], [[ #include #include @@ -309,6 +307,11 @@ AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renamea #include ]]) +AC_CHECK_TYPES([char16_t, char32_t, key_serial_t], + [], [], [[ +#include +]]) + AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IFLA_MACVLAN_FLAGS, IFLA_IPVLAN_MODE, diff --git a/src/basic/missing.h b/src/basic/missing.h index 4d3764c022..f3d32362bd 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -167,7 +167,7 @@ static inline int pivot_root(const char *new_root, const char *put_old) { # endif #endif -#ifndef HAVE_MEMFD_CREATE +#if !HAVE_DECL_MEMFD_CREATE static inline int memfd_create(const char *name, unsigned int flags) { return syscall(__NR_memfd_create, name, flags); } @@ -1089,7 +1089,7 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns #define INPUT_PROP_ACCELEROMETER 0x06 #endif -#if !HAVE_DECL_KEY_SERIAL_T +#ifndef HAVE_KEY_SERIAL_T typedef int32_t key_serial_t; #endif @@ -1160,11 +1160,11 @@ static inline key_serial_t request_key(const char *type, const char *description #ifndef IF_OPER_UP #define IF_OPER_UP 6 -#ifndef HAVE_DECL_CHAR32_T +#ifndef HAVE_CHAR32_T #define char32_t uint32_t #endif -#ifndef HAVE_DECL_CHAR16_T +#ifndef HAVE_CHAR16_T #define char16_t uint16_t #endif -- cgit v1.2.3-54-g00ecf From 9dc907f9c93636cb63ca90300fa3b8c03812701f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 19:11:18 +0100 Subject: networkd: rework idle detection logic of networkd This patch makes networkd stay around as long as there is more than just a loopback interface around, or the loopback device isn't fully probed yet, or the loopback device has a .network file attached. In essence, this means networkd stays around now continously as it should, unless it is running in some (container?) environment that really has no interface except a loopback device. Fixes #2577. --- src/network/networkd-manager.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b527191a5a..b8cb7f875d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1091,22 +1091,19 @@ static bool manager_check_idle(void *userdata) { assert(m); + /* Check whether we are idle now. The only case when we decide to be idle is when there's only a loopback + * device around, for which we have no configuration, and which already left the PENDING state. In all other + * cases we are not idle. */ + HASHMAP_FOREACH(link, m->links, i) { - /* we are not woken on udev activity, so let's just wait for the - * pending udev event */ + /* We are not woken on udev activity, so let's just wait for the pending udev event */ if (link->state == LINK_STATE_PENDING) return false; - if (!link->network) - continue; + if ((link->flags & IFF_LOOPBACK) == 0) + return false; - /* we are not woken on netork activity, so let's stay around */ - if (link_lldp_enabled(link) || - link_ipv4ll_enabled(link) || - link_dhcp4_server_enabled(link) || - link_dhcp4_enabled(link) || - link_dhcp6_enabled(link) || - link_ipv6_accept_ra_enabled(link)) + if (link->network) return false; } -- cgit v1.2.3-54-g00ecf From 41815a4aa66c59070dc86aa99eebfa720e8a263e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 21:25:33 +0100 Subject: resolve: print a noisy warning if we show crypto keys that could not be authenticated Doing DNS retrieval on non-authenticated crypt keys is useless, hence warn loudly about it. --- src/resolve/dns-type.c | 17 +++++++++++++++++ src/resolve/dns-type.h | 1 + src/resolve/resolve-tool.c | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index b2f479cae5..78d9d5733f 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -193,6 +193,23 @@ bool dns_type_is_obsolete(uint16_t type) { DNS_TYPE_NULL); } +bool dns_type_needs_authentication(uint16_t type) { + + /* Returns true for all (non-obsolete) RR types where records are not useful if they aren't + * authenticated. I.e. everything that contains crypto keys. */ + + return IN_SET(type, + DNS_TYPE_CERT, + DNS_TYPE_SSHFP, + DNS_TYPE_IPSECKEY, + DNS_TYPE_DS, + DNS_TYPE_DNSKEY, + DNS_TYPE_TLSA, + DNS_TYPE_CDNSKEY, + DNS_TYPE_OPENPGPKEY, + DNS_TYPE_CAA); +} + int dns_type_to_af(uint16_t t) { switch (t) { diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index f18ac6eef3..fb7babf12a 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -132,6 +132,7 @@ bool dns_type_is_dnssec(uint16_t type); bool dns_type_is_obsolete(uint16_t type); bool dns_type_may_wildcard(uint16_t type); bool dns_type_apex_only(uint16_t type); +bool dns_type_needs_authentication(uint16_t type); int dns_type_to_af(uint16_t t); bool dns_class_is_pseudo(uint16_t class); diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 9aade8e490..c1be03fbb2 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -339,6 +339,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ uint64_t flags; int r; usec_t ts; + bool needs_authentication = false; assert(name); @@ -421,6 +422,10 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + + if (dns_type_needs_authentication(t)) + needs_authentication = true; + n++; } if (r < 0) @@ -441,6 +446,18 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ print_source(flags, ts); + if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) { + fflush(stdout); + + fprintf(stderr, "\n%s" + "WARNING: The resources shown contain cryptographic key data which could not be\n" + " authenticated. It is not suitable to authenticate any communication.\n" + " This is usually indication that DNSSEC authentication was not enabled\n" + " or is not available for the selected protocol or DNS servers.%s\n", + ansi_highlight_red(), + ansi_normal()); + } + return 0; } -- cgit v1.2.3-54-g00ecf From 3f51aec8647fe13f4b1e46b2f75ff635403adf91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 13:18:36 +0100 Subject: core: fix assertion check Fixes: #2632 --- src/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/timer.c b/src/core/timer.c index 6f3e6a8db3..3d0bae16e5 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) { usec_t add; assert(t); - assert(*v); + assert(v); if (t->random_usec == 0) return; -- cgit v1.2.3-54-g00ecf From 6d2353394fc33e923d1ab464c8f88df2a5105ffb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 14:03:47 +0100 Subject: udev: fix cg_unified() return code checking Fixes fall-out from 8b3aa503c171acdb9ec63484a8c50e2680d31e79. Fixes: #2635 --- src/udev/udevd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 2c1c4a967b..bb92f16352 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1715,7 +1715,7 @@ int main(int argc, char *argv[]) { by PID1. otherwise we are not guaranteed to have a dedicated cgroup */ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup); if (r < 0) { - if (r == -ENOENT || r == -ENOEXEC) + if (r == -ENOENT || r == -ENOMEDIUM) log_debug_errno(r, "did not find dedicated cgroup: %m"); else log_warning_errno(r, "failed to get cgroup: %m"); -- cgit v1.2.3-54-g00ecf From c77d26122a35a8555953bbe71e4a4ff664f3462c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 14:17:53 +0100 Subject: resolved: make sure to normalize all domain names returned via the bus Most domain names we deal with are normalized anyway (since we read them that way from DNS packets), but some might not (because they are synthesized from unnormalized configuration or so), hence make sure to normalize all names before passing them out to clients, to be fully deterministic. Note that internally we are process normalized and non-normalized names the same way, and while comparing them ignore the differences due to unnormalized names. However, that internal implementation detail really shouldn't spill out the clients, hence make sure to clean it all up. --- src/resolve/resolved-bus.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6f08c43327..2d94baeb7e 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -140,6 +140,7 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin static void bus_method_resolve_hostname_complete(DnsQuery *q) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *normalized = NULL; DnsResourceRecord *rr; unsigned added = 0; int ifindex, r; @@ -199,11 +200,17 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { if (r < 0) goto finish; + /* The key names are not necessarily normalized, make sure that they are when we return them to our bus + * clients. */ + r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + if (r < 0) + goto finish; + /* Return the precise spelling and uppercasing and CNAME target reported by the server */ assert(canonical); r = sd_bus_message_append( reply, "st", - DNS_RESOURCE_KEY_NAME(canonical->key), + normalized, SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); if (r < 0) goto finish; @@ -395,13 +402,19 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { question = dns_query_question_for_protocol(q, q->answer_protocol); DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + _cleanup_free_ char *normalized = NULL; + r = dns_question_matches_rr(question, rr, NULL); if (r < 0) goto finish; if (r == 0) continue; - r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name); + r = dns_name_normalize(rr->ptr.name, &normalized); + if (r < 0) + goto finish; + + r = sd_bus_message_append(reply, "(is)", ifindex, normalized); if (r < 0) goto finish; @@ -671,6 +684,7 @@ fail: static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_free_ char *normalized = NULL; DnsQuery *aux; int r; @@ -727,10 +741,14 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) if (r < 0) return r; + r = dns_name_normalize(rr->srv.name, &normalized); + if (r < 0) + return r; + r = sd_bus_message_append( reply, "qqqs", - rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name); + rr->srv.priority, rr->srv.weight, rr->srv.port, normalized); if (r < 0) return r; @@ -776,9 +794,17 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) if (r < 0) return r; + if (canonical) { + normalized = mfree(normalized); + + r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + if (r < 0) + return r; + } + /* Note that above we appended the hostname as encoded in the * SRV, and here the canonical hostname this maps to. */ - r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name); + r = sd_bus_message_append(reply, "s", normalized); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf