summaryrefslogtreecommitdiffstats
path: root/tests/conntrackd
diff options
context:
space:
mode:
Diffstat (limited to 'tests/conntrackd')
-rwxr-xr-xtests/conntrackd/conntrackd-tests.py263
-rw-r--r--tests/conntrackd/env.yaml2
-rwxr-xr-xtests/conntrackd/netns/conntrackd-netns-test.sh66
-rw-r--r--tests/conntrackd/netns/conntrackd-nsr1.conf37
-rw-r--r--tests/conntrackd/netns/conntrackd-nsr2.conf37
-rw-r--r--tests/conntrackd/netns/ruleset-nsr1.nft6
-rw-r--r--tests/conntrackd/scenarios.yaml100
-rwxr-xr-xtests/conntrackd/scenarios/basic/network-setup.sh59
-rw-r--r--tests/conntrackd/tests.yaml83
9 files changed, 653 insertions, 0 deletions
diff --git a/tests/conntrackd/conntrackd-tests.py b/tests/conntrackd/conntrackd-tests.py
new file mode 100755
index 0000000..f760351
--- /dev/null
+++ b/tests/conntrackd/conntrackd-tests.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python3
+
+# (C) 2021 by Arturo Borrero Gonzalez <arturo@netfilter.org>
+
+#
+# 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.
+#
+
+# tests.yaml file format:
+# - name: "test 1"
+# scenario: scenario1
+# test:
+# - test1 cmd1
+# - test1 cmd2
+
+# scenarios.yaml file format:
+# - name: scenario1
+# start:
+# - cmd1
+# - cmd2
+# stop:
+# - cmd1
+# - cmd2
+
+# env.yaml file format:
+# - VAR1: value1
+# - VAR2: value2
+
+import os
+import sys
+import argparse
+import subprocess
+import yaml
+import logging
+
+
+def read_yaml_file(file):
+ try:
+ with open(file, "r") as stream:
+ try:
+ return yaml.safe_load(stream)
+ except yaml.YAMLError as e:
+ logging.error(e)
+ exit(2)
+ except FileNotFoundError as e:
+ logging.error(e)
+ exit(2)
+
+
+def validate_dictionary(dictionary, keys):
+ if not isinstance(dictionary, dict):
+ logging.error("not a dictionary:\n{}".format(dictionary))
+ return False
+ for key in keys:
+ if dictionary.get(key) is None:
+ logging.error("missing key {} in dictionary:\n{}".format(key, dictionary))
+ return False
+ return True
+
+
+def stage_validate_config(args):
+ scenarios_dict = read_yaml_file(args.scenarios_file)
+ for definition in scenarios_dict:
+ if not validate_dictionary(definition, ["name", "start", "stop"]):
+ logging.error("couldn't validate file {}".format(args.scenarios_file))
+ return False
+
+ logging.debug("{} seems valid".format(args.scenarios_file))
+ ctx.scenarios_dict = scenarios_dict
+
+ tests_dict = read_yaml_file(args.tests_file)
+ for definition in tests_dict:
+ if not validate_dictionary(definition, ["name", "scenario", "test"]):
+ logging.error("couldn't validate file {}".format(args.tests_file))
+ return False
+
+ logging.debug("{} seems valid".format(args.tests_file))
+ ctx.tests_dict = tests_dict
+
+ env_list = read_yaml_file(args.env_file)
+ if not isinstance(env_list, list):
+ logging.error("couldn't validate file {}".format(args.env_file))
+ return False
+
+ # set env to default values if not overridden when calling this very script
+ for entry in env_list:
+ for key in entry:
+ os.environ[key] = os.getenv(key, entry[key])
+
+
+def cmd_run(cmd):
+ logging.debug("running command: {}".format(cmd))
+ r = subprocess.run(cmd, shell=True)
+ if r.returncode != 0:
+ logging.warning("failed command: {}".format(cmd))
+ return r.returncode
+
+
+def scenario_get(name):
+ for n in ctx.scenarios_dict:
+ if n["name"] == name:
+ return n
+
+ logging.error("couldn't find a definition for scenario '{}'".format(name))
+ exit(1)
+
+
+def scenario_start(scenario):
+ for cmd in scenario["start"]:
+ if cmd_run(cmd) == 0:
+ continue
+
+ logging.warning("--- failed scenario: {}".format(scenario["name"]))
+ ctx.counter_scenario_failed += 1
+ ctx.skip_current_test = True
+ return
+
+
+def scenario_stop(scenario):
+ for cmd in scenario["stop"]:
+ cmd_run(cmd)
+
+
+def test_get(name):
+ for n in ctx.tests_dict:
+ if n["name"] == name:
+ return n
+
+ logging.error("couldn't find a definition for test '{}'".format(name))
+ exit(1)
+
+
+def _test_run(test_definition):
+ if ctx.skip_current_test:
+ return
+
+ for cmd in test_definition["test"]:
+ if cmd_run(cmd) == 0:
+ continue
+
+ logging.warning("--- failed test: {}".format(test_definition["name"]))
+ ctx.counter_test_failed += 1
+ return
+
+ logging.info("--- passed test: {}".format(test_definition["name"]))
+ ctx.counter_test_ok += 1
+
+
+def test_run(test_definition):
+ scenario = scenario_get(test_definition["scenario"])
+
+ logging.info("--- running test: {}".format(test_definition["name"]))
+
+ scenario_start(scenario)
+ _test_run(test_definition)
+ scenario_stop(scenario)
+
+
+def stage_run_tests(args):
+ if args.start_scenario:
+ scenario_start(scenario_get(args.start_scenario))
+ return
+
+ if args.stop_scenario:
+ scenario_stop(scenario_get(args.stop_scenario))
+ return
+
+ if args.single:
+ test_run(test_get(args.single))
+ return
+
+ for test_definition in ctx.tests_dict:
+ ctx.skip_current_test = False
+ test_run(test_definition)
+
+
+def stage_report():
+ logging.info("---")
+ logging.info("--- finished")
+ total = ctx.counter_test_ok + ctx.counter_test_failed + ctx.counter_scenario_failed
+ logging.info("--- passed tests: {}".format(ctx.counter_test_ok))
+ logging.info("--- failed tests: {}".format(ctx.counter_test_failed))
+ logging.info("--- scenario failure: {}".format(ctx.counter_scenario_failed))
+ logging.info("--- total tests: {}".format(total))
+
+
+def parse_args():
+ description = "Utility to run tests for conntrack-tools"
+ parser = argparse.ArgumentParser(description=description)
+ parser.add_argument(
+ "--tests-file",
+ default="tests.yaml",
+ help="File with testcase definitions. Defaults to '%(default)s'",
+ )
+ parser.add_argument(
+ "--scenarios-file",
+ default="scenarios.yaml",
+ help="File with configuration scenarios for tests. Defaults to '%(default)s'",
+ )
+ parser.add_argument(
+ "--env-file",
+ default="env.yaml",
+ help="File with environment variables for scenarios/tests. Defaults to '%(default)s'",
+ )
+ parser.add_argument(
+ "--single",
+ help="Execute a single testcase and exit. Use this for developing testcases",
+ )
+ parser.add_argument(
+ "--start-scenario",
+ help="Execute scenario start commands and exit. Use this for developing testcases",
+ )
+ parser.add_argument(
+ "--stop-scenario",
+ help="Execute scenario stop commands and exit. Use this for cleanup",
+ )
+ parser.add_argument(
+ "--debug",
+ action="store_true",
+ help="debug mode",
+ )
+
+ return parser.parse_args()
+
+
+class Context:
+ def __init__(self):
+ self.scenarios_dict = None
+ self.tests_dict = None
+ self.counter_test_failed = 0
+ self.counter_test_ok = 0
+ self.counter_scenario_failed = 0
+ self.skip_current_test = False
+
+
+# global data
+ctx = Context()
+
+
+def main():
+ args = parse_args()
+
+ logging_format = "[%(filename)s] %(levelname)s: %(message)s"
+ if args.debug:
+ logging_level = logging.DEBUG
+ else:
+ logging_level = logging.INFO
+ logging.basicConfig(format=logging_format, level=logging_level, stream=sys.stdout)
+
+ if os.geteuid() != 0:
+ logging.error("root required")
+ exit(1)
+
+ stage_validate_config(args)
+ stage_run_tests(args)
+ stage_report()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/conntrackd/env.yaml b/tests/conntrackd/env.yaml
new file mode 100644
index 0000000..daf8ea1
--- /dev/null
+++ b/tests/conntrackd/env.yaml
@@ -0,0 +1,2 @@
+- CONNTRACKD: ../../src/conntrackd
+- CONNTRACK: ../../src/conntrack
diff --git a/tests/conntrackd/netns/conntrackd-netns-test.sh b/tests/conntrackd/netns/conntrackd-netns-test.sh
new file mode 100755
index 0000000..6f16587
--- /dev/null
+++ b/tests/conntrackd/netns/conntrackd-netns-test.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+if [ $UID -ne 0 ]
+then
+ echo "You must be root to run this test script"
+ exit 0
+fi
+
+start () {
+ ip netns add ns1
+ ip netns add ns2
+ ip netns add nsr1
+ ip netns add nsr2
+
+ ip link add veth0 netns ns1 type veth peer name veth1 netns nsr1
+ ip link add veth0 netns nsr1 type veth peer name veth0 netns ns2
+ ip link add veth2 netns nsr1 type veth peer name veth0 netns nsr2
+
+ ip -net ns1 addr add 192.168.10.2/24 dev veth0
+ ip -net ns1 link set up dev veth0
+ ip -net ns1 ro add 10.0.1.0/24 via 192.168.10.1 dev veth0
+
+ ip -net nsr1 addr add 10.0.1.1/24 dev veth0
+ ip -net nsr1 addr add 192.168.10.1/24 dev veth1
+ ip -net nsr1 link set up dev veth0
+ ip -net nsr1 link set up dev veth1
+ ip -net nsr1 route add default via 192.168.10.2
+ ip netns exec nsr1 sysctl net.ipv4.ip_forward=1
+
+ ip -net nsr1 addr add 192.168.100.2/24 dev veth2
+ ip -net nsr1 link set up dev veth2
+ ip -net nsr2 addr add 192.168.100.3/24 dev veth0
+ ip -net nsr2 link set up dev veth0
+
+ ip -net ns2 addr add 10.0.1.2/24 dev veth0
+ ip -net ns2 link set up dev veth0
+ ip -net ns2 route add default via 10.0.1.1
+
+ echo 1 > /proc/sys/net/netfilter/nf_log_all_netns
+
+ ip netns exec nsr1 nft -f ruleset-nsr1.nft
+ ip netns exec nsr1 conntrackd -C conntrackd-nsr1.conf -d
+ ip netns exec nsr2 conntrackd -C conntrackd-nsr2.conf -d
+}
+
+stop () {
+ ip netns del ns1
+ ip netns del ns2
+ ip netns del nsr1
+ ip netns del nsr2
+ killall -15 conntrackd
+}
+
+case $1 in
+start)
+ start
+ ;;
+stop)
+ stop
+ ;;
+*)
+ echo "$0 [start|stop]"
+ ;;
+esac
+
+exit 0
diff --git a/tests/conntrackd/netns/conntrackd-nsr1.conf b/tests/conntrackd/netns/conntrackd-nsr1.conf
new file mode 100644
index 0000000..c79eff5
--- /dev/null
+++ b/tests/conntrackd/netns/conntrackd-nsr1.conf
@@ -0,0 +1,37 @@
+Sync {
+ Mode FTFW {
+ }
+ Multicast {
+ IPv4_address 225.0.0.50
+ Group 3780
+ IPv4_interface 192.168.100.2
+ Interface veth2
+ SndSocketBuffer 1249280
+ RcvSocketBuffer 1249280
+ Checksum on
+ }
+}
+General {
+ HashSize 32768
+ HashLimit 131072
+ LogFile on
+ LockFile /var/lock/conntrack-nsr1.lock
+ UNIX {
+ Path /var/run/conntrackd-nsr1.ctl
+ }
+ NetlinkBufferSize 2097152
+ NetlinkBufferSizeMaxGrowth 8388608
+ Filter From Userspace {
+ Protocol Accept {
+ TCP
+ SCTP
+ DCCP
+ }
+ Address Ignore {
+ IPv4_address 127.0.0.1
+ IPv4_address 192.168.10.1
+ IPv4_address 10.0.10.1
+ IPv4_address 192.168.100.2
+ }
+ }
+}
diff --git a/tests/conntrackd/netns/conntrackd-nsr2.conf b/tests/conntrackd/netns/conntrackd-nsr2.conf
new file mode 100644
index 0000000..65fa0d6
--- /dev/null
+++ b/tests/conntrackd/netns/conntrackd-nsr2.conf
@@ -0,0 +1,37 @@
+Sync {
+ Mode FTFW {
+ }
+ Multicast {
+ IPv4_address 225.0.0.50
+ Group 3780
+ IPv4_interface 192.168.100.3
+ Interface veth0
+ SndSocketBuffer 1249280
+ RcvSocketBuffer 1249280
+ Checksum on
+ }
+}
+General {
+ HashSize 32768
+ HashLimit 131072
+ LogFile on
+ LockFile /var/lock/conntrack-nsr2.lock
+ UNIX {
+ Path /var/run/conntrackd-nsr2.ctl
+ }
+ NetlinkBufferSize 2097152
+ NetlinkBufferSizeMaxGrowth 8388608
+ Filter From Userspace {
+ Protocol Accept {
+ TCP
+ SCTP
+ DCCP
+ }
+ Address Ignore {
+ IPv4_address 127.0.0.1
+ IPv4_address 192.168.10.1
+ IPv4_address 10.0.10.1
+ IPv4_address 192.168.100.2
+ }
+ }
+}
diff --git a/tests/conntrackd/netns/ruleset-nsr1.nft b/tests/conntrackd/netns/ruleset-nsr1.nft
new file mode 100644
index 0000000..bd6f1b4
--- /dev/null
+++ b/tests/conntrackd/netns/ruleset-nsr1.nft
@@ -0,0 +1,6 @@
+table ip filter {
+ chain postrouting {
+ type nat hook postrouting priority srcnat; policy accept;
+ oif veth0 masquerade
+ }
+}
diff --git a/tests/conntrackd/scenarios.yaml b/tests/conntrackd/scenarios.yaml
new file mode 100644
index 0000000..65d6fa4
--- /dev/null
+++ b/tests/conntrackd/scenarios.yaml
@@ -0,0 +1,100 @@
+- name: empty
+ start:
+ - ":"
+ stop:
+ - ":"
+- name: simple_stats
+ start:
+ - rm -f /var/lock/conntrack.lock
+ - |
+ cat << EOF > /tmp/conntrackd_test_simple_stats
+ General {
+ HashSize 8192
+ LockFile /var/lock/conntrack.lock
+ UNIX { Path /var/run/conntrackd.ctl }
+ }
+ Stats {
+ LogFile on
+ }
+ EOF
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -d
+ stop:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -k
+ - rm -f /var/lock/conntrack.lock
+ - rm -f /tmp/conntrackd_test_simple_stats
+
+- name: basic_2_peer_network_tcp_notrack
+ start:
+ - scenarios/basic/./network-setup.sh start
+ - |
+ cat << EOF > /tmp/ruleset.nft
+ table ip filter {
+ chain postrouting {
+ type nat hook postrouting priority srcnat; policy accept;
+ oif veth0 masquerade
+ }
+ }
+ EOF
+ - ip netns exec nsr1 nft -f /tmp/ruleset.nft
+ - |
+ cat << EOF > /tmp/nsr1.conf
+ Sync {
+ Mode NOTRACK {
+ DisableExternalCache on
+ DisableInternalCache on
+ }
+ TCP {
+ IPv4_address 192.168.100.2
+ IPv4_Destination_Address 192.168.100.3
+ Interface veth2
+ Port 3780
+ }
+ }
+ General {
+ LogFile on
+ LockFile /var/lock/conntrack-nsr1.lock
+ UNIX { Path /var/run/conntrackd-nsr1.ctl }
+ }
+ EOF
+ - |
+ cat << EOF > /tmp/nsr2.conf
+ Sync {
+ Mode NOTRACK {
+ DisableExternalCache on
+ DisableInternalCache on
+ }
+ TCP {
+ IPv4_address 192.168.100.3
+ IPv4_Destination_Address 192.168.100.2
+ Interface veth0
+ Port 3780
+ }
+ }
+ General {
+ LogFile on
+ LockFile /var/lock/conntrack-nsr2.lock
+ UNIX { Path /var/run/conntrackd-nsr2.ctl }
+ }
+ EOF
+ # finally run the daemons
+ - ip netns exec nsr1 $CONNTRACKD -C /tmp/nsr1.conf -d
+ - ip netns exec nsr2 $CONNTRACKD -C /tmp/nsr2.conf -d
+ # make sure they are alive and connected before considering the scenario started
+ - timeout 5 bash -c -- '
+ while ! ip netns exec nsr1 $CONNTRACKD -C /tmp/nsr1.conf -s | grep -q "server=connected"
+ ; do sleep 0.5 ; done'
+ - timeout 5 bash -c -- '
+ while ! ip netns exec nsr1 $CONNTRACKD -C /tmp/nsr1.conf -s | grep -q "client=connected"
+ ; do sleep 0.5 ; done'
+ - timeout 5 bash -c -- '
+ while ! ip netns exec nsr2 $CONNTRACKD -C /tmp/nsr2.conf -s | grep -q "server=connected"
+ ; do sleep 0.5 ; done'
+ - timeout 5 bash -c -- '
+ while ! ip netns exec nsr2 $CONNTRACKD -C /tmp/nsr2.conf -s | grep -q "client=connected"
+ ; do sleep 0.5 ; done'
+ stop:
+ - $CONNTRACKD -C /tmp/nsr1.conf -k 2>/dev/null
+ - $CONNTRACKD -C /tmp/nsr2.conf -k 2>/dev/null
+ - rm -f /tmp/ruleset.nft /tmp/nsr2.conf /tmp/nsr1.conf
+ - rm -f /var/lock/conntrack-nsr1.lock /var/lock/conntrack-nsr2.lock
+ - scenarios/basic/./network-setup.sh stop
diff --git a/tests/conntrackd/scenarios/basic/network-setup.sh b/tests/conntrackd/scenarios/basic/network-setup.sh
new file mode 100755
index 0000000..7f2f78a
--- /dev/null
+++ b/tests/conntrackd/scenarios/basic/network-setup.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+if [ $UID -ne 0 ]
+then
+ echo "You must be root to run this test script"
+ exit 0
+fi
+
+start () {
+ ip netns add ns1
+ ip netns add ns2
+ ip netns add nsr1
+ ip netns add nsr2
+
+ ip link add veth0 netns ns1 type veth peer name veth1 netns nsr1
+ ip link add veth0 netns nsr1 type veth peer name veth0 netns ns2
+ ip link add veth2 netns nsr1 type veth peer name veth0 netns nsr2
+
+ ip -net ns1 addr add 192.168.10.2/24 dev veth0
+ ip -net ns1 link set up dev veth0
+ ip -net ns1 ro add 10.0.1.0/24 via 192.168.10.1 dev veth0
+
+ ip -net nsr1 addr add 10.0.1.1/24 dev veth0
+ ip -net nsr1 addr add 192.168.10.1/24 dev veth1
+ ip -net nsr1 link set up dev veth0
+ ip -net nsr1 link set up dev veth1
+ ip -net nsr1 route add default via 192.168.10.2
+ ip netns exec nsr1 sysctl -q net.ipv4.ip_forward=1
+
+ ip -net nsr1 addr add 192.168.100.2/24 dev veth2
+ ip -net nsr1 link set up dev veth2
+ ip -net nsr2 addr add 192.168.100.3/24 dev veth0
+ ip -net nsr2 link set up dev veth0
+
+ ip -net ns2 addr add 10.0.1.2/24 dev veth0
+ ip -net ns2 link set up dev veth0
+ ip -net ns2 route add default via 10.0.1.1
+}
+
+stop () {
+ ip netns del ns1
+ ip netns del ns2
+ ip netns del nsr1
+ ip netns del nsr2
+}
+
+case $1 in
+start)
+ start
+ ;;
+stop)
+ stop
+ ;;
+*)
+ echo "$0 [start|stop]"
+ ;;
+esac
+
+exit 0
diff --git a/tests/conntrackd/tests.yaml b/tests/conntrackd/tests.yaml
new file mode 100644
index 0000000..307f38f
--- /dev/null
+++ b/tests/conntrackd/tests.yaml
@@ -0,0 +1,83 @@
+- name: stats_general
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: general
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s | grep -q "cache stats"
+
+- name: stats_network
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: network (no output)
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s network
+
+- name: stats_runtime
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: runtime
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s runtime | grep -q uptime
+
+- name: stats_process
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: process (no output)
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s process
+
+- name: stats_queue
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: queue (no output)
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s queue
+
+- name: stats_ct
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: ct
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s ct | grep -q traffic
+
+- name: stats_expect
+ scenario: simple_stats
+ # check that we can obtain stats via unix socket: expect (no output)
+ test:
+ - $CONNTRACKD -C /tmp/conntrackd_test_simple_stats -s expect
+
+- name: tcp_notrack_replicate_icmp
+ scenario: basic_2_peer_network_tcp_notrack
+ # check that we can replicate a ICMP conntrack entry in a 2 conntrackd TCP/NOTRACK setup
+ test:
+ # PING should inject an ICMP conntrack entry in nsr1
+ - ip netns exec ns1 ping -c1 10.0.1.2 >/dev/null
+ # verify conntrack entry is then replicated to nsr2, wait up to 5 seconds
+ - timeout 5 bash -c -- '
+ while ! ip netns exec nsr2 $CONNTRACK -L -p icmp 2>/dev/null | grep -q icmp
+ ; do sleep 0.5 ; done'
+
+- name: hash_defaults_segfault
+ scenario: empty
+ test:
+ - rm -f /var/lock/conntrack.lock
+ - |
+ cat << EOF > /tmp/conntrackd_notrack_hash_defaults
+ Sync {
+ Mode NOTRACK { }
+ Multicast {
+ IPv4_address 225.0.0.50
+ Group 3780
+ IPv4_interface 127.0.0.1
+ Interface lo
+ SndSocketBuffer 1249280
+ RcvSocketBuffer 1249280
+ Checksum on
+ }
+ }
+ General {
+ LogFile on
+ Syslog on
+ LockFile /var/lock/conntrackd.lock
+ UNIX { Path /var/run/conntrackd.sock }
+ NetlinkBufferSize 2097152
+ NetlinkBufferSizeMaxGrowth 8388608
+ }
+ EOF
+ - $CONNTRACKD -C /tmp/conntrackd_notrack_hash_defaults -d
+ - $CONNTRACKD -C /tmp/conntrackd_notrack_hash_defaults -s | grep -q "cache"
+ - $CONNTRACKD -C /tmp/conntrackd_notrack_hash_defaults -k