]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #2174 from yuwata/journal-remote-man
authorDaniel Mack <github@zonque.org>
Tue, 15 Dec 2015 14:56:19 +0000 (15:56 +0100)
committerDaniel Mack <github@zonque.org>
Tue, 15 Dec 2015 14:56:19 +0000 (15:56 +0100)
man: fix typo in journal-remote.conf(5)

15 files changed:
src/basic/hashmap.c
src/hostname/hostnamed.c
src/resolve/resolved-dns-answer.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-dnssec.h
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-packet.h
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-transaction.c
src/resolve/test-dnssec.c
units/systemd-journal-gatewayd.service.in
units/systemd-journal-gatewayd.socket
units/systemd-journal-remote.service.in
units/systemd-journal-upload.service.in

index b3954e3223bd8963ee24594e028a195ae80983a2..286ddfef5b38024d201460469c90601dfa05d1ce 100644 (file)
@@ -37,6 +37,7 @@
 #include "util.h"
 
 #ifdef ENABLE_DEBUG_HASHMAP
+#include <pthread.h>
 #include "list.h"
 #endif
 
index d383041d3951c6cf73fdd8c89767d18515de26a6..84605fa2674f65a468c035ad894a945daa33a8fb 100644 (file)
@@ -212,7 +212,7 @@ try_dmi:
            unreliable enough, so let's not do any additional guesswork
            on top of that.
 
-           See the SMBIOS Specification 4.0 section 7.4.1 for
+           See the SMBIOS Specification 3.0 section 7.4.1 for
            details about the values listed here:
 
            https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
