]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: rr - add NSEC support
authorTom Gundersen <teg@jklm.no>
Sun, 12 Jul 2015 23:51:03 +0000 (01:51 +0200)
committerTom Gundersen <teg@jklm.no>
Tue, 14 Jul 2015 19:53:10 +0000 (21:53 +0200)
Needed for DNSSEC.

src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h

index 1ebebf8ea4dec12cc80a7808e0da873a05c364e0..d2b3cb0eb1b5930d71e22cfdd86ca722870626c0 100644 (file)
@@ -502,6 +502,89 @@ fail:
         return r;
 }
 
+static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) {
+        size_t saved_size;
+        int r;
+
+        assert(p);
+        assert(types);
+
+        if (length == 0)
+                return 0;
+
+        saved_size = p->size;
+
+        r = dns_packet_append_uint8(p, window, NULL);
+        if (r < 0)
+                goto fail;
+
+        r = dns_packet_append_uint8(p, length, NULL);
+        if (r < 0)
+                goto fail;
+
+        r = dns_packet_append_blob(p, types, length, NULL);
+        if (r < 0)
+                goto fail;
+
+        if (start)
+                *start = saved_size;
+
+        return 0;
+fail:
+        dns_packet_truncate(p, saved_size);
+        return r;
+}
+
+static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
+        uint8_t window = 0;
+        uint8_t len = 0;
+        uint8_t bitmaps[32] = {};
+        unsigned n;
+        size_t saved_size;
+        int r;
+
+        assert(p);
+        assert(types);
+
+        saved_size = p->size;
+
+        BITMAP_FOREACH(n, types) {
+                uint8_t entry;
+
+                assert(n <= 0xffff);
+
+                if ((n << 8) != window) {
+                        r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+                        if (r < 0)
+                                goto fail;
+
+                        if (len > 0) {
+                                len = 0;
+                                zero(bitmaps);
+                        }
+                }
+
+                window = n << 8;
+                len ++;
+
+                entry = n & 255;
+
+                bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
+        }
+
+        r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+        if (r < 0)
+                goto fail;
+
+        if (start)
+                *start = saved_size;
+
+        return 0;
+fail:
+        dns_packet_truncate(p, saved_size);
+        return r;
+}
+
 int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
         size_t saved_size, rdlength_offset, end, rdlength;
         int r;
@@ -732,6 +815,16 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
                 break;
 
+        case DNS_TYPE_NSEC:
+                r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_types(p, rr->nsec.types, NULL);
+                if (r < 0)
+                        goto fail;
+
+                break;
         case _DNS_TYPE_INVALID: /* unparseable */
         default:
 
@@ -996,6 +1089,79 @@ fail:
         return r;
 }
 
+static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
+        uint8_t window;
+        uint8_t length;
+        const uint8_t *bitmap;
+        unsigned i;
+        bool found = false;
+        size_t saved_rindex;
+        int r;
+
+        assert(p);
+        assert(types);
+
+        saved_rindex = p->rindex;
+
+        r = bitmap_ensure_allocated(types);
+        if (r < 0)
+                goto fail;
+
+        r = dns_packet_read_uint8(p, &window, NULL);
+        if (r < 0)
+                goto fail;
+
+        r = dns_packet_read_uint8(p, &length, NULL);
+        if (r < 0)
+                goto fail;
+
+        if (length == 0 || length > 32)
+                return -EBADMSG;
+
+        r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
+        if (r < 0)
+                goto fail;
+
+        for (i = 0; i < length; i++) {
+                uint8_t bitmask = 1 << 7;
+                uint8_t bit = 0;
+
+                if (!bitmap[i]) {
+                        found = false;
+                        continue;
+                }
+
+                found = true;
+
+                while (bitmask) {
+                        if (bitmap[i] & bitmask) {
+                                uint16_t n;
+
+                                /* XXX: ignore pseudo-types? see RFC4034 section 4.1.2 */
+                                n = (uint16_t) window << 8 | (uint16_t) bit;
+
+                                r = bitmap_set(*types, n);
+                                if (r < 0)
+                                        goto fail;
+                        }
+
+                        bit ++;
+                        bitmask >>= 1;
+                }
+        }
+
+        if (!found)
+                return -EBADMSG;
+
+        if (start)
+                *start = saved_rindex;
+
+        return 0;
+fail:
+        dns_packet_rewind(p, saved_rindex);
+        return r;
+}
+
 int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
         _cleanup_free_ char *name = NULL;
         uint16_t class, type;
