1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-31 01:47:15 +03:00

Merge pull request #588 from teg/resolved-nsec

resolved: add basic NSEC and NSEC3 support
This commit is contained in:
Daniel Mack 2015-07-15 17:27:35 -04:00
commit 42921716a4
11 changed files with 1287 additions and 8 deletions

View File

@ -791,6 +791,8 @@ libbasic_la_SOURCES = \
src/basic/siphash24.h \
src/basic/set.h \
src/basic/ordered-set.h \
src/basic/bitmap.c \
src/basic/bitmap.h \
src/basic/fdset.c \
src/basic/fdset.h \
src/basic/prioq.c \
@ -1412,6 +1414,7 @@ tests += \
test-time \
test-hashmap \
test-set \
test-bitmap \
test-list \
test-unaligned \
test-tables \
@ -1768,6 +1771,12 @@ test_set_SOURCES = \
test_set_LDADD = \
libshared.la
test_bitmap_SOURCES = \
src/test/test-bitmap.c
test_bitmap_LDADD = \
libshared.la
test_xml_SOURCES = \
src/test/test-xml.c

208
src/basic/bitmap.c Normal file
View File

@ -0,0 +1,208 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2015 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "util.h"
#include "bitmap.h"
struct Bitmap {
long long unsigned *bitmaps;
size_t n_bitmaps;
size_t bitmaps_allocated;
unsigned next_entry;
};
/* Bitmaps are only meant to store relatively small numbers
* (corresponding to, say, an enum), so it is ok to limit
* the max entry. 64k should be plenty. */
#define BITMAPS_MAX_ENTRY 0xffff
/* This indicates that we reached the end of the bitmap */
#define BITMAP_END ((unsigned) -1)
#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(long long unsigned) * 8))
#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(long long unsigned) * 8))
#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(long long unsigned) * 8 + (rem))
Bitmap *bitmap_new(void) {
return new0(Bitmap, 1);
}
void bitmap_free(Bitmap *b) {
if (!b)
return;
free(b->bitmaps);
free(b);
}
int bitmap_ensure_allocated(Bitmap **b) {
Bitmap *a;
if (*b)
return 0;
a = bitmap_new();
if (!a)
return -ENOMEM;
*b = a;
return 0;
}
int bitmap_set(Bitmap *b, unsigned n) {
long long bitmask;
unsigned offset;
assert(b);
/* we refuse to allocate huge bitmaps */
if (n > BITMAPS_MAX_ENTRY)
return -ERANGE;
offset = BITMAP_NUM_TO_OFFSET(n);
if (offset >= b->n_bitmaps) {
if (!GREEDY_REALLOC0(b->bitmaps, b->bitmaps_allocated, offset + 1))
return -ENOMEM;
b->n_bitmaps = offset + 1;
}
bitmask = 1 << BITMAP_NUM_TO_REM(n);
b->bitmaps[offset] |= bitmask;
return 0;
}
void bitmap_unset(Bitmap *b, unsigned n) {
long long bitmask;
unsigned offset;
assert(b);
offset = BITMAP_NUM_TO_OFFSET(n);
if (offset >= b->n_bitmaps)
return;
bitmask = 1 << BITMAP_NUM_TO_REM(n);
b->bitmaps[offset] &= ~bitmask;
}
bool bitmap_isset(Bitmap *b, unsigned n) {
long long bitmask;
unsigned offset;
if (!b || !b->bitmaps)
return false;
offset = BITMAP_NUM_TO_OFFSET(n);
if (offset >= b->n_bitmaps)
return false;
bitmask = 1 << BITMAP_NUM_TO_REM(n);
return !!(b->bitmaps[offset] & bitmask);
}
bool bitmap_isclear(Bitmap *b) {
unsigned i;
assert(b);
for (i = 0; i < b->n_bitmaps; i++)
if (b->bitmaps[i])
return false;
return true;
}
void bitmap_clear(Bitmap *b) {
unsigned i;
assert(b);
for (i = 0; i < b->n_bitmaps; i++)
b->bitmaps[i] = 0;
}
void bitmap_rewind(Bitmap *b) {
if (!b)
return;
b->next_entry = 0;
}
bool bitmap_next(Bitmap *b, unsigned *n) {
long long bitmask;
unsigned offset, rem;
if (!b && b->next_entry == BITMAP_END)
return false;
offset = BITMAP_NUM_TO_OFFSET(b->next_entry);
rem = BITMAP_NUM_TO_REM(b->next_entry);
bitmask = 1 << rem;
for (; offset < b->n_bitmaps; offset ++) {
if (b->bitmaps[offset]) {
for (; bitmask; bitmask <<= 1, rem ++) {
if (b->bitmaps[offset] & bitmask) {
*n = BITMAP_OFFSET_TO_NUM(offset, rem);
b->next_entry = *n + 1;
return true;
}
}
}
rem = 0;
bitmask = 1;
}
b->next_entry = BITMAP_END;
return false;
}
bool bitmap_equal(Bitmap *a, Bitmap *b) {
unsigned i;
if (!a ^ !b)
return false;
if (!a)
return true;
if (a->n_bitmaps != b->n_bitmaps)
return false;
for (i = 0; i < a->n_bitmaps; i++)
if (a->bitmaps[i] != b->bitmaps[i])
return false;
return true;
}