index 6a37345e7e0a75b17369f8d570884c5da952b4ef..5355303bd33aca9fa91ede7d3b14b4732458822c 100644 (file)
@@ -22,6 +22,7 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "resolved-dns-answer.h"
+#include "resolved-dns-dnssec.h"
 #include "string-util.h"
 
 DnsAnswer *dns_answer_new(unsigned n) {
index 792c9d869211526453d9cdcd1c670e4b5aae359c..ed126505ad3f47d1dfd94e32ab0cb770072c4653 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "alloc-util.h"
 #include "dns-domain.h"
+#include "hexdecoct.h"
 #include "resolved-dns-dnssec.h"
 #include "resolved-dns-packet.h"
 #include "string-table.h"
@@ -42,6 +43,8 @@
  *   - multi-label zone compatibility
  *   - DNSSEC cname/dname compatibility
  *   - per-interface DNSSEC setting
+ *   - retry on failed validation
+ *   - fix TTL for cache entries to match RRSIG TTL
  *   - DSA support
  *   - EC support?
  *
  *            Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
  */
 
+static void initialize_libgcrypt(void) {
+        const char *p;
+
+        if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
+                return;
+
+        p = gcry_check_version("1.4.5");
+        assert(p);
+
+        gcry_control(GCRYCTL_DISABLE_SECMEM);
+        gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+}
+
 static bool dnssec_algorithm_supported(int algorithm) {
         return IN_SET(algorithm,
                       DNSSEC_ALGORITHM_RSASHA1,
@@ -72,12 +88,6 @@ static bool dnssec_algorithm_supported(int algorithm) {
                       DNSSEC_ALGORITHM_RSASHA512);
 }
 
-static bool dnssec_digest_supported(int digest) {
-        return IN_SET(digest,
-                      DNSSEC_DIGEST_SHA1,
-                      DNSSEC_DIGEST_SHA256);
-}
-
 uint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
         const uint8_t *p;
         uint32_t sum;
@@ -335,6 +345,8 @@ int dnssec_verify_rrset(
         /* Bring the RRs into canonical order */
         qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
 
+        initialize_libgcrypt();
+
         /* OK, the RRs are now in canonical order. Let's calculate the digest */
         switch (rrsig->rrsig.algorithm) {
 
@@ -679,9 +691,28 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
         return (int) c;
 }
 
+static int digest_to_gcrypt(uint8_t algorithm) {
+
+        /* Translates a DNSSEC digest algorithm into a gcrypt digest iedntifier */
+
+        switch (algorithm) {
+
+        case DNSSEC_DIGEST_SHA1:
+                return GCRY_MD_SHA1;
+
+        case DNSSEC_DIGEST_SHA256:
+                return GCRY_MD_SHA256;
+
+        default:
+                return -EOPNOTSUPP;
+        }
+}
+
 int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
-        gcry_md_hd_t md = NULL;
         char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
+        gcry_md_hd_t md = NULL;
+        size_t hash_size;
+        int algorithm;
         void *result;
         int r;
 
@@ -704,38 +735,26 @@ int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
         if (dnssec_keytag(dnskey) != ds->ds.key_tag)
                 return 0;
 
-        if (!dnssec_digest_supported(ds->ds.digest_type))
-                return -EOPNOTSUPP;
-
-        switch (ds->ds.digest_type) {
-
-        case DNSSEC_DIGEST_SHA1:
-
-                if (ds->ds.digest_size != 20)
-                        return 0;
+        initialize_libgcrypt();
 
-                gcry_md_open(&md, GCRY_MD_SHA1, 0);
-                break;
+        algorithm = digest_to_gcrypt(ds->ds.digest_type);
+        if (algorithm < 0)
+                return algorithm;
 
-        case DNSSEC_DIGEST_SHA256:
+        hash_size = gcry_md_get_algo_dlen(algorithm);
+        assert(hash_size > 0);
 
-                if (ds->ds.digest_size != 32)
-                        return 0;
-
-                gcry_md_open(&md, GCRY_MD_SHA256, 0);
-                break;
+        if (ds->ds.digest_size != hash_size)
+                return 0;
 
-        default:
-                assert_not_reached("Unknown digest");
-        }
+        r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
+        if (r < 0)
+                return r;
 
+        gcry_md_open(&md, algorithm, 0);
         if (!md)
                 return -EIO;
 
-        r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
-        if (r < 0)
-                goto finish;
-
         gcry_md_write(md, owner_name, r);
         md_add_uint16(md, dnskey->dnskey.flags);
         md_add_uint8(md, dnskey->dnskey.protocol);
@@ -779,6 +798,187 @@ int dnssec_verify_dnskey_search(DnsResourceRecord *dnskey, DnsAnswer *validated_
         return 0;
 }
 
+int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
+        uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
+        gcry_md_hd_t md = NULL;
+        size_t hash_size;
+        int algorithm;
+        void *result;
+        unsigned k;
+        int r;
+
+        assert(nsec3);
+        assert(name);
+        assert(ret);
+
+        if (nsec3->key->type != DNS_TYPE_NSEC3)
+                return -EINVAL;
+
+        algorithm = digest_to_gcrypt(nsec3->nsec3.algorithm);
+        if (algorithm < 0)
+                return algorithm;
+
+        initialize_libgcrypt();
+
+        hash_size = gcry_md_get_algo_dlen(algorithm);
+        assert(hash_size > 0);
+
+        if (nsec3->nsec3.next_hashed_name_size != hash_size)
+                return -EINVAL;
+
+        r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
+        if (r < 0)
+                return r;
+
+        gcry_md_open(&md, algorithm, 0);
+        if (!md)
+                return -EIO;
+
+        gcry_md_write(md, wire_format, r);
+        gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
+
+        result = gcry_md_read(md, 0);
+        if (!result) {
+                r = -EIO;
+                goto finish;
+        }
+
+        for (k = 0; k < nsec3->nsec3.iterations; k++) {
+                uint8_t tmp[hash_size];
+                memcpy(tmp, result, hash_size);
+
+                gcry_md_reset(md);
+                gcry_md_write(md, tmp, hash_size);
+                gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
+
+                result = gcry_md_read(md, 0);
+                if (!result) {
+                        r = -EIO;
+                        goto finish;
+                }
+        }
+
+        memcpy(ret, result, hash_size);
+        r = (int) hash_size;
+
+finish:
+        gcry_md_close(md);
+        return r;
+}
+
+int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result) {
+        DnsResourceRecord *rr;
+        int r;
+
+        assert(key);
+        assert(result);
+
+        /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
+
+        DNS_ANSWER_FOREACH(rr, answer) {
+
+                if (rr->key->class != key->class)
+                        continue;
+
+                switch (rr->key->type) {
+
+                case DNS_TYPE_NSEC:
+
+                        r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+                        if (r < 0)
+                                return r;
+                        if (r > 0) {
+                                *result = bitmap_isset(rr->nsec.types, key->type) ? DNSSEC_NSEC_FOUND : DNSSEC_NSEC_NODATA;
+                                return 0;
+                        }
+
+                        r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key), rr->nsec.next_domain_name);
+                        if (r < 0)
+                                return r;
+                        if (r > 0) {
+                                *result = DNSSEC_NSEC_NXDOMAIN;
+                                return 0;
+                        }
+                        break;
+
+                case DNS_TYPE_NSEC3: {
+                        _cleanup_free_ void *decoded = NULL;
+                        size_t decoded_size;
+                        char label[DNS_LABEL_MAX];
+                        uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
+                        int label_length, c, q;
+                        const char *p;
+                        bool covered;
+
+                        /* RFC  5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
+                        if (!IN_SET(rr->nsec3.flags, 0, 1))
+                                continue;
+
+                        p = DNS_RESOURCE_KEY_NAME(rr->key);
+                        label_length = dns_label_unescape(&p, label, sizeof(label));
+                        if (label_length < 0)
+                                return label_length;
+                        if (label_length == 0)
+                                continue;
+
+                        r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), p);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                continue;
+
+                        r = unbase32hexmem(label, label_length, false, &decoded, &decoded_size);
+                        if (r == -EINVAL)
+                                continue;
+                        if (r < 0)
+                                return r;
+
+                        if (decoded_size != rr->nsec3.next_hashed_name_size)
+                                continue;
+
+                        c = memcmp(decoded, rr->nsec3.next_hashed_name, decoded_size);
+                        if (c == 0)
+                                continue;
+
+                        r = dnssec_nsec3_hash(rr, DNS_RESOURCE_KEY_NAME(key), hashed);
+                        /* RFC 5155, Section 8.1 says we MUST ignore NSEC3 RRs with unknown algorithms */
+                        if (r == -EOPNOTSUPP)
+                                continue;
+                        if (r < 0)
+                                return r;
+                        if ((size_t) r != decoded_size)
+                                continue;
+
+                        r = memcmp(decoded, hashed, decoded_size);
+                        if (r == 0) {
+                                *result = bitmap_isset(rr->nsec3.types, key->type) ? DNSSEC_NSEC_FOUND : DNSSEC_NSEC_NODATA;
+                                return 0;
+                        }
+
+                        q = memcmp(hashed, rr->nsec3.next_hashed_name, decoded_size);
+
+                        covered = c < 0 ?
+                                r < 0 && q < 0 :
+                                q < 0 || r < 0;
+
+                        if (covered) {
+                                *result = DNSSEC_NSEC_NXDOMAIN;
+                                return 0;
+                        }
+
+                        break;
+                }
+
+                default:
+                        break;
+                }
+        }
+
+        /* No approproate NSEC RR found, report this. */
+        *result = DNSSEC_NSEC_NO_RR;
+        return 0;
+}
+
 static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
         [DNSSEC_NO] = "no",
         [DNSSEC_TRUST] = "trust",
