From: Zbigniew Jędrzejewski-Szmek Date: Sun, 3 Aug 2014 20:05:41 +0000 (-0400) Subject: resolved: DNSKEY records X-Git-Tag: v216~276 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939 resolved: DNSKEY records --- diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index ba056f1f4..951c79808 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -632,6 +632,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star 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; @@ -639,6 +640,22 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star 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: @@ -942,12 +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; @@ -1143,7 +1189,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { } case DNS_TYPE_SSHFP: - r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL); if (r < 0) goto fail; @@ -1152,18 +1197,42 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read(p, rdlength - 2, &d, NULL); + 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; - rr->sshfp.key = memdup(d, rdlength - 2); - if (!rr->sshfp.key) { - r = -ENOMEM; + 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; } - rr->sshfp.key_size = rdlength - 2; + 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: diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index af51f16c3..4e3001911 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -192,3 +192,11 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_; #define LLMNR_MULTICAST_IPV4_ADDRESS ((struct in_addr) { .s_addr = htobe32(224U << 24 | 252U) }) #define LLMNR_MULTICAST_IPV6_ADDRESS ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03 } }) + +#define DNSKEY_FLAG_ZONE_KEY (1u << 8) +#define DNSKEY_FLAG_SEP (1u << 0) + +static inline uint16_t dnskey_to_flags(const DnsResourceRecord *rr) { + return (rr->dnskey.zone_key_flag * DNSKEY_FLAG_ZONE_KEY | + rr->dnskey.sep_flag * DNSKEY_FLAG_SEP); +} diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index af22a8901..ada7333a6 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -25,6 +25,7 @@ #include "resolved-dns-domain.h" #include "resolved-dns-rr.h" +#include "resolved-dns-packet.h" #include "dns-type.h" DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { @@ -269,6 +270,10 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { free(rr->sshfp.key); break; + case DNS_TYPE_DNSKEY: + free(rr->dnskey.key); + break; + case DNS_TYPE_LOC: case DNS_TYPE_A: case DNS_TYPE_AAAA: @@ -406,6 +411,13 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor a->sshfp.key_size == b->sshfp.key_size && memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0; + case DNS_TYPE_DNSKEY: + return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag && + a->dnskey.sep_flag == b->dnskey.sep_flag && + a->dnskey.algorithm == b->dnskey.algorithm && + a->dnskey.key_size == b->dnskey.key_size && + memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0; + default: return a->generic.size == b->generic.size && memcmp(a->generic.data, b->generic.data, a->generic.size) == 0; @@ -444,7 +456,7 @@ static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t alt } int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { - _cleanup_free_ char *k = NULL; + _cleanup_free_ char *k = NULL, *t = NULL; char *s; int r; @@ -484,9 +496,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { break; case DNS_TYPE_SPF: /* exactly the same as TXT */ - case DNS_TYPE_TXT: { - _cleanup_free_ char *t; - + case DNS_TYPE_TXT: t = strv_join_quoted(rr->txt.strings); if (!t) return -ENOMEM; @@ -496,7 +506,6 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { return -ENOMEM; break; - } case DNS_TYPE_A: { _cleanup_free_ char *x = NULL; @@ -511,18 +520,15 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { break; } - case DNS_TYPE_AAAA: { - _cleanup_free_ char *x = NULL; - - r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x); + case DNS_TYPE_AAAA: + r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t); if (r < 0) return r; - s = strjoin(k, " ", x, NULL); + s = strjoin(k, " ", t, NULL); if (!s) return -ENOMEM; break; - } case DNS_TYPE_SOA: r = asprintf(&s, "%s %s %s %u %u %u %u %u", @@ -547,55 +553,61 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { return -ENOMEM; break; - case DNS_TYPE_LOC: { - _cleanup_free_ char *loc; + case DNS_TYPE_LOC: assert(rr->loc.version == 0); - loc = format_location(rr->loc.latitude, - rr->loc.longitude, - rr->loc.altitude, - rr->loc.size, - rr->loc.horiz_pre, - rr->loc.vert_pre); - if (!loc) + t = format_location(rr->loc.latitude, + rr->loc.longitude, + rr->loc.altitude, + rr->loc.size, + rr->loc.horiz_pre, + rr->loc.vert_pre); + if (!t) return -ENOMEM; - s = strjoin(k, " ", loc, NULL); + s = strjoin(k, " ", t, NULL); if (!s) return -ENOMEM; - break; - } - case DNS_TYPE_SSHFP: { - _cleanup_free_ char *x = NULL; - - x = hexmem(rr->sshfp.key, rr->sshfp.key_size); - if (!x) + case DNS_TYPE_SSHFP: + t = hexmem(rr->sshfp.key, rr->sshfp.key_size); + if (!t) return -ENOMEM; r = asprintf(&s, "%s %u %u %s", k, rr->sshfp.algorithm, rr->sshfp.fptype, - x); + t); if (r < 0) return -ENOMEM; break; - } - default: { - _cleanup_free_ char *x = NULL; + case DNS_TYPE_DNSKEY: + t = hexmem(rr->dnskey.key, rr->dnskey.key_size); + if (!t) + return -ENOMEM; - x = hexmem(rr->generic.data, rr->generic.size); - if (!x) + r = asprintf(&s, "%s %u 3 %u %s", + k, + dnskey_to_flags(rr), + rr->dnskey.algorithm, + t); + if (r < 0) return -ENOMEM; + break; - s = strjoin(k, " ", x, NULL); + default: + t = hexmem(rr->generic.data, rr->generic.size); + if (!t) + return -ENOMEM; + + s = strjoin(k, " ", t, NULL); if (!s) return -ENOMEM; break; - }} + } *ret = s; return 0; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 20a344b8c..e2272643f 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -116,6 +116,15 @@ struct DnsResourceRecord { void *key; size_t key_size; } sshfp; + + /* http://tools.ietf.org/html/rfc4034#section-2.1 */ + struct { + bool zone_key_flag:1; + bool sep_flag:1; + uint8_t algorithm; + void* key; + size_t key_size; + } dnskey; }; };