diff options
author | Daniel Mack <github@zonque.org> | 2015-07-15 17:27:35 -0400 |
---|---|---|
committer | Daniel Mack <github@zonque.org> | 2015-07-15 17:27:35 -0400 |
commit | 42921716a4d693cd72044b3626a7e87210d72eb3 (patch) | |
tree | 415cb60c2839f6dd1e020613faa8febb4ada252e /src/resolve/resolved-dns-packet.c | |
parent | 7ee7b225bd2fc3e7a3980f5fb7b10dfc6e205578 (diff) | |
parent | 5d45a8808431987c370706d365fb0cc95cf03d52 (diff) |
Merge pull request #588 from teg/resolved-nsec
resolved: add basic NSEC and NSEC3 support
Diffstat (limited to 'src/resolve/resolved-dns-packet.c')
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 284 |
1 files changed, 276 insertions, 8 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 1ebebf8ea4..e44d3926d9 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -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,50 @@ 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_NSEC3: + r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_types(p, rr->nsec3.types, NULL); + if (r < 0) + goto fail; + + break; case _DNS_TYPE_INVALID: /* unparseable */ default: @@ -996,6 +1123,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 +1582,72 @@ 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; + + case DNS_TYPE_NSEC3: { + uint8_t size; + + r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &size, NULL); + if (r < 0) + goto fail; + + rr->nsec3.salt_size = size; + + r = dns_packet_read_blob(p, &d, rr->nsec3.salt_size, NULL); + if (r < 0) + goto fail; + + rr->nsec3.salt = memdup(d, rr->nsec3.salt_size); + if (!rr->nsec3.salt) { + r = -ENOMEM; + goto fail; + } + + r = dns_packet_read_uint8(p, &size, NULL); + if (r < 0) + goto fail; + + rr->nsec3.next_hashed_name_size = size; + + r = dns_packet_read(p, rr->nsec3.next_hashed_name_size, &d, NULL); + if (r < 0) + goto fail; + + rr->nsec3.next_hashed_name = memdup(d, rr->nsec3.next_hashed_name_size); + if (!rr->nsec3.next_hashed_name) { + r = -ENOMEM; + goto fail; + } + + r = dns_packet_append_types(p, rr->nsec3.types, NULL); + if (r < 0) + goto fail; + + break; + } default: unparseable: r = dns_packet_read(p, rdlength, &d, NULL); @@ -1516,13 +1782,15 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = { 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", + [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", + [DNSSEC_ALGORITHM_DH] = "DH", + [DNSSEC_ALGORITHM_DSA] = "DSA", + [DNSSEC_ALGORITHM_ECC] = "ECC", + [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1", + [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1", + [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", + [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", + [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", + [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", }; DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int); |