]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: add a simple trust anchor database as additional RR source
authorLennart Poettering <lennart@poettering.net>
Thu, 3 Dec 2015 17:31:24 +0000 (18:31 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 3 Dec 2015 20:17:49 +0000 (21:17 +0100)
When doing DNSSEC lookups we need to know one or more DS or DNSKEY RRs
as trust anchors to validate lookups. With this change we add a
compiled-in trust anchor database, serving the root DS key as of today,
retrieved from:

https://data.iana.org/root-anchors/root-anchors.xml

The interface is kept generic, so that additional DS or DNSKEY RRs may
be served via the same interface, for example by provisioning them
locally in external files to support "islands" of security.

The trust anchor database becomes the fourth source of RRs we maintain,
besides, the network, the local cache, and the local zone.

Makefile.am
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-transaction.h
src/resolve/resolved-dns-trust-anchor.c [new file with mode: 0644]
src/resolve/resolved-dns-trust-anchor.h [new file with mode: 0644]
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

index edae4a309b726e74078f9851730d1262ef1a8803..db916f72c521252054c06353da9d1a3f0d4071e0 100644 (file)
@@ -5184,6 +5184,8 @@ systemd_resolved_SOURCES = \
        src/resolve/resolved-dns-stream.c \
        src/resolve/resolved-dns-dnssec.h \
        src/resolve/resolved-dns-dnssec.c \
+       src/resolve/resolved-dns-trust-anchor.h \
+       src/resolve/resolved-dns-trust-anchor.c \
        src/resolve/dns-type.c \
        src/resolve/dns-type.h
 
index 90133cb3327b06ed52519b23558f150f3073cbd0..7bef4be2ad0ea313e3426a5ec6c152c47b1b9aeb 100644 (file)
@@ -675,7 +675,20 @@ int dns_transaction_go(DnsTransaction *t) {
         t->answer_rcode = 0;
         t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID;
 
-        /* Check the zone, but obly if this transaction is not used
+        /* Check the trust anchor. Do so only on classic DNS, since DNSSEC does not apply otherwise. */
+        if (t->scope->protocol == DNS_PROTOCOL_DNS) {
+                r = dns_trust_anchor_lookup(&t->scope->manager->trust_anchor, t->key, &t->answer);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        t->answer_rcode = DNS_RCODE_SUCCESS;
+                        t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR;
+                        dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);
+                        return 0;
+                }
+        }
+
+        /* Check the zone, but only if this transaction is not used
          * for probing or verifying a zone item. */
         if (set_isempty(t->zone_items)) {
 
@@ -817,5 +830,6 @@ static const char* const dns_transaction_source_table[_DNS_TRANSACTION_SOURCE_MA
         [DNS_TRANSACTION_NETWORK] = "network",
         [DNS_TRANSACTION_CACHE] = "cache",
         [DNS_TRANSACTION_ZONE] = "zone",
+        [DNS_TRANSACTION_TRUST_ANCHOR] = "trust-anchor",
 };
 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_source, DnsTransactionSource);
index 5778913cc822db6dbe960def8cc4eebe900a90b3..9a2662ec0e5714cf185f4fb5f605cc75f2804403 100644 (file)
@@ -44,6 +44,7 @@ enum DnsTransactionSource {
         DNS_TRANSACTION_NETWORK,
         DNS_TRANSACTION_CACHE,
         DNS_TRANSACTION_ZONE,
+        DNS_TRANSACTION_TRUST_ANCHOR,
         _DNS_TRANSACTION_SOURCE_MAX,
         _DNS_TRANSACTION_SOURCE_INVALID = -1
 };
diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c
new file mode 100644 (file)
index 0000000..e55bdaa
--- /dev/null
@@ -0,0 +1,101 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "resolved-dns-trust-anchor.h"
+
+/* The DS RR from https://data.iana.org/root-anchors/root-anchors.xml */
+static const uint8_t root_digest[] =
+        { 0x49, 0xAA, 0xC1, 0x1D, 0x7B, 0x6F, 0x64, 0x46, 0x70, 0x2E, 0x54, 0xA1, 0x60, 0x73, 0x71, 0x60,
+          0x7A, 0x1A, 0x41, 0x85, 0x52, 0x00, 0xFD, 0x2C, 0xE1, 0xCD, 0xDE, 0x32, 0xF2, 0x4E, 0x8F, 0xB5 };
+
+int dns_trust_anchor_load(DnsTrustAnchor *d) {
+        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+        int r;
+
+        assert(d);
+
+        r = hashmap_ensure_allocated(&d->by_key, &dns_resource_key_hash_ops);
+        if (r < 0)
+                return r;
+
+        if (hashmap_get(d->by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, ".")))
+                return 0;
+
+        /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */
+        rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "");
+        if (!rr)
+                return -ENOMEM;
+
+        rr->ds.key_tag = 19036;
+        rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+        rr->ds.digest_type = DNSSEC_DIGEST_SHA256;
+        rr->ds.digest_size = sizeof(root_digest);
+        rr->ds.digest = memdup(root_digest, rr->ds.digest_size);
+        if (!rr->ds.digest)
+                return  -ENOMEM;
+
+        answer = dns_answer_new(1);
+        if (!answer)
+                return -ENOMEM;
+
+        r = dns_answer_add(answer, rr, 0);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(d->by_key, rr->key, answer);
+        if (r < 0)
+                return r;
+
+        answer = NULL;
+        return 0;
+}
+
+void dns_trust_anchor_flush(DnsTrustAnchor *d) {
+        DnsAnswer *a;
+
+        assert(d);
+
+        while ((a = hashmap_steal_first(d->by_key)))
+                dns_answer_unref(a);
+
+        d->by_key = hashmap_free(d->by_key);
+}
+
+int dns_trust_anchor_lookup(DnsTrustAnchor *d, DnsResourceKey *key, DnsAnswer **ret) {
+        DnsAnswer *a;
+
+        assert(d);
+        assert(key);
+        assert(ret);
+
+        /* We only serve DS and DNSKEY RRs. */
+        if (!IN_SET(key->type, DNS_TYPE_DS, DNS_TYPE_DNSKEY))
+                return 0;
+
+        a = hashmap_get(d->by_key, key);
+        if (!a)
+                return 0;
+
+        *ret = dns_answer_ref(a);
+        return 1;
+}
diff --git a/src/resolve/resolved-dns-trust-anchor.h b/src/resolve/resolved-dns-trust-anchor.h
new file mode 100644 (file)
index 0000000..06f3723
--- /dev/null
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct DnsTrustAnchor DnsTrustAnchor;
+
+#include "hashmap.h"
+#include "resolved-dns-answer.h"
+#include "resolved-dns-rr.h"
+
+/* This contains a fixed database mapping domain names to DS or DNSKEY records. */
+
+struct DnsTrustAnchor {
+        Hashmap *by_key;
+};
+
+int dns_trust_anchor_load(DnsTrustAnchor *d);
+void dns_trust_anchor_flush(DnsTrustAnchor *d);
+
+int dns_trust_anchor_lookup(DnsTrustAnchor *d, DnsResourceKey* key, DnsAnswer **answer);
index 62562f0d248fd8954876965e7d74b5e7c3b0675f..5a3696ccb05f616df961ba0a7a7ccc1f42d53337 100644 (file)
@@ -478,6 +478,10 @@ int manager_new(Manager **ret) {
         m->read_resolv_conf = true;
         m->need_builtin_fallbacks = true;
 
+        r = dns_trust_anchor_load(&m->trust_anchor);
+        if (r < 0)
+                return r;
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -572,6 +576,8 @@ Manager *manager_free(Manager *m) {
         free(m->llmnr_hostname);
         free(m->mdns_hostname);
 
+        dns_trust_anchor_flush(&m->trust_anchor);
+
         free(m);
 
         return NULL;
index d00c4445839ace26e89d7c90e8f9539b06c9601f..1056f23ab7c017f196d1538c36523979f8af2327 100644 (file)
@@ -44,6 +44,7 @@ enum Support {
 #include "resolved-dns-search-domain.h"
 #include "resolved-dns-server.h"
 #include "resolved-dns-stream.h"
+#include "resolved-dns-trust-anchor.h"
 #include "resolved-link.h"
 
 #define MANAGER_SEARCH_DOMAINS_MAX 32
@@ -85,6 +86,8 @@ struct Manager {
         bool read_resolv_conf:1;
         usec_t resolv_conf_mtime;
 
+        DnsTrustAnchor trust_anchor;
+
         LIST_HEAD(DnsScope, dns_scopes);
         DnsScope *unicast_scope;