mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-03-03 05:50:31 -05:00
405 lines
12 KiB
C
405 lines
12 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/>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <tap/basic.h>
|
|
|
|
#include "libknot/yparser/yptrafo.h"
|
|
#include "libknot/libknot.h"
|
|
|
|
static void int_test(const char *txt, int64_t num, yp_style_t s,
|
|
int64_t min, int64_t max)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
|
|
|
|
diag("integer \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(yp_int(b) == num, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, s | YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void int_bad_test(const char *txt, int code, yp_style_t s,
|
|
int64_t min, int64_t max)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
|
|
|
|
diag("integer \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void bool_test(const char *txt, bool val)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
|
|
|
|
diag("boolean \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(yp_bool(b) == val, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void bool_bad_test(const char *txt, int code)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
|
|
|
|
diag("boolean \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void opt_test(const char *txt, unsigned val, const knot_lookup_t *opts)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
|
|
|
|
diag("option \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(b_len == 1, "compare length");
|
|
ok(yp_opt(b) == val, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void opt_bad_test(const char *txt, int code, const knot_lookup_t *opts)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
|
|
|
|
diag("option \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void str_test(const char *txt, const char *val)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TSTR, YP_VNONE };
|
|
|
|
diag("string \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(b_len == strlen(txt) + 1, "compare length");
|
|
ok(memcmp(yp_str(b), val, b_len) == 0, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void addr_test(const char *txt, bool port)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
|
|
|
|
diag("address \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
bool no_port;
|
|
yp_addr(b, &no_port);
|
|
ok(no_port == port, "compare port presence");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void addr_bad_test(const char *txt, int code)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
|
|
|
|
diag("address \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void addr_range_test(const char *txt)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TNET, YP_VNONE };
|
|
|
|
diag("address range \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void addr_range_bad_test(const char *txt, int code)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_TNET, YP_VNONE };
|
|
|
|
diag("address range \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void dname_test(const char *txt, const char *val)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TDNAME, YP_VNONE };
|
|
|
|
diag("dname \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(memcmp(yp_dname(b), val, b_len) == 0, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void hex_test(const char *txt, const char *val, const char *txt_out)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_THEX, YP_VNONE };
|
|
|
|
if (txt_out == NULL) {
|
|
txt_out = txt;
|
|
}
|
|
|
|
diag("hex \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt_out) == t_len, "txt length");
|
|
ok(memcmp(txt_out, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void hex_bad_test(const char *txt, int code)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
yp_item_t i = { NULL, YP_THEX, YP_VNONE };
|
|
|
|
diag("hex \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
ok(ret == code, "invalid txt to bin");
|
|
}
|
|
|
|
static void base64_test(const char *txt, const char *val)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t i = { NULL, YP_TB64, YP_VNONE };
|
|
|
|
diag("base64 \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
static void ref_test(const char *txt, bool val)
|
|
{
|
|
int ret;
|
|
uint8_t b[64];
|
|
size_t b_len = sizeof(b);
|
|
char t[64];
|
|
size_t t_len = sizeof(t);
|
|
yp_item_t id = { NULL, YP_TBOOL, YP_VNONE };
|
|
yp_item_t ref = { NULL, YP_TGRP, YP_VNONE };
|
|
yp_item_t i = { NULL, YP_TREF, YP_VNONE };
|
|
ref.var.g.id = &id;
|
|
i.var.r.ref = &ref;
|
|
|
|
diag("reference to boolean \"%s\":", txt);
|
|
ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
|
|
is_int(KNOT_EOK, ret, "txt to bin");
|
|
ok(yp_bool(b) == val, "compare");
|
|
ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
|
|
is_int(KNOT_EOK, ret, "bin to txt");
|
|
ok(strlen(t) == t_len, "txt ret length");
|
|
ok(strlen(txt) == t_len, "txt length");
|
|
ok(memcmp(txt, t, t_len) == 0, "compare");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
plan_lazy();
|
|
|
|
/* Integer tests. */
|
|
int64_t min = -20000000000, max = 20000000000;
|
|
int_test("5", 5, YP_SNONE, min, max);
|
|
int_test("0", 0, YP_SNONE, min, max);
|
|
int_test("-5", -5, YP_SNONE, min, max);
|
|
int_test("20000000000", max, YP_SNONE, min, max);
|
|
int_test("-20000000000", min, YP_SNONE, min, max);
|
|
int_test("11B", 11LL * 1, YP_SSIZE, min, max);
|
|
int_test("11K", 11LL * 1024, YP_SSIZE, min, max);
|
|
int_test("11M", 11LL * 1024 * 1024, YP_SSIZE, min, max);
|
|
int_test("11G", 11LL * 1024 * 1024 * 1024, YP_SSIZE, min, max);
|
|
int_test("11s", 11LL * 1, YP_STIME, min, max);
|
|
int_test("11m", 11LL * 60, YP_STIME, min, max);
|
|
int_test("11h", 11LL * 3600, YP_STIME, min, max);
|
|
int_test("6d", 6LL * 24 * 3600, YP_STIME, min, max);
|
|
int_test("4w", 4LL * 7 * 24 * 3600, YP_STIME, min, max);
|
|
int_test("11M", 11LL * 30 * 24 * 3600, YP_STIME, min, max);
|
|
int_test("2y", 2LL * 365 * 24 * 3600, YP_STIME, min, max);
|
|
int_test("1025B", 1025LL, YP_SSIZE, min, max);
|
|
int_test("61s", 61LL, YP_STIME, min, max);
|
|
int_bad_test("20000000001", KNOT_ERANGE, YP_SNONE, min, max);
|
|
int_bad_test("-20000000001", KNOT_ERANGE, YP_SNONE, min, max);
|
|
int_bad_test("1x", KNOT_EINVAL, YP_SNONE, min, max);
|
|
int_bad_test("1sx", KNOT_EINVAL, YP_STIME, min, max);
|
|
|
|
/* Boolean tests. */
|
|
bool_test("on", true);
|
|
bool_test("off", false);
|
|
bool_bad_test("onx", KNOT_EINVAL);
|
|
bool_bad_test("enable", KNOT_EINVAL);
|
|
|
|
/* Option tests. */
|
|
static const knot_lookup_t opts[] = {
|
|
{ 1, "one" },
|
|
{ 10, "ten" },
|
|
{ 255, "max" },
|
|
{ 0, NULL }
|
|
};
|
|
opt_test("one", 1, opts);
|
|
opt_test("ten", 10, opts);
|
|
opt_test("max", 255, opts);
|
|
opt_bad_test("onex", KNOT_EINVAL, opts);
|
|
opt_bad_test("word", KNOT_EINVAL, opts);
|
|
|
|
/* String tests. */
|
|
str_test("Test string!", "Test string!");
|
|
|
|
/* Address tests. */
|
|
addr_test("192.168.123.1", true);
|
|
addr_test("192.168.123.1@12345", false);
|
|
addr_test("2001:db8::1", true);
|
|
addr_test("::1@12345", false);
|
|
addr_test("/tmp/test.sock", true);
|
|
addr_test("eth1@53", true);
|
|
addr_test("::1%lo", true);
|
|
addr_test("::1%2", true);
|
|
addr_test("::1%lo@12345", false);
|
|
addr_test("::1%4@12345", false);
|
|
addr_bad_test("192.168.123.x", KNOT_EINVAL);
|
|
addr_bad_test("192.168.123.1@", KNOT_EINVAL);
|
|
addr_bad_test("192.168.123.1@1x", KNOT_EINVAL);
|
|
addr_bad_test("192.168.123.1@65536", KNOT_ERANGE);
|
|
addr_bad_test("::1%", KNOT_EINVAL);
|
|
addr_bad_test("::1%@53", KNOT_EINVAL);
|
|
|
|
/* Address range tests. */
|
|
addr_range_test("/tmp/unix.sock");
|
|
addr_range_test("1.1.1.1");
|
|
addr_range_test("1.1.1.1/0");
|
|
addr_range_test("1.1.1.1/32");
|
|
addr_range_test("1.1.1.1-1.2.3.4");
|
|
addr_range_test("::1");
|
|
addr_range_test("::1/0");
|
|
addr_range_test("::1/32");
|
|
addr_range_test("::1%lo/32");
|
|
addr_range_test("1::-5::");
|
|
addr_range_test("1::%lo-5::%lo");
|
|
addr_range_bad_test("unix", KNOT_EINVAL);
|
|
addr_range_bad_test("1.1.1", KNOT_EINVAL);
|
|
addr_range_bad_test("1.1.1.1/", KNOT_EINVAL);
|
|
addr_range_bad_test("1.1.1.1/33", KNOT_ERANGE);
|
|
addr_range_bad_test("1.1.1.1-", KNOT_EINVAL);
|
|
addr_range_bad_test("1.1.1.1-::1", KNOT_EINVAL);
|
|
|
|
/* Dname tests. */
|
|
dname_test("example.com.", "\x07""example""\x03""com""\x00");
|
|
|
|
/* Hex tests. */
|
|
hex_test("", "", NULL);
|
|
hex_test("0x", "", "");
|
|
hex_test("Hello World!", "Hello World!", NULL);
|
|
hex_test("0x0155FF", "\x01\x55\xFF", NULL);
|
|
hex_bad_test("0xA", KNOT_EINVAL);
|
|
|
|
/* Base64 tests. */
|
|
base64_test("Zm9vYmFy", "foobar");
|
|
|
|
/* Ref tests. */
|
|
ref_test("on", true);
|
|
|
|
return 0;
|
|
}
|