From 151226ab4bf276d60d51864330a99f886b923697 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 3 Aug 2014 18:17:22 -0400 Subject: [PATCH] resolved: RRSIG records --- TODO | 1 + src/resolve/resolved-dns-packet.c | 129 ++++++++++++++++++++++++------ src/resolve/resolved-dns-packet.h | 6 +- src/resolve/resolved-dns-rr.c | 51 ++++++++++++ src/resolve/resolved-dns-rr.h | 14 ++++ 5 files changed, 175 insertions(+), 26 deletions(-) diff --git a/TODO b/TODO index 3f13b913d..a0f71f5dd 100644 --- a/TODO +++ b/TODO @@ -32,6 +32,7 @@ Features: - DNSSEC - use base64 for key presentation? - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)? + - add nice formatting of DNS timestamps - LLMNR: - do not fail daemon startup if socket is already busy (container) - process incoming notification of conflict diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 626b904d9..b97fd1796 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -377,7 +377,8 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start return 0; } -int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) { +int dns_packet_append_name(DnsPacket *p, const char *name, + bool allow_compression, size_t *start) { size_t saved_size; int r; @@ -389,10 +390,11 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) { while (*name) { _cleanup_free_ char *s = NULL; char label[DNS_LABEL_MAX]; - size_t n; + size_t n = 0; int k; - n = PTR_TO_SIZE(hashmap_get(p->names, name)); + if (allow_compression) + n = PTR_TO_SIZE(hashmap_get(p->names, name)); if (n > 0) { assert(n < p->size); @@ -430,15 +432,19 @@ int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) { if (r < 0) goto fail; - r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func); - if (r < 0) - goto fail; + if (allow_compression) { + r = hashmap_ensure_allocated(&p->names, + dns_name_hash_func, + dns_name_compare_func); + if (r < 0) + goto fail; - r = hashmap_put(p->names, s, SIZE_TO_PTR(n)); - if (r < 0) - goto fail; + r = hashmap_put(p->names, s, SIZE_TO_PTR(n)); + if (r < 0) + goto fail; - s = NULL; + s = NULL; + } } r = dns_packet_append_uint8(p, 0, NULL); @@ -465,7 +471,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), NULL); + r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL); if (r < 0) goto fail; @@ -524,14 +530,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, NULL); + r = dns_packet_append_name(p, rr->srv.name, true, 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); + r = dns_packet_append_name(p, rr->ptr.name, true, NULL); break; case DNS_TYPE_HINFO: @@ -565,11 +571,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, NULL); + r = dns_packet_append_name(p, rr->soa.mname, true, NULL); if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->soa.rname, NULL); + r = dns_packet_append_name(p, rr->soa.rname, true, NULL); if (r < 0) goto fail; @@ -597,7 +603,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, NULL); + r = dns_packet_append_name(p, rr->mx.exchange, true, NULL); break; case DNS_TYPE_LOC: @@ -656,6 +662,42 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL); break; + case DNS_TYPE_RRSIG: + r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL); + break; + case _DNS_TYPE_INVALID: /* unparseable */ default: @@ -824,7 +866,8 @@ fail: return r; } -int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) { +int dns_packet_read_name(DnsPacket *p, char **_ret, + bool allow_compression, size_t *start) { size_t saved_rindex, after_rindex = 0; _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; @@ -872,7 +915,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) { memcpy(ret + n, t, r); n += r; continue; - } else if ((c & 0xc0) == 0xc0) { + } else if (allow_compression && (c & 0xc0) == 0xc0) { uint16_t ptr; /* Pointer */ @@ -929,7 +972,7 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { saved_rindex = p->rindex; - r = dns_packet_read_name(p, &name, NULL); + r = dns_packet_read_name(p, &name, true, NULL); if (r < 0) goto fail; @@ -1050,14 +1093,14 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { 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); + r = dns_packet_read_name(p, &rr->srv.name, true, 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); + r = dns_packet_read_name(p, &rr->ptr.name, true, NULL); break; case DNS_TYPE_HINFO: @@ -1095,11 +1138,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; case DNS_TYPE_SOA: - r = dns_packet_read_name(p, &rr->soa.mname, NULL); + r = dns_packet_read_name(p, &rr->soa.mname, true, NULL); if (r < 0) goto fail; - r = dns_packet_read_name(p, &rr->soa.rname, NULL); + r = dns_packet_read_name(p, &rr->soa.rname, true, NULL); if (r < 0) goto fail; @@ -1127,7 +1170,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_name(p, &rr->mx.exchange, NULL); + r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL); break; case DNS_TYPE_LOC: { @@ -1234,6 +1277,44 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; } + case DNS_TYPE_RRSIG: + r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_public_key(p, offset + rdlength - p->rindex, + &rr->rrsig.signature, &rr->rrsig.signature_size, + NULL); + break; + default: unparseable: r = dns_packet_read(p, rdlength, &d, NULL); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index f3b0f0c9e..26a2e7646 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -142,7 +142,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_label(DnsPacket *p, const char *s, size_t l, size_t *start); -int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start); +int dns_packet_append_name(DnsPacket *p, const char *name, + bool allow_compression, 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); @@ -152,7 +153,8 @@ int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start); int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start); int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start); int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start); -int dns_packet_read_name(DnsPacket *p, char **ret, size_t *start); +int dns_packet_read_name(DnsPacket *p, char **ret, + bool allow_compression, size_t *start); int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start); int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index bc0cbef92..c792deda4 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -274,6 +274,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { free(rr->dnskey.key); break; + case DNS_TYPE_RRSIG: + free(rr->rrsig.signer); + free(rr->rrsig.signature); + break; + case DNS_TYPE_LOC: case DNS_TYPE_A: case DNS_TYPE_AAAA: @@ -418,6 +423,21 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor a->dnskey.key_size == b->dnskey.key_size && memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0; + case DNS_TYPE_RRSIG: + /* do the fast comparisons first */ + if (a->rrsig.type_covered != a->rrsig.type_covered || + a->rrsig.algorithm != a->rrsig.algorithm || + a->rrsig.labels != a->rrsig.labels || + a->rrsig.original_ttl != a->rrsig.original_ttl || + a->rrsig.expiration != a->rrsig.expiration || + a->rrsig.inception != a->rrsig.inception || + a->rrsig.key_tag != a->rrsig.key_tag || + a->rrsig.signature_size != b->rrsig.signature_size || + memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0) + return false; + + return dns_name_equal(a->rrsig.signer, b->rrsig.signer); + default: return a->generic.size == b->generic.size && memcmp(a->generic.data, b->generic.data, a->generic.size) == 0; @@ -604,6 +624,37 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { break; } + case DNS_TYPE_RRSIG: { + const char *type, *alg; + + type = dns_type_to_string(rr->rrsig.type_covered); + alg = dnssec_algorithm_to_string(rr->rrsig.algorithm); + + t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size); + if (!t) + return -ENOMEM; + + /* TYPE?? follows + * http://tools.ietf.org/html/rfc3597#section-5 */ + + r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s", + k, + type ?: "TYPE", + type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered, + alg ? -1 : 0, alg, + alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm, + rr->rrsig.labels, + rr->rrsig.original_ttl, + rr->rrsig.expiration, + rr->rrsig.inception, + rr->rrsig.key_tag, + rr->rrsig.signer, + t); + if (r < 0) + return -ENOMEM; + break; + } + default: t = hexmem(rr->generic.data, rr->generic.size); if (!t) diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index e2272643f..3222f1f0e 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -125,6 +125,20 @@ struct DnsResourceRecord { void* key; size_t key_size; } dnskey; + + /* http://tools.ietf.org/html/rfc4034#section-3.1 */ + struct { + uint16_t type_covered; + uint8_t algorithm; + uint8_t labels; + uint32_t original_ttl; + uint32_t expiration; + uint32_t inception; + uint16_t key_tag; + char *signer; + void *signature; + size_t signature_size; + } rrsig; }; }; -- 2.30.2