aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/netinet
diff options
context:
space:
mode:
authorLutz Donnerhacke <donner@FreeBSD.org>2021-05-16 21:37:37 +0000
committerLutz Donnerhacke <donner@FreeBSD.org>2021-05-29 13:09:55 +0000
commitcfeeb57166d9ef3dfd5823b31fc0bcfb24fe147e (patch)
tree0b899657fa8c90f2c9712ad9541ff47d9e486c09 /tests/sys/netinet
parent738ebfa0f6b420523c49b8c774ad0c07bd335313 (diff)
Diffstat (limited to 'tests/sys/netinet')
-rw-r--r--tests/sys/netinet/Makefile2
-rw-r--r--tests/sys/netinet/libalias/1_instance.c119
-rw-r--r--tests/sys/netinet/libalias/2_natout.c414
-rw-r--r--tests/sys/netinet/libalias/Makefile31
-rw-r--r--tests/sys/netinet/libalias/perf.c231
-rw-r--r--tests/sys/netinet/libalias/util.c114
-rw-r--r--tests/sys/netinet/libalias/util.h62
7 files changed, 973 insertions, 0 deletions
diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile
index 7dd21c3545b5..a053ec711fff 100644
--- a/tests/sys/netinet/Makefile
+++ b/tests/sys/netinet/Makefile
@@ -5,6 +5,8 @@ PACKAGE= tests
TESTSDIR= ${TESTSBASE}/sys/netinet
BINDIR= ${TESTSDIR}
+TESTS_SUBDIRS+= libalias
+
ATF_TESTS_C= ip_reass_test \
so_reuseport_lb_test \
socket_afinet \
diff --git a/tests/sys/netinet/libalias/1_instance.c b/tests/sys/netinet/libalias/1_instance.c
new file mode 100644
index 000000000000..842acb41bb90
--- /dev/null
+++ b/tests/sys/netinet/libalias/1_instance.c
@@ -0,0 +1,119 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2021 Lutz Donnerhacke
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <atf-c.h>
+#include <alias.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+ATF_TC(2_destroynull);
+ATF_TC_HEAD(2_destroynull, env)
+{
+ atf_tc_set_md_var(env, "descr", "Destroy the NULL instance");
+}
+ATF_TC_BODY(2_destroynull, dummy)
+{
+ atf_tc_expect_death("Code expects valid pointer.");
+ LibAliasUninit(NULL);
+}
+
+ATF_TC(1_singleinit);
+ATF_TC_HEAD(1_singleinit, env)
+{
+ atf_tc_set_md_var(env, "descr", "Create an instance");
+}
+ATF_TC_BODY(1_singleinit, dummy)
+{
+ struct libalias *la;
+
+ la = LibAliasInit(NULL);
+ ATF_CHECK_MSG(la != NULL, "Creating an instance failed.");
+ LibAliasUninit(la);
+}
+
+ATF_TC(3_multiinit);
+ATF_TC_HEAD(3_multiinit, env)
+{
+ atf_tc_set_md_var(env, "descr", "Recreate an instance multiple times");
+}
+ATF_TC_BODY(3_multiinit, dummy)
+{
+ struct libalias *la;
+ int i;
+
+ la = LibAliasInit(NULL);
+ for(i = 1; i < 30; i++) {
+ struct libalias *lo = la;
+
+ la = LibAliasInit(la);
+ ATF_CHECK_MSG(la == lo, "Recreating moved the instance around: %d", i);
+ }
+ LibAliasUninit(la);
+}
+
+ATF_TC(4_multiinstance);
+ATF_TC_HEAD(4_multiinstance, env)
+{
+ atf_tc_set_md_var(env, "descr", "Create and destoy multiple instances.");
+}
+ATF_TC_BODY(4_multiinstance, dummy)
+{
+ struct libalias *la[300];
+ int const num_instances = sizeof(la) / sizeof(*la);
+ int i;
+
+ for (i = 0; i < num_instances; i++) {
+ la[i] = LibAliasInit(NULL);
+ ATF_CHECK_MSG(la[i] != NULL, "Creating instance %d failed.", i);
+ }
+
+ qsort(la, num_instances, sizeof(*la), randcmp);
+
+ for (i = 0; i < num_instances; i++)
+ LibAliasUninit(la[i]);
+}
+
+ATF_TP_ADD_TCS(instance)
+{
+ /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
+ srand(0x5ac4);
+
+ ATF_TP_ADD_TC(instance, 2_destroynull);
+ ATF_TP_ADD_TC(instance, 1_singleinit);
+ ATF_TP_ADD_TC(instance, 3_multiinit);
+ ATF_TP_ADD_TC(instance, 4_multiinstance);
+
+ return atf_no_error();
+}
diff --git a/tests/sys/netinet/libalias/2_natout.c b/tests/sys/netinet/libalias/2_natout.c
new file mode 100644
index 000000000000..1eeeac2ef868
--- /dev/null
+++ b/tests/sys/netinet/libalias/2_natout.c
@@ -0,0 +1,414 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2021 Lutz Donnerhacke
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <atf-c.h>
+#include <alias.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+/* common ip ranges */
+static struct in_addr masq = { htonl(0x01020304) };
+static struct in_addr pub = { htonl(0x0102dead) };
+static struct in_addr prv1 = { htonl(0x0a00dead) };
+static struct in_addr prv2 = { htonl(0xac10dead) };
+static struct in_addr prv3 = { htonl(0xc0a8dead) };
+static struct in_addr cgn = { htonl(0x6440dead) };
+static struct in_addr ext = { htonl(0x12345678) };
+
+#define NAT_CHECK(pip, src, msq) do { \
+ int res; \
+ int len = ntohs(pip->ip_len); \
+ struct in_addr dst = pip->ip_dst; \
+ pip->ip_src = src; \
+ res = LibAliasOut(la, pip, len); \
+ ATF_CHECK_MSG(res == PKT_ALIAS_OK, \
+ ">%d< not met PKT_ALIAS_OK", res); \
+ ATF_CHECK(addr_eq(msq, pip->ip_src)); \
+ ATF_CHECK(addr_eq(dst, pip->ip_dst)); \
+} while(0)
+
+#define NAT_FAIL(pip, src, dst) do { \
+ int res; \
+ int len = ntohs(pip->ip_len); \
+ pip->ip_src = src; \
+ pip->ip_dst = dst; \
+ res = LibAliasOut(la, pip, len); \
+ ATF_CHECK_MSG(res != PKT_ALIAS_OK), \
+ ">%d< not met !PKT_ALIAS_OK", res); \
+ ATF_CHECK(addr_eq(src, pip->ip_src)); \
+ ATF_CHECK(addr_eq(dst, pip->ip_dst)); \
+} while(0)
+
+#define UNNAT_CHECK(pip, src, dst, rel) do { \
+ int res; \
+ int len = ntohs(pip->ip_len); \
+ pip->ip_src = src; \
+ pip->ip_dst = dst; \
+ res = LibAliasIn(la, pip, len); \
+ ATF_CHECK_MSG(res == PKT_ALIAS_OK, \
+ ">%d< not met PKT_ALIAS_OK", res); \
+ ATF_CHECK(addr_eq(src, pip->ip_src)); \
+ ATF_CHECK(addr_eq(rel, pip->ip_dst)); \
+} while(0)
+
+#define UNNAT_FAIL(pip, src, dst) do { \
+ int res; \
+ int len = ntohs(pip->ip_len); \
+ pip->ip_src = src; \
+ pip->ip_dst = dst; \
+ res = LibAliasIn(la, pip, len); \
+ ATF_CHECK_MSG(res != PKT_ALIAS_OK, \
+ ">%d< not met !PKT_ALIAS_OK", res); \
+ ATF_CHECK(addr_eq(src, pip->ip_src)); \
+ ATF_CHECK(addr_eq(dst, pip->ip_dst)); \
+} while(0)
+
+ATF_TC_WITHOUT_HEAD(1_simplemasq);
+ATF_TC_BODY(1_simplemasq, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *pip;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, 0, ~0);
+
+ pip = ip_packet(prv1, ext, 254, 64);
+ NAT_CHECK(pip, prv1, masq);
+ NAT_CHECK(pip, prv2, masq);
+ NAT_CHECK(pip, prv3, masq);
+ NAT_CHECK(pip, cgn, masq);
+ NAT_CHECK(pip, pub, masq);
+
+ free(pip);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(2_unregistered);
+ATF_TC_BODY(2_unregistered, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *pip;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_ONLY, ~0);
+
+ pip = ip_packet(prv1, ext, 254, 64);
+ NAT_CHECK(pip, prv1, masq);
+ NAT_CHECK(pip, prv2, masq);
+ NAT_CHECK(pip, prv3, masq);
+ NAT_CHECK(pip, cgn, cgn);
+ NAT_CHECK(pip, pub, pub);
+
+ /*
+ * State is only for new connections
+ * Because they are now active,
+ * the mode setting should be ignored
+ */
+ LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_ONLY);
+ NAT_CHECK(pip, prv1, masq);
+ NAT_CHECK(pip, prv2, masq);
+ NAT_CHECK(pip, prv3, masq);
+ NAT_CHECK(pip, cgn, cgn);
+ NAT_CHECK(pip, pub, pub);
+
+ free(pip);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(3_cgn);
+ATF_TC_BODY(3_cgn, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *pip;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_CGN, ~0);
+
+ pip = ip_packet(prv1, ext, 254, 64);
+ NAT_CHECK(pip, prv1, masq);
+ NAT_CHECK(pip, prv2, masq);
+ NAT_CHECK(pip, prv3, masq);
+ NAT_CHECK(pip, cgn, masq);
+ NAT_CHECK(pip, pub, pub);
+
+ /*
+ * State is only for new connections
+ * Because they are now active,
+ * the mode setting should be ignored
+ */
+ LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_CGN);
+ NAT_CHECK(pip, prv1, masq);
+ NAT_CHECK(pip, prv2, masq);
+ NAT_CHECK(pip, prv3, masq);
+ NAT_CHECK(pip, cgn, masq);
+ NAT_CHECK(pip, pub, pub);
+
+ free(pip);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(4_udp);
+ATF_TC_BODY(4_udp, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *po, *pi;
+ struct udphdr *ui, *uo;
+ uint16_t sport = 0x1234;
+ uint16_t dport = 0x5678;
+ uint16_t aport;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, 0, ~0);
+
+ /* Query from prv1 */
+ po = ip_packet(prv1, ext, 0, 64);
+ uo = set_udp(po, sport, dport);
+ NAT_CHECK(po, prv1, masq);
+ ATF_CHECK(uo->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(po->ip_dst, ext));
+ aport = ntohs(uo->uh_sport);
+ /* should use a different external port */
+ ATF_CHECK(aport != sport);
+
+ /* Response */
+ pi = ip_packet(po->ip_dst, po->ip_src, 0, 64);
+ ui = set_udp(pi, ntohs(uo->uh_dport), ntohs(uo->uh_sport));
+ UNNAT_CHECK(pi, ext, masq, prv1);
+ ATF_CHECK(ui->uh_sport == htons(dport));
+ ATF_CHECK(ui->uh_dport == htons(sport));
+
+ /* Query from different source with same ports */
+ uo = set_udp(po, sport, dport);
+ NAT_CHECK(po, prv2, masq);
+ ATF_CHECK(uo->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(po->ip_dst, ext));
+ /* should use a different external port */
+ ATF_CHECK(uo->uh_sport != htons(aport));
+
+ /* Response to prv2 */
+ ui->uh_dport = uo->uh_sport;
+ UNNAT_CHECK(pi, ext, masq, prv2);
+ ATF_CHECK(ui->uh_sport == htons(dport));
+ ATF_CHECK(ui->uh_dport == htons(sport));
+
+ /* Response to prv1 again */
+ ui->uh_dport = htons(aport);
+ UNNAT_CHECK(pi, ext, masq, prv1);
+ ATF_CHECK(ui->uh_sport == htons(dport));
+ ATF_CHECK(ui->uh_dport == htons(sport));
+
+ free(pi);
+ free(po);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(5_sameport);
+ATF_TC_BODY(5_sameport, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *p;
+ struct udphdr *u;
+ uint16_t sport = 0x1234;
+ uint16_t dport = 0x5678;
+ uint16_t aport;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, ~0);
+
+ /* Query from prv1 */
+ p = ip_packet(prv1, ext, 0, 64);
+ u = set_udp(p, sport, dport);
+ NAT_CHECK(p, prv1, masq);
+ ATF_CHECK(u->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(p->ip_dst, ext));
+ aport = ntohs(u->uh_sport);
+ /* should use the same external port */
+ ATF_CHECK(aport == sport);
+
+ /* Query from different source with same ports */
+ u = set_udp(p, sport, dport);
+ NAT_CHECK(p, prv2, masq);
+ ATF_CHECK(u->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(p->ip_dst, ext));
+ /* should use a different external port */
+ ATF_CHECK(u->uh_sport != htons(aport));
+
+ free(p);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(6_cleartable);
+ATF_TC_BODY(6_cleartable, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *po, *pi;
+ struct udphdr *ui, *uo;
+ uint16_t sport = 0x1234;
+ uint16_t dport = 0x5678;
+ uint16_t aport;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);
+ LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, PKT_ALIAS_SAME_PORTS);
+ LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
+
+ /* Query from prv1 */
+ po = ip_packet(prv1, ext, 0, 64);
+ uo = set_udp(po, sport, dport);
+ NAT_CHECK(po, prv1, masq);
+ ATF_CHECK(uo->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(po->ip_dst, ext));
+ aport = ntohs(uo->uh_sport);
+ /* should use the same external port */
+ ATF_CHECK(aport == sport);
+
+ /* Response */
+ pi = ip_packet(po->ip_dst, po->ip_src, 0, 64);
+ ui = set_udp(pi, ntohs(uo->uh_dport), ntohs(uo->uh_sport));
+ UNNAT_CHECK(pi, ext, masq, prv1);
+ ATF_CHECK(ui->uh_sport == htons(dport));
+ ATF_CHECK(ui->uh_dport == htons(sport));
+
+ /* clear table by keeping the address */
+ LibAliasSetAddress(la, ext);
+ LibAliasSetAddress(la, masq);
+
+ /* Response to prv1 again -> DENY_INCOMING */
+ ui->uh_dport = htons(aport);
+ UNNAT_FAIL(pi, ext, masq);
+
+ /* Query from different source with same ports */
+ uo = set_udp(po, sport, dport);
+ NAT_CHECK(po, prv2, masq);
+ ATF_CHECK(uo->uh_dport == htons(dport));
+ ATF_CHECK(addr_eq(po->ip_dst, ext));
+ /* should use the same external port, because it's free */
+ ATF_CHECK(uo->uh_sport == htons(aport));
+
+ /* Response to prv2 */
+ ui->uh_dport = uo->uh_sport;
+ UNNAT_CHECK(pi, ext, masq, prv2);
+ ATF_CHECK(ui->uh_sport == htons(dport));
+ ATF_CHECK(ui->uh_dport == htons(sport));
+
+ free(pi);
+ free(po);
+ LibAliasUninit(la);
+}
+
+ATF_TC_WITHOUT_HEAD(7_stress);
+ATF_TC_BODY(7_stress, dummy)
+{
+ struct libalias *la = LibAliasInit(NULL);
+ struct ip *p;
+ struct udphdr *u;
+ struct {
+ struct in_addr src, dst;
+ uint16_t sport, dport, aport;
+ } *batch;
+ size_t const batch_size = 12000;
+ size_t const rounds = 25;
+ size_t i, j;
+
+ ATF_REQUIRE(la != NULL);
+ LibAliasSetAddress(la, masq);
+
+ p = ip_packet(prv1, ext, 0, 64);
+ u = set_udp(p, 0, 0);
+
+ batch = calloc(batch_size, sizeof(*batch));
+ ATF_REQUIRE(batch != NULL);
+ for (j = 0; j < rounds; j++) {
+ for (i = 0; i < batch_size; i++) {
+ struct in_addr s, d;
+ switch (i&3) {
+ case 0: s = prv1; d = ext; break;
+ case 1: s = prv2; d = pub; break;
+ case 2: s = prv3; d = ext; break;
+ case 3: s = cgn; d = pub; break;
+ }
+ s.s_addr &= htonl(0xffff0000);
+ d.s_addr &= htonl(0xffff0000);
+ batch[i].src.s_addr = s.s_addr | htonl(rand_range(0, 0xffff));
+ batch[i].dst.s_addr = d.s_addr | htonl(rand_range(0, 0xffff));
+ batch[i].sport = rand_range(1000, 60000);
+ batch[i].dport = rand_range(1000, 60000);
+ }
+
+ for (i = 0; i < batch_size; i++) {
+ p->ip_dst = batch[i].dst;
+ u = set_udp(p, batch[i].sport, batch[i].dport);
+ NAT_CHECK(p, batch[i].src, masq);
+ ATF_CHECK(u->uh_dport == htons(batch[i].dport));
+ ATF_CHECK(addr_eq(p->ip_dst, batch[i].dst));
+ batch[i].aport = htons(u->uh_sport);
+ }
+
+ qsort(batch, batch_size, sizeof(*batch), randcmp);
+
+ for (i = 0; i < batch_size; i++) {
+ u = set_udp(p, batch[i].dport, batch[i].aport);
+ UNNAT_CHECK(p, batch[i].dst, masq, batch[i].src);
+ ATF_CHECK(u->uh_dport == htons(batch[i].sport));
+ ATF_CHECK(u->uh_sport == htons(batch[i].dport));
+ }
+ }
+
+ free(batch);
+ free(p);
+ LibAliasUninit(la);
+}
+
+ATF_TP_ADD_TCS(natout)
+{
+ /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
+ srand(0x0b61);
+
+ ATF_TP_ADD_TC(natout, 1_simplemasq);
+ ATF_TP_ADD_TC(natout, 2_unregistered);
+ ATF_TP_ADD_TC(natout, 3_cgn);
+ ATF_TP_ADD_TC(natout, 4_udp);
+ ATF_TP_ADD_TC(natout, 5_sameport);
+ ATF_TP_ADD_TC(natout, 6_cleartable);
+ ATF_TP_ADD_TC(natout, 7_stress);
+
+ return atf_no_error();
+}
diff --git a/tests/sys/netinet/libalias/Makefile b/tests/sys/netinet/libalias/Makefile
new file mode 100644
index 000000000000..6ee2fc0e0e1f
--- /dev/null
+++ b/tests/sys/netinet/libalias/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/sys/netinet/libalias
+BINDIR= ${TESTSDIR}
+
+ATF_TESTS_C+= 1_instance \
+ 2_natout \
+
+PROGS+= perf
+
+LIBADD+= alias
+
+SRCS.1_instance=1_instance.c util.c
+SRCS.2_natout= 2_natout.c util.c
+SRCS.perf= perf.c util.c
+
+.include <bsd.test.mk>
+
+#
+# Testing during development
+#
+test: all
+ cd ${.OBJDIR}; kyua test
+
+report:
+ cd ${.OBJDIR}; kyua report
+
+report-v:
+ cd ${.OBJDIR}; kyua report --verbose
diff --git a/tests/sys/netinet/libalias/perf.c b/tests/sys/netinet/libalias/perf.c
new file mode 100644
index 000000000000..365b8f2e9fcc
--- /dev/null
+++ b/tests/sys/netinet/libalias/perf.c
@@ -0,0 +1,231 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2021 Lutz Donnerhacke
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/time.h>
+#include "util.h"
+#include <alias.h>
+
+/* common ip ranges */
+static struct in_addr masq = { htonl(0x01020304) };
+static struct in_addr prv = { htonl(0x0a000000) };
+static struct in_addr ext = { htonl(0x12000000) };
+
+#define timevalcmp(tv, uv, cmp) \
+ (((tv).tv_sec == (uv).tv_sec) \
+ ? ((tv).tv_usec cmp (uv).tv_usec) \
+ : ((tv).tv_sec cmp (uv).tv_sec))
+
+#define timevaldiff(n, o) (float) \
+ (((n).tv_sec - (o).tv_sec)*1000000l + \
+ ((n).tv_usec - (o).tv_usec))
+
+int main(int argc, char ** argv)
+{
+ struct libalias *la;
+ struct timeval timeout;
+ struct ip *p;
+ struct udphdr *u;
+ struct {
+ struct in_addr src, dst;
+ uint16_t sport, dport, aport;
+ } *batch;
+ struct {
+ unsigned long ok, fail;
+ } nat, unnat, random, attack;
+ int max_seconds, batch_size, random_size, attack_length, round, cnt;
+
+ if(argc != 5 ||
+ 0 > (max_seconds = atoi(argv[1])) ||
+ 0 >= (batch_size = atoi(argv[2])) ||
+ 0 >= (random_size = atoi(argv[3])) ||
+ 0 >= (attack_length = atoi(argv[4]))) {
+ printf("Usage: %s max_seconds batch_size random_size attack_length\n", argv[0]);
+ return 1;
+ }
+ if (NULL == (la = LibAliasInit(NULL))) {
+ perror("LibAliasInit");
+ return -1;
+ }
+
+ bzero(&nat, sizeof(nat));
+ bzero(&unnat, sizeof(unnat));
+ bzero(&random, sizeof(random));
+ bzero(&attack, sizeof(attack));
+
+ LibAliasSetAddress(la, masq);
+ LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
+
+ prv.s_addr &= htonl(0xffff0000);
+ ext.s_addr &= htonl(0xffff0000);
+
+ p = ip_packet(prv, ext, 0, 64);
+ u = set_udp(p, 0, 0);
+
+ if (NULL == (batch = calloc(batch_size, sizeof(*batch)))) {
+ perror("calloc(batch)");
+ return -1;
+ }
+
+ gettimeofday(&timeout, NULL);
+ timeout.tv_sec += max_seconds;
+
+ printf("RND SECND NAT RND ATT UNA\n");
+ for (round = 0; ; round++) {
+ int i, res;
+ struct timeval now, start;
+
+ printf("%3d ", round+1);
+
+ gettimeofday(&start, NULL);
+ printf("%5.1f ", max_seconds - timevaldiff(timeout, start)/1000000.0f);
+ for (cnt = i = 0; i < batch_size; i++, cnt++) {
+ batch[i].src.s_addr = prv.s_addr | htonl(rand_range(0, 0xffff));
+ batch[i].dst.s_addr = ext.s_addr | htonl(rand_range(0, 0xffff));
+ batch[i].sport = rand_range(1000, 60000);
+ batch[i].dport = rand_range(1000, 60000);
+
+ p->ip_src = batch[i].src;
+ p->ip_dst = batch[i].dst;
+ u = set_udp(p, batch[i].sport, batch[i].dport);
+
+ res = LibAliasOut(la, p, 64);
+ batch[i].aport = htons(u->uh_sport);
+
+ if (res == PKT_ALIAS_OK &&
+ u->uh_dport == htons(batch[i].dport) &&
+ addr_eq(p->ip_dst, batch[i].dst) &&
+ addr_eq(p->ip_src, masq))
+ nat.ok++;
+ else
+ nat.fail++;
+
+ gettimeofday(&now, NULL);
+ if(timevalcmp(now, timeout, >=))
+ goto out;
+ }
+ if (cnt > 0)
+ printf("%3.0f ", timevaldiff(now, start) / cnt);
+
+ start = now;
+ for (cnt = i = 0; i < random_size; i++, cnt++) {
+ p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000);
+ p->ip_src.s_addr |= htonl(rand_range(0, 0xffff));
+ p->ip_dst = masq;
+ u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff));
+
+ res = LibAliasIn(la, p, 64);
+
+ if (res == PKT_ALIAS_OK)
+ random.ok++;
+ else
+ random.fail++;
+
+ gettimeofday(&now, NULL);
+ if(timevalcmp(now, timeout, >=))
+ goto out;
+ }
+ if (cnt > 0)
+ printf("%3.0f ", timevaldiff(now, start) / cnt);
+
+ start = now;
+ p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000);
+ p->ip_src.s_addr |= htonl(rand_range(0, 0xffff));
+ p->ip_dst = masq;
+ u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff));
+ for (cnt = i = 0; i < attack_length; i++, cnt++) {
+ res = LibAliasIn(la, p, 64);
+
+ if (res == PKT_ALIAS_OK)
+ attack.ok++;
+ else
+ attack.fail++;
+
+ gettimeofday(&now, NULL);
+ if(timevalcmp(now, timeout, >=))
+ goto out;
+ }
+ if (cnt > 0)
+ printf("%3.0f ", timevaldiff(now, start) / cnt);
+
+ qsort(batch, batch_size, sizeof(*batch), randcmp);
+
+ gettimeofday(&start, NULL);
+ for (cnt = i = 0; i < batch_size; i++, cnt++) {
+ p->ip_src = batch[i].dst;
+ p->ip_dst = masq;
+ u = set_udp(p, batch[i].dport, batch[i].aport);
+
+ res = LibAliasIn(la, p, 64);
+ batch[i].aport = htons(u->uh_sport);
+
+ if (res == PKT_ALIAS_OK &&
+ u->uh_sport == htons(batch[i].dport) &&
+ u->uh_dport == htons(batch[i].sport) &&
+ addr_eq(p->ip_dst, batch[i].src) &&
+ addr_eq(p->ip_src, batch[i].dst))
+ unnat.ok++;
+ else
+ unnat.fail++;
+
+ gettimeofday(&now, NULL);
+ if(timevalcmp(now, timeout, >=))
+ goto out;
+ }
+ if (cnt > 0)
+ printf("%3.0f\n", timevaldiff(now, start) / cnt);
+ }
+out:
+ printf("\n\n");
+ free(batch);
+ free(p);
+ LibAliasUninit(la);
+
+ printf("Results\n");
+ printf(" Rounds : %7u\n", round);
+ printf(" NAT ok : %7lu\n", nat.ok);
+ printf(" NAT fail: %7lu\n", nat.fail);
+ printf(" UNNAT ok : %7lu\n", unnat.ok);
+ printf(" UNNAT fail: %7lu\n", unnat.fail);
+ printf("RANDOM ok : %7lu\n", random.ok);
+ printf("RANDOM fail: %7lu\n", random.fail);
+ printf("ATTACK ok : %7lu\n", attack.ok);
+ printf("ATTACK fail: %7lu\n", attack.fail);
+ printf(" -------------------\n");
+ printf(" Total: %7lu\n",
+ nat.ok + nat.fail + unnat.ok + unnat.fail +
+ random.ok + random.fail + attack.ok + attack.fail);
+ return (0);
+}
diff --git a/tests/sys/netinet/libalias/util.c b/tests/sys/netinet/libalias/util.c
new file mode 100644
index 000000000000..df2e320a4eba
--- /dev/null
+++ b/tests/sys/netinet/libalias/util.c
@@ -0,0 +1,114 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2021 Lutz Donnerhacke
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <netinet/in.h>
+
+#include "util.h"
+
+#define REQUIRE(x) do { \
+ if (!(x)) { \
+ fprintf(stderr, "Failed in %s %s:%d.\n",\
+ __FUNCTION__, __FILE__, __LINE__); \
+ exit(-1); \
+ } \
+} while(0)
+
+int
+randcmp(const void *a, const void *b)
+{
+ int res, r = rand();
+
+ (void)a;
+ (void)b;
+ res = (r/4 < RAND_MAX/9) ? 1
+ : (r/5 < RAND_MAX/9) ? 0
+ : -1;
+ return (res);
+}
+
+void
+hexdump(void *p, size_t len)
+{
+ size_t i;
+ unsigned char *c = p;
+
+ for (i = 0; i < len; i++) {
+ printf(" %02x", c[i]);
+ switch (i & 0xf) {
+ case 0xf: printf("\n"); break;
+ case 0x7: printf(" "); break;
+ default: break;
+ }
+ }
+ if ((i & 0xf) != 0x0)
+ printf("\n");
+}
+
+struct ip *
+ip_packet(struct in_addr src, struct in_addr dst, u_char protocol, size_t len)
+{
+ struct ip * p;
+
+ REQUIRE(len >= 64 && len <= IP_MAXPACKET);
+
+ p = calloc(1, len);
+ REQUIRE(p != NULL);
+
+ p->ip_v = IPVERSION;
+ p->ip_hl = sizeof(*p)/4;
+ p->ip_len = htons(len);
+ p->ip_ttl = IPDEFTTL;
+ p->ip_src = src;
+ p->ip_dst = dst;
+ p->ip_p = protocol;
+ REQUIRE(p->ip_hl == 5);
+
+ return (p);
+}
+
+struct udphdr *
+set_udp(struct ip *p, u_short sport, u_short dport) {
+ uint32_t *up = (void *)p;
+ struct udphdr *u = (void *)&(up[p->ip_hl]);
+ int payload = ntohs(p->ip_len) - 4*p->ip_hl;
+
+ REQUIRE(payload >= (int)sizeof(*u));
+ p->ip_p = IPPROTO_UDP;
+ u->uh_sport = htons(sport);
+ u->uh_dport = htons(dport);
+ u->uh_ulen = htons(payload);
+ return (u);
+}
diff --git a/tests/sys/netinet/libalias/util.h b/tests/sys/netinet/libalias/util.h
new file mode 100644
index 000000000000..f441aea49cfb
--- /dev/null
+++ b/tests/sys/netinet/libalias/util.h
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2021 Lutz Donnerhacke
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+int randcmp(const void *a, const void *b);
+void hexdump(void *p, size_t len);
+struct ip * ip_packet(struct in_addr src, struct in_addr dst, u_char protocol, size_t len);
+struct udphdr * set_udp(struct ip *p, u_short sport, u_short dport);
+
+inline int
+addr_eq(struct in_addr a, struct in_addr b)
+{
+ return a.s_addr == b.s_addr;
+}
+
+#define a2h(a) ntohl(a.s_addr)
+
+inline int
+rand_range(int min, int max)
+{
+ return min + rand()%(max - min);
+}
+
+#endif /* _UTIL_H */