resolved: rr - add NSEC support

Needed for DNSSEC.
This commit is contained in:
Tom Gundersen
2015-07-14 21:53:10 +02:00
parent 5ffa42cb80
commit 50f1e641a9
3 changed files with 237 additions and 0 deletions
+178
View 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);
+53
View 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)
+6
View 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;
};
};