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:
commit
42921716a4
@ -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
208
src/basic/bitmap.c
Normal 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
50
src/basic/bitmap.h
Normal 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)
|
350
src/basic/util.c
350
src/basic/util.c
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
96
src/test/test-bitmap.c
Normal 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;
|
||||
}
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user