summaryrefslogtreecommitdiffstats
path: root/tests/modules
diff options
context:
space:
mode:
Diffstat (limited to 'tests/modules')
-rw-r--r--tests/modules/test_onlinesign.c203
-rw-r--r--tests/modules/test_rrl.c178
2 files changed, 381 insertions, 0 deletions
diff --git a/tests/modules/test_onlinesign.c b/tests/modules/test_onlinesign.c
new file mode 100644
index 0000000..fbddb6e
--- /dev/null
+++ b/tests/modules/test_onlinesign.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+#include <assert.h>
+
+#include "knot/modules/onlinesign/nsec_next.h"
+#include "libknot/consts.h"
+#include "libknot/dname.h"
+#include "libknot/errcode.h"
+
+/*!
+ * \brief Assert that a domain name in a static buffer is valid.
+ */
+#define _assert_dname(name) \
+ assert(knot_dname_wire_check(name, name + KNOT_DNAME_MAXLEN, NULL) > 0)
+
+static void _test_nsec_next(const char *msg,
+ const knot_dname_t *input,
+ const knot_dname_t *apex,
+ const knot_dname_t *expected)
+{
+ knot_dname_t *next = online_nsec_next(input, apex);
+ ok(next != NULL && knot_dname_is_equal(next, expected),
+ "nsec_next, %s", msg);
+ knot_dname_free(next, NULL);
+}
+
+/*!
+ * \brief Check \a online_nsec_next.
+ *
+ * Intentionally implemented as a macro. The input domain names are copied
+ * into static buffers and validated.
+ */
+#define test_nsec_next(msg, _input, _apex, _expected) \
+{ \
+ uint8_t input[KNOT_DNAME_MAXLEN] = _input; \
+ uint8_t apex[KNOT_DNAME_MAXLEN] = _apex; \
+ uint8_t expected[KNOT_DNAME_MAXLEN] = _expected; \
+ \
+ _assert_dname(input); \
+ _assert_dname(apex); \
+ _assert_dname(expected); \
+ \
+ _test_nsec_next(msg, input, apex, expected); \
+}
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ // adding a single zero-byte label
+
+ test_nsec_next(
+ "zero-byte label, apex",
+ "\x7""example""\x3""com",
+ "\x7""example""\x3""com",
+ "\x01\x00""\x07""example""\x03""com"
+ );
+
+ test_nsec_next(
+ "zero-byte label, subdomain",
+ "\x02""nx""\x7""example""\x3""com",
+ "\x7""example""\x3""com",
+ "\x01\x00""\x02""nx""\x07""example""\x03""com"
+ );
+
+ test_nsec_next(
+ "zero-byte label, binary",
+ "\x02\xff\xff""\x7""example""\x3""com",
+ "\x07""example""\x3""com",
+ "\x01\x00""\x02\xff\xff""\x7""example""\x3""com"
+ );
+
+ // zero byte label won't fit, increment
+ #define APEX \
+ "\x05""bacon""\x05""salad"
+
+ #define LONG_SUFFIX \
+ "\x2e""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
+ "\x2e""iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii" \
+ "\x2e""mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm" \
+ "\x2e""qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" \
+ "\x2c""zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" \
+ APEX
+ assert(sizeof(LONG_SUFFIX) == 245 + 1);
+
+ test_nsec_next(
+ "increment first label (simple)",
+ "\x08""icecream" LONG_SUFFIX,
+ APEX,
+ "\x08""icecrean" LONG_SUFFIX
+ );
+
+ test_nsec_next(
+ "increment first label (binary)",
+ "\x08""walrus\xff\xff" LONG_SUFFIX,
+ APEX,
+ "\x08""walrut\x00\x00" LONG_SUFFIX
+ );
+
+ test_nsec_next(
+ "increment first label (in place)",
+ "\x07""lobster" LONG_SUFFIX,
+ APEX,
+ "\x07""lobstes" LONG_SUFFIX
+ );
+
+ test_nsec_next(
+ "increment first label (extend)",
+ "\x07""\xff\xff\xff\xff\xff\xff\xff" LONG_SUFFIX,
+ APEX,
+ "\x08""\xff\xff\xff\xff\xff\xff\xff\x00" LONG_SUFFIX
+ );
+
+ // name too long
+
+ test_nsec_next(
+ "name to long, strip label and increase next (simple)",
+ "\x03""\xff\xff\xff""\x04""newt" LONG_SUFFIX,
+ APEX,
+ "\x04""newu" LONG_SUFFIX
+ );
+
+ test_nsec_next(
+ "name to long, strip label and increase next (binary)",
+ "\x03""\xff\xff\xff""\x04""cc\xff\xff" LONG_SUFFIX,
+ APEX,
+ "\x04""cd\x00\x00" LONG_SUFFIX
+ );
+
+ test_nsec_next(
+ "name to long, strip label and increase next (extend)",
+ "\x04""\xff\xff\xff\xff""\x03""\xff\xff\xff" LONG_SUFFIX,
+ APEX,
+ "\x04""\xff\xff\xff\x00" LONG_SUFFIX
+ );
+
+ // label too long
+
+ #define MAX_LABEL "\x3f" /* 63 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff"
+ assert(sizeof(MAX_LABEL) == 64 + 1);
+
+ #define PAD_LABEL "\x28" /* 40 */ \
+ "iiiiiiiiiioooooooooottttttttttssssssssss"
+ assert(sizeof(PAD_LABEL) == 41 + 1);
+
+ test_nsec_next(
+ "label too long, strip and increase next (simple)",
+ MAX_LABEL "\x08""mandrill" MAX_LABEL MAX_LABEL PAD_LABEL APEX,
+ APEX,
+ "\x08""mandrilm" MAX_LABEL MAX_LABEL PAD_LABEL APEX
+ );
+
+ test_nsec_next(
+ "label too long, strip and increase next (extend)",
+ MAX_LABEL "\x07""\xff\xff\xff\xff\xff\xff\xff" MAX_LABEL MAX_LABEL PAD_LABEL APEX,
+ APEX,
+ "\x08""\xff\xff\xff\xff\xff\xff\xff\x00" MAX_LABEL MAX_LABEL PAD_LABEL APEX
+ );
+
+ test_nsec_next(
+ "label too long, strip multiple",
+ MAX_LABEL MAX_LABEL "\x08""flamingo" MAX_LABEL PAD_LABEL APEX,
+ APEX,
+ "\x08""flamingp" MAX_LABEL PAD_LABEL APEX
+ );
+
+ test_nsec_next(
+ "label too long, wrap around to apex",
+ "\x31" /* 49 */
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ MAX_LABEL MAX_LABEL MAX_LABEL APEX,
+ APEX,
+ APEX
+ );
+
+ return 0;
+}
diff --git a/tests/modules/test_rrl.c b/tests/modules/test_rrl.c
new file mode 100644
index 0000000..6a5210f
--- /dev/null
+++ b/tests/modules/test_rrl.c
@@ -0,0 +1,178 @@
+/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "libdnssec/crypto.h"
+#include "libdnssec/random.h"
+#include "libknot/libknot.h"
+#include "contrib/sockaddr.h"
+#include "knot/modules/rrl/functions.c"
+#include "stdio.h"
+
+/* Enable time-dependent tests. */
+//#define ENABLE_TIMED_TESTS
+#define RRL_SIZE 196613
+#define RRL_THREADS 8
+#define RRL_INSERTS (RRL_SIZE/(5*RRL_THREADS)) /* lf = 1/5 */
+
+/* Disabled as default as it depends on random input.
+ * Table may be consistent even if some collision occur (and they may occur).
+ * Note: Disabled due to reported problems when running on VMs due to time
+ * flow inconsistencies. Should work alright on a host machine.
+ */
+#ifdef ENABLE_TIMED_TESTS
+struct bucketmap {
+ unsigned i;
+ uint64_t x;
+};
+
+/*! \brief Unit runnable. */
+struct runnable_data {
+ int passed;
+ rrl_table_t *rrl;
+ struct sockaddr_storage *addr;
+ rrl_req_t *rq;
+ knot_dname_t *zone;
+};
+
+static void* rrl_runnable(void *arg)
+{
+ struct runnable_data *d = (struct runnable_data *)arg;
+ struct sockaddr_storage addr;
+ memcpy(&addr, d->addr, sizeof(struct sockaddr_storage));
+ int lock = -1;
+ uint32_t now = time(NULL);
+ struct bucketmap *m = malloc(RRL_INSERTS * sizeof(struct bucketmap));
+ for (unsigned i = 0; i < RRL_INSERTS; ++i) {
+ m[i].i = dnssec_random_uint32_t();
+ ((struct sockaddr_in *) &addr)->sin_addr.s_addr = m[i].i;
+ rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock);
+ rrl_unlock(d->rrl, lock);
+ m[i].x = b->netblk;
+ }
+ for (unsigned i = 0; i < RRL_INSERTS; ++i) {
+ ((struct sockaddr_in *) &addr)->sin_addr.s_addr = m[i].i;
+ rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock);
+ rrl_unlock(d->rrl, lock);
+ if (b->netblk != m[i].x) {
+ d->passed = 0;
+ }
+ }
+ free(m);
+ return NULL;
+}
+
+static void rrl_hopscotch(struct runnable_data* rd)
+{
+ rd->passed = 1;
+ pthread_t thr[RRL_THREADS];
+ for (unsigned i = 0; i < RRL_THREADS; ++i) {
+ pthread_create(thr + i, NULL, &rrl_runnable, rd);
+ }
+ for (unsigned i = 0; i < RRL_THREADS; ++i) {
+ pthread_join(thr[i], NULL);
+ }
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ plan_lazy();
+
+ dnssec_crypto_init();
+
+ /* Prepare query. */
+ knot_pkt_t *query = knot_pkt_new(NULL, 512, NULL);
+ if (query == NULL) {
+ return KNOT_ERROR; /* Fatal */
+ }
+
+ knot_dname_t *qname = knot_dname_from_str_alloc("beef.");
+ int ret = knot_pkt_put_question(query, qname, KNOT_CLASS_IN, KNOT_RRTYPE_A);
+ knot_dname_free(qname, NULL);
+ if (ret != KNOT_EOK) {
+ knot_pkt_free(query);
+ return KNOT_ERROR; /* Fatal */
+ }
+
+ /* Prepare response */
+ uint8_t rbuf[65535];
+ size_t rlen = sizeof(rbuf);
+ memcpy(rbuf, query->wire, query->size);
+ knot_wire_flags_set_qr(rbuf);
+
+ rrl_req_t rq;
+ rq.wire = rbuf;
+ rq.len = rlen;
+ rq.query = query;
+ rq.flags = 0;
+
+ /* 1. create rrl table */
+ const uint32_t rate = 10;
+ rrl_table_t *rrl = rrl_create(RRL_SIZE, rate);
+ ok(rrl != NULL, "rrl: create");
+
+ /* 2. N unlimited requests. */
+ knot_dname_t *zone = knot_dname_from_str_alloc("rrl.");
+
+ struct sockaddr_storage addr;
+ struct sockaddr_storage addr6;
+ sockaddr_set(&addr, AF_INET, "1.2.3.4", 0);
+ sockaddr_set(&addr6, AF_INET6, "1122:3344:5566:7788::aabb", 0);
+ ret = 0;
+ for (unsigned i = 0; i < rate * RRL_CAPACITY; ++i) {
+ if (rrl_query(rrl, &addr, &rq, zone, NULL) != KNOT_EOK ||
+ rrl_query(rrl, &addr6, &rq, zone, NULL) != KNOT_EOK) {
+ ret = KNOT_ELIMIT;
+ break;
+ }
+ }
+ is_int(0, ret, "rrl: unlimited IPv4/v6 requests");
+
+ /* 3. Endian-independent hash input buffer. */
+ uint8_t buf[RRL_CLSBLK_MAXLEN];
+ // CLS_LARGE + remote + dname wire.
+ uint8_t expectedv4[] = "\x10\x01\x02\x03\x00\x00\x00\x00\x00\x04""beef";
+ rrl_classify(buf, sizeof(buf), &addr, &rq, qname);
+ is_int(0, memcmp(buf, expectedv4, sizeof(expectedv4)), "rrl: IPv4 hash input buffer");
+ uint8_t expectedv6[] = "\x10\x11\x22\x33\x44\x55\x66\x77\x00\x04""beef";
+ rrl_classify(buf, sizeof(buf), &addr6, &rq, qname);
+ is_int(0, memcmp(buf, expectedv6, sizeof(expectedv6)), "rrl: IPv6 hash input buffer");
+
+#ifdef ENABLE_TIMED_TESTS
+ /* 5. limited request */
+ ret = rrl_query(rrl, &addr, &rq, zone, NULL);
+ is_int(KNOT_ELIMIT, ret, "rrl: throttled IPv4 request");
+
+ /* 6. limited IPv6 request */
+ ret = rrl_query(rrl, &addr6, &rq, zone, NULL);
+ is_int(KNOT_ELIMIT, ret, "rrl: throttled IPv6 request");
+
+ /* 8. hopscotch test */
+ struct runnable_data rd = {
+ 1, rrl, &addr, &rq, zone
+ };
+ rrl_hopscotch(&rd);
+ ok(rd.passed, "rrl: hashtable is ~ consistent");
+#endif
+
+ knot_dname_free(zone, NULL);
+ knot_pkt_free(query);
+ rrl_destroy(rrl);
+ dnssec_crypto_cleanup();
+ return 0;
+}