@@ -795,5 +995,6 @@ static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
         [DNSSEC_MISSING_KEY] = "missing-key",
         [DNSSEC_UNSIGNED] = "unsigned",
         [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
+        [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
 };
 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
index f33abe3e11a81c92da6c2171853c87585b24e1c3..442e3013027be9e607f712c854e98a13e8409713 100644 (file)
@@ -56,12 +56,16 @@ enum DnssecResult {
         /* These two are added by the DnsTransaction logic */
         DNSSEC_UNSIGNED,
         DNSSEC_FAILED_AUXILIARY,
+        DNSSEC_NSEC_MISMATCH,
         _DNSSEC_RESULT_MAX,
         _DNSSEC_RESULT_INVALID = -1
 };
 
 #define DNSSEC_CANONICAL_HOSTNAME_MAX (DNS_HOSTNAME_MAX + 2)
 
+/* The longest digest we'll ever generate, of all digest algorithms we support */
+#define DNSSEC_HASH_SIZE_MAX (MAX(20, 32))
+
 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey);
 int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig);
 
@@ -75,6 +79,17 @@ uint16_t dnssec_keytag(DnsResourceRecord *dnskey);
 
 int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max);
 
+int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret);
+
+typedef enum DnssecNsecResult {
+        DNSSEC_NSEC_NO_RR,     /* No suitable NSEC/NSEC3 RR found */
+        DNSSEC_NSEC_NXDOMAIN,
+        DNSSEC_NSEC_NODATA,
+        DNSSEC_NSEC_FOUND,
+} DnssecNsecResult;
+
+int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result);
+
 const char* dnssec_mode_to_string(DnssecMode m) _const_;
 DnssecMode dnssec_mode_from_string(const char *s) _pure_;
 
