chiark / gitweb /
resolved: add identifiers for dnssec algorithms
[elogind.git] / src / resolve / resolved-dns-packet.c
index fae105d0daae4e9f0ff8dfe140ad7e577791d9b6..626b904d98054dadf39b9d29be02196266f651aa 100644 (file)
@@ -390,6 +390,7 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
                 _cleanup_free_ char *s = NULL;
                 char label[DNS_LABEL_MAX];
                 size_t n;
+                int k;
 
                 n = PTR_TO_SIZE(hashmap_get(p->names, name));
                 if (n > 0) {
@@ -414,6 +415,17 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
                 if (r < 0)
                         goto fail;
 
+                if (p->protocol == DNS_PROTOCOL_DNS)
+                        k = dns_label_apply_idna(label, r, label, sizeof(label));
+                else
+                        k = dns_label_undo_idna(label, r, label, sizeof(label));
+                if (k < 0) {
+                        r = k;
+                        goto fail;
+                }
+                if (k > 0)
+                        r = k;
+
                 r = dns_packet_append_label(p, label, r, &n);
                 if (r < 0)
                         goto fail;
@@ -499,9 +511,26 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
 
         switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
 
+        case DNS_TYPE_SRV:
+                r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint16(p, rr->srv.port, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_name(p, rr->srv.name, 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, NULL);
                 break;
 
@@ -523,6 +552,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                                 goto fail;
                 }
 
+                r = 0;
                 break;
         }
 
@@ -587,20 +617,45 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_uint16(p, rr->loc.latitude, NULL);
+                r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_uint16(p, rr->loc.longitude, NULL);
+                r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
                 if (r < 0)
                         goto fail;
 
-                r = dns_packet_append_uint16(p, rr->loc.altitude, NULL);
+                r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
                 break;
 
-        case DNS_TYPE_SRV:
-        case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
+                r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
+                break;
+
+        case DNS_TYPE_DNSKEY:
+                r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, 3u, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
+                break;
+
         case _DNS_TYPE_INVALID: /* unparseable */
         default:
 
@@ -814,7 +869,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
                         else
                                 first = false;
 
-                        memcpy(ret + n, t, c);
+                        memcpy(ret + n, t, r);
                         n += r;
                         continue;
                 } else if ((c & 0xc0) == 0xc0) {
@@ -904,6 +959,41 @@ fail:
         return r;
 }
 
+static int dns_packet_read_public_key(DnsPacket *p, size_t length,
+                                      void **dp, size_t *lengthp,
+                                      size_t *start) {
+        int r;
+        const void *d;
+        void *d2;
+
+        r = dns_packet_read(p, length, &d, NULL);
+        if (r < 0)
+                return r;
+
+        d2 = memdup(d, length);
+        if (!d2)
+                return -ENOMEM;
+
+        *dp = d2;
+        *lengthp = length;
+        return 0;
+}
+
+static bool loc_size_ok(uint8_t size) {
+        uint8_t m = size >> 4, e = size & 0xF;
+
+        return m <= 9 && e <= 9 && (m > 0 || e == 0);
+}
+
+static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) {
+        if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY))
+                return -EBADMSG;
+
+        rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY;
+        rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP;
+        return 0;
+}
+
 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
@@ -950,9 +1040,23 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
 
         switch (rr->key->type) {
 
+        case DNS_TYPE_SRV:
+                r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
+                if (r < 0)
+                        goto fail;
+                r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
+                if (r < 0)
+                        goto fail;
+                r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
+                if (r < 0)
+                        goto fail;
+                r = dns_packet_read_name(p, &rr->srv.name, NULL);
+                break;
+
         case DNS_TYPE_PTR:
         case DNS_TYPE_NS:
         case DNS_TYPE_CNAME:
+        case DNS_TYPE_DNAME:
                 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
                 break;
 
@@ -968,7 +1072,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
         case DNS_TYPE_TXT: {
                 char *s;
 
-                while (p->rindex < p->size) {
+                while (p->rindex < offset + rdlength) {
                         r = dns_packet_read_string(p, &s, NULL);
                         if (r < 0)
                                 goto fail;
@@ -976,7 +1080,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                         r = strv_consume(&rr->txt.strings, s);
                         if (r < 0)
                                 goto fail;
-                };
+                }
+
+                r = 0;
                 break;
         }
 
@@ -1039,14 +1145,29 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                         if (r < 0)
                                 goto fail;
 
+                        if (!loc_size_ok(rr->loc.size)) {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
                         r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
                         if (r < 0)
                                 goto fail;
 
+                        if (!loc_size_ok(rr->loc.horiz_pre)) {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
                         r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
                         if (r < 0)
                                 goto fail;
 
+                        if (!loc_size_ok(rr->loc.vert_pre)) {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
                         r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
                         if (r < 0)
                                 goto fail;
@@ -1063,14 +1184,58 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
                 } else {
                         dns_packet_rewind(p, pos);
                         rr->unparseable = true;
-                        /* fall through */
+                        goto unparseable;
                 }
         }
 
-        case DNS_TYPE_SRV:
-        case DNS_TYPE_DNAME:
         case DNS_TYPE_SSHFP:
+                r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_public_key(p, rdlength - 2,
+                                               &rr->sshfp.key, &rr->sshfp.key_size,
+                                               NULL);
+                break;
+
+        case DNS_TYPE_DNSKEY: {
+                uint16_t flags;
+                uint8_t proto;
+
+                r = dns_packet_read_uint16(p, &flags, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dnskey_parse_flags(rr, flags);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_uint8(p, &proto, NULL);
+                if (r < 0)
+                        goto fail;
+
+                /* protocol is required to be always 3 */
+                if (proto != 3) {
+                        r = -EBADMSG;
+                        goto fail;
+                }
+
+                r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
+                if (r < 0)
+                        goto fail;
+
+                r = dns_packet_read_public_key(p, rdlength - 4,
+                                               &rr->dnskey.key, &rr->dnskey.key_size,
+                                               NULL);
+                break;
+        }
+
         default:
+        unparseable:
                 r = dns_packet_read(p, rdlength, &d, NULL);
                 if (r < 0)
                         goto fail;
@@ -1196,3 +1361,15 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
         [DNS_PROTOCOL_LLMNR] = "llmnr",
 };
 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
+
+static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
+        [DNSSEC_ALGORITHM_RSAMD5]     = "RSAMD5",
+        [DNSSEC_ALGORITHM_DH]         = "DH",
+        [DNSSEC_ALGORITHM_DSA]        = "DSA",
+        [DNSSEC_ALGORITHM_ECC]        = "ECC",
+        [DNSSEC_ALGORITHM_RSASHA1]    = "RSASHA1",
+        [DNSSEC_ALGORITHM_INDIRECT]   = "INDIRECT",
+        [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
+        [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
+};
+DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);