resolved: rr - add NSEC support
Needed for DNSSEC.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user