index 4e069ab4cb45f4c8462d4fad2d0dd9e4beb5c372..c34ecc44f8ec41b3bf02d61c5112174d99265264 100644 (file)
@@ -80,7 +80,7 @@ void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool trun
                 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
                                                          0 /* opcode */,
                                                          0 /* c */,
-                                                         0/* tc */,
+                                                         0 /* tc */,
                                                          0 /* t */,
                                                          0 /* ra */,
                                                          0 /* ad */,
@@ -438,10 +438,15 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_
         return 0;
 }
 
-int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
+int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, bool canonical_candidate, size_t *start) {
         uint8_t *w;
         int r;
 
+        /* Append a label to a packet. Optionally, does this in DNSSEC
+         * canonical form, if this label is marked as a candidate for
+         * it, and the canonical form logic is enabled for the
+         * packet */
+
         assert(p);
         assert(d);
 
@@ -454,7 +459,7 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start
 
         *(w++) = (uint8_t) l;
 
-        if (p->canonical_form) {
+        if (p->canonical_form && canonical_candidate) {
                 size_t i;
 
                 /* Generate in canonical form, as defined by DNSSEC
@@ -479,6 +484,7 @@ int dns_packet_append_name(
                 DnsPacket *p,
                 const char *name,
                 bool allow_compression,
+                bool canonical_candidate,
                 size_t *start) {
 
         size_t saved_size;
@@ -533,7 +539,7 @@ int dns_packet_append_name(
                 if (k > 0)
                         r = k;
 
-                r = dns_packet_append_label(p, label, r, &n);
+                r = dns_packet_append_label(p, label, r, canonical_candidate, &n);
                 if (r < 0)
                         goto fail;
 
@@ -574,7 +580,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start)
 
         saved_size = p->size;
 
-        r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL);
+        r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL);
         if (r < 0)
                 goto fail;
 
@@ -596,7 +602,7 @@ fail:
         return r;
 }
 
-static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) {
+static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, const uint8_t *types, size_t *start) {
         size_t saved_size;
         int r;
 
@@ -653,15 +659,16 @@ static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
                 }
 
                 window = n >> 8;
-
                 entry = n & 255;
 
                 bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
         }
 
-        r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
-        if (r < 0)
-                goto fail;
+        if (bitmaps[entry / 8] != 0) {
+                r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
+                if (r < 0)
+                        goto fail;
+        }
 
         if (start)
                 *start = saved_size;
@@ -762,14 +769,14 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->srv.name, true, NULL);
+                r = dns_packet_append_name(p, rr->srv.name, true, false, NULL);
                 break;
 
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
         case DNS_TYPE_CNAME:
         case DNS_TYPE_DNAME:
-                r = dns_packet_append_name(p, rr->ptr.name, true, NULL);
+                r = dns_packet_append_name(p, rr->ptr.name, true, false, NULL);
                 break;
 
         case DNS_TYPE_HINFO:
@@ -812,11 +819,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 break;
 
         case DNS_TYPE_SOA:
-                r = dns_packet_append_name(p, rr->soa.mname, true, NULL);
+                r = dns_packet_append_name(p, rr->soa.mname, true, false, NULL);
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->soa.rname, true, NULL);
+                r = dns_packet_append_name(p, rr->soa.rname, true, false, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -844,7 +851,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->mx.exchange, true, NULL);
+                r = dns_packet_append_name(p, rr->mx.exchange, true, false, NULL);
                 break;
 
         case DNS_TYPE_LOC:
@@ -948,7 +955,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL);
+                r = dns_packet_append_name(p, rr->rrsig.signer, false, true, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -956,7 +963,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 break;
 
         case DNS_TYPE_NSEC:
-                r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL);
+                r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, false, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -1848,7 +1855,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
         case DNS_TYPE_NSEC: {
 
                 /*
-                 * RFC6762, section 18.14 explicly states mDNS should use name compression.
+                 * RFC6762, section 18.14 explictly states mDNS should use name compression.
                  * This contradicts RFC3845, section 2.1.1
                  */
 
index 5b6a71dc01edbb6ed8d63554c311a3a43056c9b5..082e92833c3065821319dd6ad9dc9d1cb46c139d 100644 (file)
@@ -169,8 +169,8 @@ int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start);
 int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start);
 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start);
 int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start);