50
src/basic/bitmap.h Normal file
View File

@ -0,0 +1,50 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2015 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "macro.h"
typedef struct Bitmap Bitmap;
Bitmap *bitmap_new(void);
void bitmap_free(Bitmap *b);
int bitmap_ensure_allocated(Bitmap **b);
int bitmap_set(Bitmap *b, unsigned n);
void bitmap_unset(Bitmap *b, unsigned n);
bool bitmap_isset(Bitmap *b, unsigned n);
bool bitmap_isclear(Bitmap *b);
void bitmap_clear(Bitmap *b);
void bitmap_rewind(Bitmap *b);
bool bitmap_next(Bitmap *b, unsigned *n);
bool bitmap_equal(Bitmap *a, Bitmap *b);
#define BITMAP_FOREACH(n, b) \
for (bitmap_rewind(b); bitmap_next((b), &(n)); )
DEFINE_TRIVIAL_CLEANUP_FUNC(Bitmap*, bitmap_free);
#define _cleanup_bitmap_free_ _cleanup_(bitmap_freep)

View File

@ -954,6 +954,351 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-6 */
char base32hexchar(int x) {
static const char table[32] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUV";
return table[x & 31];
}
int unbase32hexchar(char c) {
unsigned offset;
if (c >= '0' && c <= '9')
return c - '0';
offset = '9' - '0' + 1;
if (c >= 'A' && c <= 'V')
return c - 'A' + offset;
return -EINVAL;
}
char *base32hexmem(const void *p, size_t l, bool padding) {
char *r, *z;
const uint8_t *x;
size_t len;
if (padding)
/* five input bytes makes eight output bytes, padding is added so we must round up */
len = 8 * (l + 4) / 5;
else {
/* same, but round down as there is no padding */
len = 8 * l / 5;
switch (l % 5) {
case 4:
len += 7;
break;
case 3:
len += 5;
break;
case 2:
len += 4;
break;
case 1:
len += 2;
break;
}
}
z = r = malloc(len + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
*(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
}
switch (l % 5) {
case 4:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
if (padding)
*(z++) = '=';
break;
case 3:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 2:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 1:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
}
*z = 0;
return r;
}
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d, e, f, g, h;
uint8_t *z;
const char *x;
size_t len;
unsigned pad = 0;
assert(p);
/* padding ensures any base32hex input has input divisible by 8 */
if (padding && l % 8 != 0)
return -EINVAL;
if (padding) {
/* strip the padding */
while (l > 0 && p[l - 1] == '=' && pad < 7) {
pad ++;
l --;
}
}
/* a group of eight input bytes needs five output bytes, in case of
padding we need to add some extra bytes */
len = (l / 8) * 5;
switch (l % 8) {
case 7:
len += 4;
break;
case 5:
len += 3;
break;
case 4:
len += 2;
break;
case 2:
len += 1;
break;
case 0:
break;
default:
return -EINVAL;
}
z = r = malloc(len + 1);
if (!r)
return -ENOMEM;
for (x = p; x < p + (l / 8) * 8; x += 8) {
/* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
h = unbase32hexchar(x[7]);
if (h < 0)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
*(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
}
switch (l % 8) {
case 7:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
/* g == 000VV000 */
if (g & 7)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
break;
case 5:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
/* e == 000SSSS0 */
if (e & 1)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
break;
case 4:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
/* d == 000W0000 */
if (d & 15)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
break;
case 2:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
/* b == 000YYY00 */
if (b & 3)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;
*mem = r;
r = NULL;
*_len = len;
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-4 */
char base64char(int x) {
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -1117,6 +1462,11 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;

View File

@ -240,6 +240,8 @@ char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
char base32hexchar(int x) _const_;
int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
@ -618,6 +620,9 @@ static inline void *mempset(void *s, int c, size_t n) {
char *hexmem(const void *p, size_t l);
int unhexmem(const char *p, size_t l, void **mem, size_t *len);
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);

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,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);
@ -1521,6 +1787,8 @@ static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] =
[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",

View File

@ -223,6 +223,8 @@ enum {
DNSSEC_ALGORITHM_DSA,
DNSSEC_ALGORITHM_ECC,
DNSSEC_ALGORITHM_RSASHA1,
DNSSEC_ALGORITHM_DSA_NSEC3_SHA1,
DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1,
DNSSEC_ALGORITHM_INDIRECT = 252,
DNSSEC_ALGORITHM_PRIVATEDNS,
DNSSEC_ALGORITHM_PRIVATEOID,

View File

@ -288,6 +288,17 @@ 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_NSEC3:
free(rr->nsec3.next_hashed_name);
free(rr->nsec3.salt);
bitmap_free(rr->nsec3.types);
break;
case DNS_TYPE_LOC:
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
@ -448,6 +459,19 @@ 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);
case DNS_TYPE_NSEC3:
return a->nsec3.algorithm == b->nsec3.algorithm &&
a->nsec3.flags == b->nsec3.flags &&
a->nsec3.iterations == b->nsec3.iterations &&
a->nsec3.salt_size == b->nsec3.salt_size &&
memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
bitmap_equal(a->nsec3.types, b->nsec3.types);
default:
return a->generic.size == b->generic.size &&
memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
@ -500,6 +524,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 +759,50 @@ 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;
case DNS_TYPE_NSEC3: {
_cleanup_free_ char *salt = NULL, *hash = NULL;
if (rr->nsec3.salt_size) {
salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
if (!salt)
return -ENOMEM;
}
hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
if (!hash)
return -ENOMEM;
t = format_types(rr->nsec3.types);
if (!t)
return -ENOMEM;
r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
k,
rr->nsec3.algorithm,
rr->nsec3.flags,
rr->nsec3.iterations,
rr->nsec3.salt_size ? salt : "-",
hash,
t);
if (r < 0)
return -ENOMEM;
break;
}
default:
t = hexmem(rr->generic.data, rr->generic.size);
if (!t)

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,22 @@ struct DnsResourceRecord {
void *signature;
size_t signature_size;
} rrsig;
struct {
char *next_domain_name;
Bitmap *types;
} nsec;
struct {
uint8_t algorithm;
uint8_t flags;
uint16_t iterations;
void *salt;
size_t salt_size;
void *next_hashed_name;
size_t next_hashed_name_size;
Bitmap *types;
} nsec3;
};
};

