knot-dns/tests/knot/test_conf.c

331 lines
8.9 KiB
C

/* Copyright (C) CZ.NIC, z.s.p.o. and contributors
* SPDX-License-Identifier: GPL-2.0-or-later
* For more information, see <https://www.knot-dns.cz/>
*/
#define CONFIG_DIR "/tmp"
#include <tap/basic.h>
#include "knot/conf/conf.c"
#include "test_conf.h"
#define ZONE_ARPA "0/25.2.0.192.in-addr.arpa."
#define ZONE_ROOT "."
#define ZONE_1LABEL "x."
#define ZONE_3LABEL "abc.ab.a."
#define ZONE_UNKNOWN "unknown."
static void check_name(const char *zone, const char *name, const char *ref)
{
knot_dname_t *z = knot_dname_from_str_alloc(zone);
char *file = conf_get_filename_txn(conf(), NULL, z, name);
ok(file != NULL, "Get zonefile path for %s", zone);
if (file != NULL) {
ok(strcmp(file, ref) == 0, "Zonefile path compare %s", name);
free(file);
}
knot_dname_free(z, NULL);
}
static void check_name_err(const char *zone, const char *name)
{
knot_dname_t *z = knot_dname_from_str_alloc(zone);
char *filename = conf_get_filename_txn(conf(), NULL, z, name);
ok(filename == NULL, "Invalid name %s", name);
free(filename);
knot_dname_free(z, NULL);
}
static void test_get_filename(void)
{
int ret = test_conf("", NULL);
is_int(KNOT_EOK, ret, "Prepare empty configuration");
// Name formatter.
char *zone = "abc";
check_name(zone, "/%s", "/abc");
zone = ".";
check_name(zone, "/%s", "/");
// Char formatter.
zone = "abc.def.g";
check_name(zone, "/%c[0]", "/a");
check_name(zone, "/%c[3]", "/.");
check_name(zone, "/%c[8]", "/g");
check_name(zone, "/%c[9]", "/.");
check_name(zone, "/%c[10]", "/");
check_name(zone, "/%c[255]", "/");
check_name(zone, "/%c[0-1]", "/ab");
check_name(zone, "/%c[1-1]", "/b");
check_name(zone, "/%c[1-3]", "/bc.");
check_name(zone, "/%c[1-4]", "/bc.d");
check_name(zone, "/%c[254-255]", "/");
check_name_err(zone, "/%c");
check_name_err(zone, "/%cx");
check_name_err(zone, "/%c[a]");
check_name_err(zone, "/%c[:]");
check_name_err(zone, "/%c[/]");
check_name_err(zone, "/%c[-1]");
check_name_err(zone, "/%c[256]");
check_name_err(zone, "/%c[");
check_name_err(zone, "/%c[1");
check_name_err(zone, "/%c[1-");
check_name_err(zone, "/%c[1-2");
check_name_err(zone, "/%c[1-b]");
check_name_err(zone, "/%c[8-0]");
zone = "abcd";
check_name(zone, "/%c[2-9]", "/cd.");
check_name(zone, "/%c[3]", "/d");
check_name(zone, "/%c[4]", "/.");
zone = ".";
check_name(zone, "/%c[0]", "/.");
check_name(zone, "/%c[1]", "/");
// Label formatter.
zone = "abc.def.gh";
check_name(zone, "/%l[0]", "/gh");
check_name(zone, "/%l[1]", "/def");
check_name(zone, "/%l[2]", "/abc");
check_name(zone, "/%l[3]", "/");
check_name(zone, "/%l[255]", "/");
check_name(zone, "/%l[0]-%l[1]-%l[2]", "/gh-def-abc");
check_name_err(zone, "/%l[0-1]");
check_name_err(zone, "/%l[-1]");
check_name_err(zone, "/%l[256]");
zone = ".";
check_name(zone, "/%l[0]", "/");
check_name(zone, "/%l[1]", "/");
test_conf_free();
}
static void test_conf_zonefile(void)
{
int ret;
char *file;
knot_dname_t *zone_arpa = knot_dname_from_str_alloc(ZONE_ARPA);
ok(zone_arpa != NULL, "create dname "ZONE_ARPA);
knot_dname_t *zone_root = knot_dname_from_str_alloc(ZONE_ROOT);
ok(zone_root != NULL, "create dname "ZONE_ROOT);
knot_dname_t *zone_1label = knot_dname_from_str_alloc(ZONE_1LABEL);
ok(zone_1label != NULL, "create dname "ZONE_1LABEL);
knot_dname_t *zone_3label = knot_dname_from_str_alloc(ZONE_3LABEL);
ok(zone_3label != NULL, "create dname "ZONE_3LABEL);
knot_dname_t *zone_unknown = knot_dname_from_str_alloc(ZONE_UNKNOWN);
ok(zone_unknown != NULL, "create dname "ZONE_UNKNOWN);
const char *conf_str =
"template:\n"
" - id: default\n"
" storage: /tmp\n"
"\n"
"zone:\n"
" - domain: "ZONE_ARPA"\n"
" file: dir/a%%b/%s.suffix/%a\n"
" - domain: "ZONE_ROOT"\n"
" file: /%s\n"
" - domain: "ZONE_1LABEL"\n"
" file: /%s\n"
" - domain: "ZONE_3LABEL"\n";
ret = test_conf(conf_str, NULL);
is_int(KNOT_EOK, ret, "Prepare configuration");
// Relative path with formatters.
file = conf_zonefile(conf(), zone_arpa);
ok(file != NULL, "Get zonefile path for "ZONE_ARPA);
if (file != NULL) {
ok(strcmp(file, "/tmp/dir/a%b/0_25.2.0.192.in-addr.arpa.suffix/") == 0,
"Zonefile path compare for "ZONE_ARPA);
free(file);
}
// Absolute path without formatters - root zone.
file = conf_zonefile(conf(), zone_root);
ok(file != NULL, "Get zonefile path for "ZONE_ROOT);
if (file != NULL) {
ok(strcmp(file, "/") == 0,
"Zonefile path compare for "ZONE_ROOT);
free(file);
}
// Absolute path without formatters - non-root zone.
file = conf_zonefile(conf(), zone_1label);
ok(file != NULL, "Get zonefile path for "ZONE_1LABEL);
if (file != NULL) {
ok(strcmp(file, "/x") == 0,
"Zonefile path compare for "ZONE_1LABEL);
free(file);
}
// Default zonefile path.
file = conf_zonefile(conf(), zone_3label);
ok(file != NULL, "Get zonefile path for "ZONE_3LABEL);
if (file != NULL) {
ok(strcmp(file, "/tmp/abc.ab.a.zone") == 0,
"Zonefile path compare for "ZONE_3LABEL);
free(file);
}
// Unknown zone zonefile path.
file = conf_zonefile(conf(), zone_unknown);
ok(file != NULL, "Get zonefile path for "ZONE_UNKNOWN);
if (file != NULL) {
ok(strcmp(file, "/tmp/unknown.zone") == 0,
"Zonefile path compare for "ZONE_UNKNOWN);
free(file);
}
test_conf_free();
knot_dname_free(zone_arpa, NULL);
knot_dname_free(zone_root, NULL);
knot_dname_free(zone_1label, NULL);
knot_dname_free(zone_3label, NULL);
knot_dname_free(zone_unknown, NULL);
}
static void test_mix_ref(void)
{
const char *conf_string =
"remote:\n"
" - id: r1\n"
" address: ::1\n"
" - id: r2\n"
" address: ::2\n"
" - id: r3\n"
" address: ::3\n"
" - id: r4\n"
" address: ::4\n"
" - id: r5\n"
" address: ::5\n"
"remotes:\n"
" - id: rs2\n"
" remote: [r2]\n"
" - id: rs45\n"
" remote: [r4, r5]\n"
"\n"
"submission:\n"
" - id: t1\n"
" parent: [r1, rs2, r3, rs45]\n"
" - id: t2\n"
" parent: [rs45, r2, r1]\n";
int ret = test_conf(conf_string, NULL);
is_int(KNOT_EOK, ret, "Prepare configuration");
size_t cnt1 = 0;
conf_val_t test1 = conf_rawid_get(conf(), C_SBM, C_PARENT, (const uint8_t *)"t1", 3);
conf_mix_iter_t iter1;
conf_mix_iter_init(conf(), &test1, &iter1);
while (iter1.id->code == KNOT_EOK) {
cnt1++;
conf_mix_iter_next(&iter1);
}
is_int(5, cnt1, "number of mixed references 1");
size_t cnt2 = 0;
conf_val_t test2 = conf_rawid_get(conf(), C_SBM, C_PARENT, (const uint8_t *)"t2", 3);
conf_mix_iter_t iter2;
conf_mix_iter_init(conf(), &test2, &iter2);
while (iter2.id->code == KNOT_EOK) {
cnt2++;
conf_mix_iter_next(&iter2);
}
is_int(4, cnt2, "number of mixed references 2");
test_conf_free();
}
static void check_addrs(struct sockaddr_storage *addr, struct sockaddr_storage *via,
int family, const char *addr_str, const char *via_str)
{
struct sockaddr_storage ref = { 0 };
int set_ret = sockaddr_set(&ref, family, addr_str, 0);
int cmp_ret = sockaddr_cmp(&ref, addr, true);
is_int(KNOT_EOK, set_ret, "set address '%s'", addr_str);
is_int(KNOT_EOK, cmp_ret, "cmp address '%s'", addr_str);
if (via_str != NULL) {
set_ret = sockaddr_set(&ref, family, via_str, 0);
cmp_ret = sockaddr_cmp(&ref, via, true);
is_int(KNOT_EOK, set_ret, "set via '%s'", via_str);
is_int(KNOT_EOK, cmp_ret, "cmp via '%s'", via_str);
} else {
is_int(AF_UNSPEC, via->ss_family, "empty via");
}
}
static void test_conf_remote(void)
{
const char *conf_string =
"remote:\n"
" - id: r1\n"
" address: [1::2, 1.0.0.2, 2::2, 3::2, 2.0.0.2]\n"
" via: [1::1, 2::1, 1.0.0.1, 2.0.0.1]\n"
" - id: r2\n"
" address: [1::2, 1.0.0.2, 2::2]\n"
" via: [1::1, 2::1, 3::1]\n"
"template:\n"
" - id: t1\n"
" notify: r1\n"
" - id: t2\n"
" notify: r2\n";
int ret = test_conf(conf_string, NULL);
is_int(KNOT_EOK, ret, "Prepare configuration");
conf_remote_t r;
conf_val_t id;
id = conf_rawid_get(conf(), C_TPL, C_NOTIFY, (const uint8_t *)"t1", 3);
r = conf_remote(conf(), &id, 0);
check_addrs(&r.addr, &r.via, AF_INET6, "1::2", "1::1");
r = conf_remote(conf(), &id, 1);
check_addrs(&r.addr, &r.via, AF_INET, "1.0.0.2", "1.0.0.1");
r = conf_remote(conf(), &id, 2);
check_addrs(&r.addr, &r.via, AF_INET6, "2::2", "2::1");
r = conf_remote(conf(), &id, 3);
check_addrs(&r.addr, &r.via, AF_INET6, "3::2", "2::1");
r = conf_remote(conf(), &id, 4);
check_addrs(&r.addr, &r.via, AF_INET, "2.0.0.2", "2.0.0.1");
id = conf_rawid_get(conf(), C_TPL, C_NOTIFY, (const uint8_t *)"t2", 3);
r = conf_remote(conf(), &id, 0);
check_addrs(&r.addr, &r.via, AF_INET6, "1::2", "1::1");
r = conf_remote(conf(), &id, 1);
check_addrs(&r.addr, &r.via, AF_INET, "1.0.0.2", NULL);
r = conf_remote(conf(), &id, 2);
check_addrs(&r.addr, &r.via, AF_INET6, "2::2", "2::1");
test_conf_free();
}
int main(int argc, char *argv[])
{
plan_lazy();
diag("get_filename");
test_get_filename();
diag("conf_zonefile");
test_conf_zonefile();
diag("mixed references");
test_mix_ref();
diag("conf_remote");
test_conf_remote();
return 0;
}