-int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start);
-int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start);
+int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonical_candidate, size_t *start);
+int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start);
 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start);
 int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start);
 int dns_packet_append_opt_rr(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start);
index a6565f2ba2ad77e53972946aa9678384da39de00..405882a6ea9f21ca284e8e50d2aea9d4eca1dbbc 100644 (file)
@@ -185,6 +185,14 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
 
                 switch (t->state) {
 
+                case DNS_TRANSACTION_NULL:
+                        /* If there's a NULL transaction pending, then
+                         * this means not all transactions where
+                         * started yet, and we were called from within
+                         * the stackframe that is supposed to start
+                         * remaining transactions. In this case,
+                         * simply claim the candidate is pending. */
+
                 case DNS_TRANSACTION_PENDING:
                 case DNS_TRANSACTION_VALIDATING:
                         /* If there's one transaction currently in
@@ -197,9 +205,6 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
                         state = t->state;
                         break;
 
-                case DNS_TRANSACTION_NULL:
-                        assert_not_reached("Transaction not started?");
-
                 default:
                         if (state != DNS_TRANSACTION_SUCCESS)
                                 state = t->state;
index 61bca04b94309f3ff22a1f87c5bac66de99b1db1..5bd733a8ff36191a91d5ba1420b649386a244101 100644 (file)
@@ -506,7 +506,7 @@ int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
 
         if (s->protocol == DNS_PROTOCOL_DNS) {
 
-                /* On classic DNS, lookin up non-address RRs is always
+                /* On classic DNS, looking up non-address RRs is always
                  * fine. (Specifically, we want to permit looking up
                  * DNSKEY and DS records on the root and top-level
                  * domains.) */
index 8b3e59a1eabc4c6f5f74a19eb24dddb7d9566fdc..f09788b0c67159da650d54b9ef11a66ab1e5dc06 100644 (file)
@@ -843,7 +843,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
         assert(t);
         assert(t->scope->protocol == DNS_PROTOCOL_MDNS);
 
-        /* Discard any previously prepared packet, so we can start over and coaleasce again */
+        /* Discard any previously prepared packet, so we can start over and coalesce again */
         t->sent = dns_packet_unref(t->sent);
 
         r = dns_packet_new_query(&p, t->scope->protocol, 0, false);
@@ -1288,7 +1288,10 @@ static int dns_transaction_is_primary_response(DnsTransaction *t, DnsResourceRec
 
         /* Check if the specified RR is the "primary" response,
          * i.e. either matches the question precisely or is a
-         * CNAME/DNAME for it */
+         * CNAME/DNAME for it, or is any kind of NSEC/NSEC3 RR */
+
+        if (IN_SET(rr->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3))
+                return 1;
 
         r = dns_resource_key_match_rr(t->key, rr, NULL);
         if (r != 0)
@@ -1469,8 +1472,57 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
         /* Everything that's now in t->answer is known to be good, hence cacheable. */
         t->n_answer_cacheable = (unsigned) -1; /* everything! */
 
-        t->answer_authenticated = true;
-        t->dnssec_result = DNSSEC_VALIDATED;
+        /* At this point the answer only contains validated
+         * RRsets. Now, let's see if it actually answers the question
+         * we asked. If so, great! If it doesn't, then see if
+         * NSEC/NSEC3 can prove this. */
+        r = dns_answer_match_key(t->answer, t->key);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                /* Yes, it answer the question, everything is authenticated. */
+                t->dnssec_result = DNSSEC_VALIDATED;
+                t->answer_rcode = DNS_RCODE_SUCCESS;
+                t->answer_authenticated = true;
+        } else if (r == 0) {
+                DnssecNsecResult nr;
+
+                /* Bummer! Let's check NSEC/NSEC3 */
+                r = dnssec_test_nsec(t->answer, t->key, &nr);
+                if (r < 0)
+                        return r;
+
+                switch (nr) {
+
+                case DNSSEC_NSEC_NXDOMAIN:
+                        /* NSEC proves the domain doesn't exist. Very good. */
+                        t->dnssec_result = DNSSEC_VALIDATED;
+                        t->answer_rcode = DNS_RCODE_NXDOMAIN;
+                        t->answer_authenticated = true;
+                        break;
+
+                case DNSSEC_NSEC_NODATA:
+                        /* NSEC proves that there's no data here, very good. */
+                        t->dnssec_result = DNSSEC_VALIDATED;
+                        t->answer_rcode = DNS_RCODE_SUCCESS;
+                        t->answer_authenticated = true;
+                        break;
+
+                case DNSSEC_NSEC_NO_RR:
+                        /* No NSEC data? Bummer! */
+                        t->dnssec_result = DNSSEC_UNSIGNED;
+                        break;
+
+                case DNSSEC_NSEC_FOUND:
+                        /* NSEC says it needs to be there, but we couldn't find it? Bummer! */
+                        t->dnssec_result = DNSSEC_NSEC_MISMATCH;
+                        break;
+
+                default:
+                        assert_not_reached("Unexpected NSEC result.");
+                }
+        }
+
         return 1;
 }
 