96
src/test/test-bitmap.c Normal file
View File

@ -0,0 +1,96 @@
/***
This file is part of systemd
Copyright 2015 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "bitmap.h"
int main(int argc, const char *argv[]) {
_cleanup_bitmap_free_ Bitmap *b = NULL;
unsigned n = (unsigned) -1, i = 0;
b = bitmap_new();
assert_se(b);
assert_se(bitmap_ensure_allocated(&b) == 0);
bitmap_free(b);
b = NULL;
assert_se(bitmap_ensure_allocated(&b) == 0);
assert_se(bitmap_isset(b, 0) == false);
assert_se(bitmap_isset(b, 1) == false);
assert_se(bitmap_isset(b, 256) == false);
assert_se(bitmap_isclear(b) == true);
assert_se(bitmap_set(b, 0) == 0);
assert_se(bitmap_isset(b, 0) == true);
assert_se(bitmap_isclear(b) == false);
bitmap_unset(b, 0);
assert_se(bitmap_isset(b, 0) == false);
assert_se(bitmap_isclear(b) == true);
assert_se(bitmap_set(b, 1) == 0);
assert_se(bitmap_isset(b, 1) == true);
assert_se(bitmap_isclear(b) == false);
bitmap_unset(b, 1);
assert_se(bitmap_isset(b, 1) == false);
assert_se(bitmap_isclear(b) == true);
assert_se(bitmap_set(b, 256) == 0);
assert_se(bitmap_isset(b, 256) == true);
assert_se(bitmap_isclear(b) == false);
bitmap_unset(b, 256);
assert_se(bitmap_isset(b, 256) == false);
assert_se(bitmap_isclear(b) == true);
assert_se(bitmap_set(b, 0) == 0);
assert_se(bitmap_set(b, 1) == 0);
assert_se(bitmap_set(b, 256) == 0);
BITMAP_FOREACH(n, b) {
assert_se(n == i);
if (i == 0)
i = 1;
else if (i == 1)
i = 256;
else if (i == 256)
i = (unsigned) -1;
}
assert_se(i == (unsigned) -1);
i = 0;
BITMAP_FOREACH(n, b) {
assert_se(n == i);
if (i == 0)
i = 1;
else if (i == 1)
i = 256;
else if (i == 256)
i = (unsigned) -1;
}
assert_se(i == (unsigned) -1);
bitmap_clear(b);
assert_se(bitmap_isclear(b) == true);
assert_se(bitmap_set(b, (unsigned) -1) == -ERANGE);
return 0;
}

View File

@ -390,6 +390,21 @@ static void test_unhexchar(void) {
assert_se(unhexchar('0') == 0x0);
}
static void test_base32hexchar(void) {
assert_se(base32hexchar(0) == '0');
assert_se(base32hexchar(9) == '9');
assert_se(base32hexchar(10) == 'A');
assert_se(base32hexchar(31) == 'V');
}
static void test_unbase32hexchar(void) {
assert_se(unbase32hexchar('0') == 0);
assert_se(unbase32hexchar('9') == 9);
assert_se(unbase32hexchar('A') == 10);
assert_se(unbase32hexchar('V') == 31);
assert_se(unbase32hexchar('=') == -EINVAL);
}
static void test_base64char(void) {
assert_se(base64char(0) == 'A');
assert_se(base64char(26) == 'a');
@ -452,6 +467,162 @@ static void test_unhexmem(void) {
assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
}
/* https://tools.ietf.org/html/rfc4648#section-10 */
static void test_base32hexmem(void) {
char *b32;
b32 = base32hexmem("", strlen(""), true);
assert_se(b32);
assert_se(streq(b32, ""));
free(b32);
b32 = base32hexmem("f", strlen("f"), true);
assert_se(b32);
assert_se(streq(b32, "CO======"));
free(b32);
b32 = base32hexmem("fo", strlen("fo"), true);
assert_se(b32);
assert_se(streq(b32, "CPNG===="));
free(b32);
b32 = base32hexmem("foo", strlen("foo"), true);
assert_se(b32);
assert_se(streq(b32, "CPNMU==="));
free(b32);
b32 = base32hexmem("foob", strlen("foob"), true);
assert_se(b32);
assert_se(streq(b32, "CPNMUOG="));
free(b32);
b32 = base32hexmem("fooba", strlen("fooba"), true);
assert_se(b32);
assert_se(streq(b32, "CPNMUOJ1"));
free(b32);
b32 = base32hexmem("foobar", strlen("foobar"), true);
assert_se(b32);
assert_se(streq(b32, "CPNMUOJ1E8======"));
free(b32);
b32 = base32hexmem("", strlen(""), false);
assert_se(b32);
assert_se(streq(b32, ""));
free(b32);
b32 = base32hexmem("f", strlen("f"), false);
assert_se(b32);
assert_se(streq(b32, "CO"));
free(b32);
b32 = base32hexmem("fo", strlen("fo"), false);
assert_se(b32);
assert_se(streq(b32, "CPNG"));
free(b32);
b32 = base32hexmem("foo", strlen("foo"), false);
assert_se(b32);
assert_se(streq(b32, "CPNMU"));
free(b32);
b32 = base32hexmem("foob", strlen("foob"), false);
assert_se(b32);
assert_se(streq(b32, "CPNMUOG"));
free(b32);
b32 = base32hexmem("fooba", strlen("fooba"), false);
assert_se(b32);
assert_se(streq(b32, "CPNMUOJ1"));
free(b32);
b32 = base32hexmem("foobar", strlen("foobar"), false);
assert_se(b32);
assert_se(streq(b32, "CPNMUOJ1E8"));
free(b32);
}
static void test_unbase32hexmem(void) {
void *mem;
size_t len;
assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), ""));
free(mem);
assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "f"));
free(mem);
assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "fo"));
free(mem);
assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foo"));
free(mem);
assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foob"));
free(mem);
assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "fooba"));
free(mem);
assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foobar"));
free(mem);
assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), ""));
free(mem);
assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "f"));
free(mem);
assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "fo"));
free(mem);
assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foo"));
free(mem);
assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foob"));
free(mem);
assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "fooba"));
free(mem);
assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0);
assert_se(streq(strndupa(mem, len), "foobar"));
free(mem);
assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL);
assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL);
}
/* https://tools.ietf.org/html/rfc4648#section-10 */
static void test_base64mem(void) {
char *b64;
@ -1924,6 +2095,8 @@ int main(int argc, char *argv[]) {
test_in_charset();
test_hexchar();
test_unhexchar();
test_base32hexchar();
test_unbase32hexchar();
test_base64char();
test_unbase64char();
test_octchar();
@ -1931,6 +2104,8 @@ int main(int argc, char *argv[]) {
test_decchar();
test_undecchar();
test_unhexmem();
test_base32hexmem();
test_unbase32hexmem();
test_base64mem();
test_unbase64mem();
test_cescape();