@@ -1382,6 +1548,18 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                                                NULL);
                 break;
 
+        case DNS_TYPE_NSEC:
+                r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL);
+                if (r < 0)
+                        goto fail;
+
+                while (p->rindex != offset + rdlength) {
+                        r = dns_packet_read_type_window(p, &rr->nsec.types, NULL);
+                        if (r < 0)
+                                goto fail;
+                }
+
+                break;
         default:
         unparseable:
                 r = dns_packet_read(p, rdlength, &d, NULL);
index 676b77713ef9c0882b668e9430c3c6f47947c011..48fb3538ae7a291acabbfbe8d50fc17d384b60c8 100644 (file)
@@ -288,6 +288,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
                         free(rr->rrsig.signature);
                         break;
 
+                case DNS_TYPE_NSEC:
+                        free(rr->nsec.next_domain_name);
+                        bitmap_free(rr->nsec.types);
+                        break;
+
                 case DNS_TYPE_LOC:
                 case DNS_TYPE_A:
                 case DNS_TYPE_AAAA:
@@ -448,6 +453,10 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
 
                 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
 
+        case DNS_TYPE_NSEC:
+                return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
+                       bitmap_equal(a->nsec.types, b->nsec.types);
+
         default:
                 return a->generic.size == b->generic.size &&
                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@@ -500,6 +509,37 @@ static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
         return 0;
 }
 
+static char *format_types(Bitmap *types) {
+        _cleanup_strv_free_ char **strv = NULL;
+        _cleanup_free_ char *str = NULL;
+        unsigned type;
+        int r;
+
+        BITMAP_FOREACH(type, types) {
+                if (dns_type_to_string(type)) {
+                        r = strv_extend(&strv, strdup(dns_type_to_string(type)));
+                        if (r < 0)
+                                return NULL;
+                } else {
+                        char *t;
+
+                        r = asprintf(&t, "TYPE%u", type);
+                        if (r < 0)
+                                return NULL;
+
+                        r = strv_extend(&strv, t);
+                        if (r < 0)
+                                return NULL;
+                }
+        }
+
+        str = strv_join(strv, " ");
+        if (!str)
+                return NULL;
+
+        return strjoin("( ", str, " )", NULL);
+}
+
 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
         _cleanup_free_ char *k = NULL, *t = NULL;
         char *s;
@@ -704,6 +744,19 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
                 break;
         }
 
+        case DNS_TYPE_NSEC:
+                t = format_types(rr->nsec.types);
+                if (!t)
+                        return -ENOMEM;
+
+                r = asprintf(&s, "%s %s %s",
+                             k,
+                             rr->nsec.next_domain_name,
+                             t);
+                if (r < 0)
+                        return -ENOMEM;
+                break;
+
         default:
                 t = hexmem(rr->generic.data, rr->generic.size);
                 if (!t)
index b375d6b9fc34e115037af8b655e6ea8844c51f80..eaaafb1f2544196ff95b0b18c680e92bce9e8b68 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <netinet/in.h>
 
+#include "bitmap.h"
 #include "hashmap.h"
 #include "in-addr-util.h"
 #include "dns-type.h"
@@ -145,6 +146,11 @@ struct DnsResourceRecord {
                         void *signature;
                         size_t signature_size;
                 } rrsig;
+
+                struct {
+                        char *next_domain_name;
+                        Bitmap *types;
+                } nsec;
         };
 };