index a2118513f1d8b67a933a4e0431efb7b68c9553b0..807eeb3d9a6f15b96853012c38a8f2e9743fea60 100644 (file)
 #include "resolved-dns-dnssec.h"
 #include "resolved-dns-rr.h"
 #include "string-util.h"
+#include "hexdecoct.h"
+
+static void test_dnssec_verify_rrset2(void) {
+
+       static const uint8_t signature_blob[] = {
+               0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
+               0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
+               0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
+               0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
+               0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
+               0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
+               0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
+               0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
+        };
+
+        static const uint8_t dnskey_blob[] = {
+                0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
+                0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
+                0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
+                0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
+                0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
+                0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
+                0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
+                0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
+                0x74, 0x62, 0xfe, 0xd7,
+        };
+
+        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
+        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+        _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
+        DnssecResult result;
+
+        nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
+        assert_se(nsec);
+
+        nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
+        assert_se(nsec->nsec.next_domain_name);
+
+        nsec->nsec.types = bitmap_new();
+        assert_se(nsec->nsec.types);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
+        assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
+
+        assert_se(dns_resource_record_to_string(nsec, &x) >= 0);
+        log_info("NSEC: %s", x);
+
+        rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
+        assert_se(rrsig);
+
+        rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
+        rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+        rrsig->rrsig.labels = 2;
+        rrsig->rrsig.original_ttl = 300;
+        rrsig->rrsig.expiration = 0x5689002f;
+        rrsig->rrsig.inception = 0x56617230;
+        rrsig->rrsig.key_tag = 30390;
+        rrsig->rrsig.signer = strdup("Nasa.Gov.");
+        assert_se(rrsig->rrsig.signer);
+        rrsig->rrsig.signature_size = sizeof(signature_blob);
+        rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
+        assert_se(rrsig->rrsig.signature);
+
+        assert_se(dns_resource_record_to_string(rrsig, &y) >= 0);
+        log_info("RRSIG: %s", y);
+
+        dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
+        assert_se(dnskey);
+
+        dnskey->dnskey.flags = 256;
+        dnskey->dnskey.protocol = 3;
+        dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+        dnskey->dnskey.key_size = sizeof(dnskey_blob);
+        dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
+        assert_se(dnskey->dnskey.key);
+
+        assert_se(dns_resource_record_to_string(dnskey, &z) >= 0);
+        log_info("DNSKEY: %s", z);
+        log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey));
+
+        assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
+        assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey) > 0);
+
+        answer = dns_answer_new(1);
+        assert_se(answer);
+        assert_se(dns_answer_add(answer, nsec, 0) >= 0);
+
+        /* Validate the RR as it if was 2015-12-11 today */
+        assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
+        assert_se(result == DNSSEC_VALIDATED);
+}
 
 static void test_dnssec_verify_rrset(void) {
 
@@ -209,11 +306,46 @@ static void test_dnssec_canonicalize(void) {
         test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
 }
 
+static void test_dnssec_nsec3_hash(void) {
+        static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE };
+        static const uint8_t next_hashed_name[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 };
+        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+        _cleanup_free_ char *a = NULL, *b = NULL;
+        uint8_t h[DNSSEC_HASH_SIZE_MAX];
+        int k;
+
+        /* The NSEC3 RR for eurid.eu on 2015-12-14. */
+        rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC3, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM.eurid.eu.");
+        assert_se(rr);
+
+        rr->nsec3.algorithm = DNSSEC_DIGEST_SHA1;
+        rr->nsec3.flags = 1;
+        rr->nsec3.iterations = 1;
+        rr->nsec3.salt = memdup(salt, sizeof(salt));
+        assert_se(rr->nsec3.salt);
+        rr->nsec3.salt_size = sizeof(salt);
+        rr->nsec3.next_hashed_name = memdup(next_hashed_name, sizeof(next_hashed_name));
+        assert_se(rr->nsec3.next_hashed_name);
+        rr->nsec3.next_hashed_name_size = sizeof(next_hashed_name);
+
+        assert_se(dns_resource_record_to_string(rr, &a) >= 0);
+        log_info("NSEC3: %s", a);
+
+        k = dnssec_nsec3_hash(rr, "eurid.eu", &h);
+        assert_se(k >= 0);
+
+        b = base32hexmem(h, k, false);
+        assert_se(b);
+        assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
+}
+
 int main(int argc, char*argv[]) {
 
         test_dnssec_canonicalize();
         test_dnssec_verify_dns_key();
         test_dnssec_verify_rrset();
+        test_dnssec_verify_rrset2();
+        test_dnssec_nsec3_hash();
 
         return 0;
 }
index 987220e554208dbf6a0a2eaa4b06d6453a7f8899..f4f845841da0f80a7c54447a764084b3c7d66d98 100644 (file)
@@ -7,6 +7,7 @@
 
 [Unit]
 Description=Journal Gateway Service
+Documentation=man:systemd-journal-gatewayd(8)
 Requires=systemd-journal-gatewayd.socket
 
 [Service]
index fd11058ab4ae5210b481c2a5a0a019b01a255a88..79d9b04210130cdb8e55759b00f2749d63d27d5d 100644 (file)
@@ -7,6 +7,7 @@
 
 [Unit]
 Description=Journal Gateway Service Socket
+Documentation=man:systemd-journal-gatewayd(8)
 
 [Socket]
 ListenStream=19531
index 2928a230211737402b4ffa830458b0a5fcf67a9d..fdf3da4b642ebfe9c4e4a43261e7411621fbfe00 100644 (file)
@@ -7,6 +7,7 @@
 
 [Unit]
 Description=Journal Remote Sink Service
+Documentation=man:systemd-journal-remote(8) man:journal-remote.conf(5)
 Requires=systemd-journal-remote.socket
 
 [Service]
index a757673a621b13504a5fa53089b21b9008f21830..4a89186f31dc5085929acce35f6b1ed744939e44 100644 (file)
@@ -7,6 +7,7 @@
 
 [Unit]
 Description=Journal Remote Upload Service
+Documentation=man:systemd-journal-upload(8)
 After=network.target
 
 [Service]