aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/netpfil/pf
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sys/netpfil/pf')
-rw-r--r--tests/sys/netpfil/pf/Makefile2
-rw-r--r--tests/sys/netpfil/pf/anchor.sh46
-rw-r--r--tests/sys/netpfil/pf/divert-to.sh43
-rw-r--r--tests/sys/netpfil/pf/ether.sh3
-rw-r--r--tests/sys/netpfil/pf/ioctl/validation.c58
-rw-r--r--tests/sys/netpfil/pf/killstate.sh2
-rw-r--r--tests/sys/netpfil/pf/nat.sh112
-rw-r--r--tests/sys/netpfil/pf/pflog.sh7
-rw-r--r--tests/sys/netpfil/pf/proxy.sh61
-rw-r--r--tests/sys/netpfil/pf/rdr.sh51
-rw-r--r--tests/sys/netpfil/pf/rules_counter.sh1
-rw-r--r--tests/sys/netpfil/pf/sctp.py67
-rw-r--r--tests/sys/netpfil/pf/sctp.sh18
-rwxr-xr-xtests/sys/netpfil/pf/src_track.sh74
-rw-r--r--tests/sys/netpfil/pf/syncookie.sh5
-rw-r--r--tests/sys/netpfil/pf/table.sh62
-rw-r--r--tests/sys/netpfil/pf/tftpd_inetd.conf28
-rw-r--r--tests/sys/netpfil/pf/tftpd_proxy_inetd.conf27
18 files changed, 654 insertions, 13 deletions
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
index b363e0b17c76..9416f6abbdf1 100644
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -90,6 +90,8 @@ ${PACKAGE}FILES+= \
pft_ether.py \
pft_read_ipfix.py \
rdr-srcport.py \
+ tftpd_inetd.conf \
+ tftpd_proxy_inetd.conf \
utils.subr \
utils.py
diff --git a/tests/sys/netpfil/pf/anchor.sh b/tests/sys/netpfil/pf/anchor.sh
index 64ca84b34c3d..f321c742788e 100644
--- a/tests/sys/netpfil/pf/anchor.sh
+++ b/tests/sys/netpfil/pf/anchor.sh
@@ -123,6 +123,51 @@ nested_anchor_cleanup()
pft_cleanup
}
+atf_test_case "deeply_nested" "cleanup"
+deeply_nested_head()
+{
+ atf_set descr 'Test setting and retrieving deeply nested anchors'
+ atf_set require.user root
+}
+
+deeply_nested_body()
+{
+ pft_init
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail alcatraz ${epair}a
+
+ pft_set_rules alcatraz \
+ "anchor \"foo\" { \n\
+ anchor \"bar\" { \n\
+ anchor \"foobar\" { \n\
+ pass on ${epair}a \n\
+ } \n\
+ anchor \"quux\" { \n\
+ pass on ${epair}a \n\
+ } \n\
+ } \n\
+ anchor \"baz\" { \n\
+ pass on ${epair}a \n\
+ } \n\
+ anchor \"qux\" { \n\
+ pass on ${epair}a \n\
+ } \n\
+ }"
+
+ atf_check -s exit:0 -o \
+ inline:" foo\n foo/bar\n foo/bar/foobar\n foo/bar/quux\n foo/baz\n foo/qux\n" \
+ jexec alcatraz pfctl -sA
+
+ atf_check -s exit:0 -o inline:" foo/bar/foobar\n foo/bar/quux\n" \
+ jexec alcatraz pfctl -a foo/bar -sA
+}
+
+deeply_nested_cleanup()
+{
+ pft_cleanup
+}
+
atf_test_case "wildcard" "cleanup"
wildcard_head()
{
@@ -498,6 +543,7 @@ atf_init_test_cases()
atf_add_test_case "pr183198"
atf_add_test_case "pr279225"
atf_add_test_case "nested_anchor"
+ atf_add_test_case "deeply_nested"
atf_add_test_case "wildcard"
atf_add_test_case "nested_label"
atf_add_test_case "quick"
diff --git a/tests/sys/netpfil/pf/divert-to.sh b/tests/sys/netpfil/pf/divert-to.sh
index ae44cd5d51af..153136199311 100644
--- a/tests/sys/netpfil/pf/divert-to.sh
+++ b/tests/sys/netpfil/pf/divert-to.sh
@@ -372,6 +372,47 @@ in_dn_in_div_in_out_div_out_dn_out_cleanup()
pft_cleanup
}
+atf_test_case "pr260867" "cleanup"
+pr260867_head()
+{
+ atf_set descr 'Test for the loop reported in PR260867'
+ atf_set require.user root
+}
+
+pr260867_body()
+{
+ pft_init
+ divert_init
+
+ epair=$(vnet_mkepair)
+
+ ifconfig ${epair}a 192.0.2.1/24 up
+
+ vnet_mkjail alcatraz ${epair}b
+ jexec alcatraz ifconfig ${epair}b 192.0.2.2/24 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ jexec alcatraz /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
+ jexec alcatraz $(atf_get_srcdir)/../common/divapp 1001 divert-back &
+
+ jexec alcatraz pfctl -e
+ pft_set_rules alcatraz \
+ "pass in on ${epair}b proto tcp from any to port 7 divert-to 0.0.0.0 port 1001"
+
+ reply=$(echo "foo" | nc -N 192.0.2.2 7)
+ if ["${reply}" != "foo" ];
+ then
+ atf_fail "Did not receive echo reply"
+ fi
+}
+
+pr260867_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "in_div"
@@ -383,4 +424,6 @@ atf_init_test_cases()
atf_add_test_case "in_div_in_fwd_out_div_out"
atf_add_test_case "in_dn_in_div_in_out_div_out_dn_out"
+
+ atf_add_test_case "pr260867"
}
diff --git a/tests/sys/netpfil/pf/ether.sh b/tests/sys/netpfil/pf/ether.sh
index f0fdce50a7d3..f15dff06f9cd 100644
--- a/tests/sys/netpfil/pf/ether.sh
+++ b/tests/sys/netpfil/pf/ether.sh
@@ -287,6 +287,7 @@ captive_body()
# Run the echo server only on the gw, so we know we've redirectly
# correctly if we get an echo message.
jexec gw /usr/sbin/inetd -p ${PWD}/echo_inetd.pid $(atf_get_srcdir)/echo_inetd.conf
+ sleep 1
# Confirm that we're getting redirected
atf_check -s exit:0 -o match:"^foo$" -x "echo foo | nc -N 198.51.100.2 7"
@@ -305,6 +306,7 @@ captive_body()
# Start a server in srv
jexec srv /usr/sbin/inetd -p ${PWD}/echo_inetd.pid $(atf_get_srcdir)/echo_inetd.conf
+ sleep 1
# And now we can talk to that one.
atf_check -s exit:0 -o match:"^foo$" -x "echo foo | nc -N 198.51.100.2 7"
@@ -364,6 +366,7 @@ captive_long_body()
jexec gw /usr/sbin/inetd -p ${PWD}/gw.pid $(atf_get_srcdir)/echo_inetd.conf
jexec srv /usr/sbin/inetd -p ${PWD}/srv.pid $(atf_get_srcdir)/daytime_inetd.conf
+ sleep p1
echo foo | nc -N 198.51.100.2 13
diff --git a/tests/sys/netpfil/pf/ioctl/validation.c b/tests/sys/netpfil/pf/ioctl/validation.c
index 3e03163cc752..bb060e22f3a0 100644
--- a/tests/sys/netpfil/pf/ioctl/validation.c
+++ b/tests/sys/netpfil/pf/ioctl/validation.c
@@ -194,6 +194,38 @@ ATF_TC_CLEANUP(gettables, tc)
COMMON_CLEANUP();
}
+ATF_TC_WITH_CLEANUP(clrtables);
+ATF_TC_HEAD(clrtables, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "require.kmods", "pf");
+}
+
+ATF_TC_BODY(clrtables, tc)
+{
+ struct pfioc_table io;
+ struct pfr_table tbl;
+ int flags;
+
+ COMMON_HEAD();
+
+ flags = 0;
+
+ memset(&io, '/', sizeof(io));
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = &tbl;
+ io.pfrio_esize = 0;
+ io.pfrio_size = 1;
+
+ if (ioctl(dev, DIOCRCLRTABLES, &io) == 0)
+ atf_tc_fail("Request with unterminated anchor name succeeded");
+}
+
+ATF_TC_CLEANUP(clrtables, tc)
+{
+ COMMON_CLEANUP();
+}
+
ATF_TC_WITH_CLEANUP(gettstats);
ATF_TC_HEAD(gettstats, tc)
{
@@ -949,11 +981,36 @@ ATF_TC_CLEANUP(natlook, tc)
COMMON_CLEANUP();
}
+ATF_TC_WITH_CLEANUP(addstate);
+ATF_TC_HEAD(addstate, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "require.kmods", "pfsync");
+}
+
+ATF_TC_BODY(addstate, tc)
+{
+ struct pfioc_state st;
+
+ COMMON_HEAD();
+
+ memset(&st, 'a', sizeof(st));
+ st.state.timeout = PFTM_TCP_FIRST_PACKET;
+
+ ATF_CHECK_ERRNO(EINVAL, ioctl(dev, DIOCADDSTATE, &st) == -1);
+}
+
+ATF_TC_CLEANUP(addstate, tc)
+{
+ COMMON_CLEANUP();
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, addtables);
ATF_TP_ADD_TC(tp, deltables);
ATF_TP_ADD_TC(tp, gettables);
+ ATF_TP_ADD_TC(tp, clrtables);
ATF_TP_ADD_TC(tp, getastats);
ATF_TP_ADD_TC(tp, gettstats);
ATF_TP_ADD_TC(tp, clrtstats);
@@ -974,6 +1031,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, rpool_mtx);
ATF_TP_ADD_TC(tp, rpool_mtx2);
ATF_TP_ADD_TC(tp, natlook);
+ ATF_TP_ADD_TC(tp, addstate);
return (atf_no_error());
}
diff --git a/tests/sys/netpfil/pf/killstate.sh b/tests/sys/netpfil/pf/killstate.sh
index ffb01df57908..dc082464b36c 100644
--- a/tests/sys/netpfil/pf/killstate.sh
+++ b/tests/sys/netpfil/pf/killstate.sh
@@ -187,12 +187,14 @@ v6_body()
jexec alcatraz pfctl -e
pft_set_rules alcatraz "block all" \
+ "pass quick inet6 proto ipv6-icmp all icmp6-type { neighbrsol, neighbradv } no state" \
"pass in proto icmp6" \
"set skip on lo"
# Sanity check & establish state
atf_check -s exit:0 -o ignore ${common_dir}/pft_ping.py \
--sendif ${epair}a \
+ --fromaddr 2001:db8::1 \
--to 2001:db8::2 \
--replyif ${epair}a
diff --git a/tests/sys/netpfil/pf/nat.sh b/tests/sys/netpfil/pf/nat.sh
index e55f46418221..3d953b495953 100644
--- a/tests/sys/netpfil/pf/nat.sh
+++ b/tests/sys/netpfil/pf/nat.sh
@@ -55,6 +55,9 @@ exhaust_body()
jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up
jexec echo /usr/sbin/inetd -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
+ # Disable checksum offload on one of the interfaces to ensure pf handles that
+ jexec nat ifconfig ${epair_nat}a -txcsum
+
# Enable pf!
jexec nat pfctl -e
pft_set_rules nat \
@@ -257,6 +260,64 @@ endpoint_independent_compat_cleanup()
rm -f server2.out
}
+atf_test_case "endpoint_independent_exhaust" "cleanup"
+endpoint_independent_exhaust_head()
+{
+ atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
+ atf_set require.user root
+}
+
+endpoint_independent_exhaust_body()
+{
+ endpoint_independent_setup # Sets ${epair_…} variables
+
+ endpoint_independent_common \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)" \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) port 3000:3001 sticky-address endpoint-independent"
+
+ # Exhaust the available nat ports
+ for i in $(seq 1 10); do
+ echo "ping" | jexec client nc -u 198.51.100.32 1234 -w 0
+ echo "ping" | jexec client nc -u 198.51.100.22 1234 -w 0
+ done
+}
+
+endpoint_independent_exhaust_cleanup()
+{
+ pft_cleanup
+ rm -f server1.out
+ rm -f server2.out
+}
+
+atf_test_case "endpoint_independent_static_port" "cleanup"
+endpoint_independent_static_port_head()
+{
+ atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers, with static-port'
+ atf_set require.user root
+}
+
+endpoint_independent_static_port_body()
+{
+ endpoint_independent_setup # Sets ${epair_…} variables
+
+ endpoint_independent_common \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)" \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) static-port sticky-address endpoint-independent"
+
+ # Exhaust the available nat ports
+ for i in $(seq 1 10); do
+ echo "ping" | jexec client nc -u 198.51.100.32 1234 -w 0
+ echo "ping" | jexec client nc -u 198.51.100.22 1234 -w 0
+ done
+}
+
+endpoint_independent_static_port_cleanup()
+{
+ pft_cleanup
+ rm -f server1.out
+ rm -f server2.out
+}
+
atf_test_case "endpoint_independent_pass" "cleanup"
endpoint_independent_pass_head()
{
@@ -474,14 +535,49 @@ no_addrs_random_cleanup()
pft_cleanup
}
-nat_pass_head()
+atf_test_case "nat_pass_in" "cleanup"
+nat_pass_in_head()
+{
+ atf_set descr 'IPv4 NAT on inbound pass rule'
+ atf_set require.user root
+ atf_set require.progs scapy
+}
+
+nat_pass_in_body()
+{
+ setup_router_server_ipv4
+ # Delete the route back to make sure that the traffic has been NAT-ed
+ jexec server route del -net ${net_tester} ${net_server_host_router}
+ # Provide routing back to the NAT address
+ jexec server route add 203.0.113.0/24 ${net_server_host_router}
+ jexec router route add 203.0.113.0/24 -iface ${epair_tester}b
+
+ pft_set_rules router \
+ "block" \
+ "pass in on ${epair_tester}b inet proto tcp nat-to 203.0.113.0 keep state" \
+ "pass out on ${epair_server}a inet proto tcp keep state"
+
+ ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
+
+ jexec router pfctl -qvvsr
+ jexec router pfctl -qvvss
+ jexec router ifconfig
+ jexec router netstat -rn
+}
+
+nat_pass_in_cleanup()
+{
+ pft_cleanup
+}
+
+nat_pass_out_head()
{
- atf_set descr 'IPv4 NAT on pass rule'
+ atf_set descr 'IPv4 NAT on outbound pass rule'
atf_set require.user root
atf_set require.progs scapy
}
-nat_pass_body()
+nat_pass_out_body()
{
setup_router_server_ipv4
# Delete the route back to make sure that the traffic has been NAT-ed
@@ -500,11 +596,12 @@ nat_pass_body()
jexec router netstat -rn
}
-nat_pass_cleanup()
+nat_pass_out_cleanup()
{
pft_cleanup
}
+atf_test_case "nat_match" "cleanup"
nat_match_head()
{
atf_set descr 'IPv4 NAT on match rule'
@@ -644,6 +741,7 @@ map_e_pass_cleanup()
pft_cleanup
}
+atf_test_case "binat_compat" "cleanup"
binat_compat_head()
{
atf_set descr 'IPv4 BINAT with nat ruleset'
@@ -710,6 +808,7 @@ binat_compat_cleanup()
kill $(cat ${PWD}/inetd_tester.pid)
}
+atf_test_case "binat_match" "cleanup"
binat_match_head()
{
atf_set descr 'IPv4 BINAT with nat ruleset'
@@ -859,6 +958,8 @@ atf_init_test_cases()
atf_add_test_case "exhaust"
atf_add_test_case "nested_anchor"
atf_add_test_case "endpoint_independent_compat"
+ atf_add_test_case "endpoint_independent_exhaust"
+ atf_add_test_case "endpoint_independent_static_port"
atf_add_test_case "endpoint_independent_pass"
atf_add_test_case "nat6_nolinklocal"
atf_add_test_case "empty_table_source_hash"
@@ -867,7 +968,8 @@ atf_init_test_cases()
atf_add_test_case "no_addrs_random"
atf_add_test_case "map_e_compat"
atf_add_test_case "map_e_pass"
- atf_add_test_case "nat_pass"
+ atf_add_test_case "nat_pass_in"
+ atf_add_test_case "nat_pass_out"
atf_add_test_case "nat_match"
atf_add_test_case "binat_compat"
atf_add_test_case "binat_match"
diff --git a/tests/sys/netpfil/pf/pflog.sh b/tests/sys/netpfil/pf/pflog.sh
index 550548a59c11..b11b1a3bade0 100644
--- a/tests/sys/netpfil/pf/pflog.sh
+++ b/tests/sys/netpfil/pf/pflog.sh
@@ -205,9 +205,11 @@ state_max_body()
epair=$(vnet_mkepair)
vnet_mkjail alcatraz ${epair}a
+ jexec alcatraz ifconfig ${epair}a inet6 ifdisabled
jexec alcatraz ifconfig ${epair}a 192.0.2.1/24 up
ifconfig ${epair}b 192.0.2.2/24 up
+ ifconfig ${epair}b inet6 ifdisabled
# Sanity check
atf_check -s exit:0 -o ignore \
@@ -353,6 +355,11 @@ rdr_action_body()
vnet_mkjail ${j}gw ${epair_srv}b ${epair_c}a
vnet_mkjail ${j}c ${epair_c}b
+ jexec ${j}srv ifconfig ${epair_srv}a inet6 ifdisabled
+ jexec ${j}gw ifconfig ${epair_srv}b inet6 ifdisabled
+ jexec ${j}gw ifconfig ${epair_c}a inet6 ifdisabled
+ jexec ${j}c ifconfig ${epair_c}b inet6 ifdisabled
+
jexec ${j}srv ifconfig ${epair_srv}a 198.51.100.1/24 up
# No default route in srv jail, to ensure we're NAT-ing
jexec ${j}gw ifconfig ${epair_srv}b 198.51.100.2/24 up
diff --git a/tests/sys/netpfil/pf/proxy.sh b/tests/sys/netpfil/pf/proxy.sh
index 78ce25930c04..a07bb259b544 100644
--- a/tests/sys/netpfil/pf/proxy.sh
+++ b/tests/sys/netpfil/pf/proxy.sh
@@ -88,7 +88,68 @@ ftp_cleanup()
pft_cleanup
}
+atf_test_case "tftp" "cleanup"
+tftp_head()
+{
+ atf_set descr 'Test tftp-proxy'
+ atf_set require.user root
+}
+
+tftp_body()
+{
+ pft_init
+
+ epair_client=$(vnet_mkepair)
+ epair_link=$(vnet_mkepair)
+
+ ifconfig ${epair_client}a 192.0.2.2/24 up
+ route add -net 198.51.100.0/24 192.0.2.1
+
+ vnet_mkjail fwd ${epair_client}b ${epair_link}a
+ jexec fwd ifconfig lo0 127.0.0.1/8 up
+ jexec fwd ifconfig ${epair_client}b 192.0.2.1/24 up
+ jexec fwd ifconfig ${epair_link}a 198.51.100.1/24 up
+ jexec fwd ifconfig lo0 127.0.0.1/8 up
+ jexec fwd sysctl net.inet.ip.forwarding=1
+
+ vnet_mkjail srv ${epair_link}b
+ jexec srv ifconfig ${epair_link}b 198.51.100.2/24 up
+ jexec srv route add default 198.51.100.1
+
+ # Start tftp server in srv
+ jexec srv /usr/sbin/inetd -p ${PWD}/inetd-srv.pid \
+ $(atf_get_srcdir)/tftpd_inetd.conf
+
+ jexec fwd /usr/sbin/inetd -p ${PWD}/inetd-fwd.pid \
+ $(atf_get_srcdir)/tftpd_proxy_inetd.conf
+
+ jexec fwd pfctl -e
+ pft_set_rules fwd \
+ "nat on ${epair_link}a inet from 192.0.2.0/24 to any -> (${epair_link}a)" \
+ "nat-anchor \"tftp-proxy/*\"" \
+ "rdr-anchor \"tftp-proxy/*\"" \
+ "rdr pass on ${epair_client}b proto udp from 192.0.2.0/24 to any port 69 -> 127.0.0.1 port 69" \
+ "anchor \"tftp-proxy/*\"" \
+ "pass out proto udp from 127.0.0.1 to any port 69"
+
+ # Create a dummy file to download
+ echo 'foo' > /tmp/remote.txt
+ echo 'get remote.txt local.txt' | tftp 198.51.100.2
+
+ # Compare the downloaded file to the original
+ if ! diff -q local.txt /tmp/remote.txt;
+ then
+ atf_fail 'Failed to retrieve file'
+ fi
+}
+
+tftp_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "ftp"
+ atf_add_test_case "tftp"
}
diff --git a/tests/sys/netpfil/pf/rdr.sh b/tests/sys/netpfil/pf/rdr.sh
index 24b95b2047f4..b0f0e6d13d0f 100644
--- a/tests/sys/netpfil/pf/rdr.sh
+++ b/tests/sys/netpfil/pf/rdr.sh
@@ -338,6 +338,56 @@ natpass_cleanup()
pft_cleanup
}
+atf_test_case "pr290177" "cleanup"
+pr290177_head()
+{
+ atf_set descr 'Test PR290177'
+ atf_set require.user root
+}
+
+pr290177_body()
+{
+ pft_init
+
+ epair=$(vnet_mkepair)
+
+ ifconfig ${epair}a 192.0.2.2/24 up
+ ifconfig ${epair}a inet alias 192.0.2.3/24 up
+
+ vnet_mkjail alcatraz ${epair}b
+ jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up
+ jexec alcatraz ifconfig lo0 127.0.0.1/8 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore \
+ ping -c 1 192.0.2.1
+
+ jexec alcatraz pfctl -e
+ pft_set_rules alcatraz \
+ "table <white> { 192.0.2.2 }" \
+ "no rdr inet proto tcp from <white> to any port 25" \
+ "rdr pass inet proto tcp from any to any port 25 -> 127.0.0.1 port 2500"
+
+ echo foo | jexec alcatraz nc -N -l 2500 &
+ sleep 1
+
+ reply=$(nc -w 3 -s 192.0.2.2 192.0.2.1 25)
+ if [ "${reply}" == "foo" ]
+ then
+ atf_fail "no rdr rule failed"
+ fi
+ reply=$(nc -w 3 -s 192.0.2.3 192.0.2.1 25)
+ if [ "${reply}" != "foo" ]
+ then
+ atf_fail "rdr rule failed"
+ fi
+}
+
+pr290177_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "natpass"
@@ -345,4 +395,5 @@ atf_init_test_cases()
atf_add_test_case "tcp_v6_pass"
atf_add_test_case "srcport_compat"
atf_add_test_case "srcport_pass"
+ atf_add_test_case "pr290177"
}
diff --git a/tests/sys/netpfil/pf/rules_counter.sh b/tests/sys/netpfil/pf/rules_counter.sh
index 98f96a7adca1..e80a46e9d6c6 100644
--- a/tests/sys/netpfil/pf/rules_counter.sh
+++ b/tests/sys/netpfil/pf/rules_counter.sh
@@ -153,6 +153,7 @@ atf_test_case "4G" "cleanup"
{
atf_set descr 'Test keepcounter for values above 32 bits'
atf_set require.user root
+ atf_set timeout 900
}
4G_body()
diff --git a/tests/sys/netpfil/pf/sctp.py b/tests/sys/netpfil/pf/sctp.py
index f492f26b63a1..9f1d7dea4ef6 100644
--- a/tests/sys/netpfil/pf/sctp.py
+++ b/tests/sys/netpfil/pf/sctp.py
@@ -551,6 +551,73 @@ class TestSCTP(VnetTestTemplate):
assert re.search(r"epair.*sctp 192.0.2.1:.*192.0.2.3:1234", states)
assert re.search(r"epair.*sctp 192.0.2.1:.*192.0.2.2:1234", states)
+class TestSCTP_SRV(VnetTestTemplate):
+ REQUIRED_MODULES = ["sctp", "pf"]
+ TOPOLOGY = {
+ "vnet1": {"ifaces": ["if1"]},
+ "vnet2": {"ifaces": ["if1"]},
+ "if1": {"prefixes4": [("192.0.2.1/24", "192.0.2.2/24")]},
+ }
+
+ def vnet2_handler(self, vnet):
+ ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "set state-policy if-bound",
+ "pass inet proto sctp",
+ "pass on lo"])
+
+ # Start an SCTP server process, pipe the ppid + data back to the other vnet?
+ srv = SCTPServer(socket.AF_INET, port=1234)
+ while True:
+ srv.accept(vnet)
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_initiate_tag_check(self):
+ # Ensure we don't send ABORTs in response to the other end's INIT_ACK
+ # That'd interfere with our test.
+ ToolsHelper.print_output("/sbin/sysctl net.inet.sctp.blackhole=2")
+
+ import scapy.all as sp
+
+ packet = sp.IP(src="192.0.2.1", dst="192.0.2.2") \
+ / sp.SCTP(sport=1234, dport=1234) \
+ / sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, a_rwnd=1500)
+ packet.show()
+
+ r = sp.sr1(packet, timeout=3)
+ assert r
+ r.show()
+ assert r.getlayer(sp.SCTP)
+ assert r.getlayer(sp.SCTPChunkInitAck)
+ assert r.getlayer(sp.SCTP).tag == 1
+
+ # Send another INIT with the same initiate tag, expect another init ack
+ packet = sp.IP(src="192.0.2.1", dst="192.0.2.2") \
+ / sp.SCTP(sport=1234, dport=1234) \
+ / sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, a_rwnd=1500)
+ packet.show()
+
+ r = sp.sr1(packet, timeout=3)
+ assert r
+ r.show()
+ assert r.getlayer(sp.SCTP)
+ assert r.getlayer(sp.SCTPChunkInitAck)
+ assert r.getlayer(sp.SCTP).tag == 1
+
+ # Send an INIT with a different initiate tag, expect another init ack
+ packet = sp.IP(src="192.0.2.1", dst="192.0.2.2") \
+ / sp.SCTP(sport=1234, dport=1234) \
+ / sp.SCTPChunkInit(init_tag=42, n_in_streams=1, n_out_streams=1, a_rwnd=1500)
+ packet.show()
+
+ r = sp.sr1(packet, timeout=3)
+ assert r
+ r.show()
+ assert r.getlayer(sp.SCTP)
+ assert r.getlayer(sp.SCTPChunkInitAck)
+ assert r.getlayer(sp.SCTP).tag == 42
+
class TestSCTPv6(VnetTestTemplate):
REQUIRED_MODULES = ["sctp", "pf"]
TOPOLOGY = {
diff --git a/tests/sys/netpfil/pf/sctp.sh b/tests/sys/netpfil/pf/sctp.sh
index 78055f5a9dd2..47bf40181b1b 100644
--- a/tests/sys/netpfil/pf/sctp.sh
+++ b/tests/sys/netpfil/pf/sctp.sh
@@ -29,9 +29,6 @@
sctp_init()
{
pft_init
- if ! kldstat -q -m sctp; then
- atf_skip "This test requires SCTP"
- fi
}
atf_test_case "basic_v4" "cleanup"
@@ -39,6 +36,7 @@ basic_v4_head()
{
atf_set descr 'Basic SCTP connection over IPv4 passthrough'
atf_set require.user root
+ atf_set require.kmods sctp
}
basic_v4_body()
@@ -112,6 +110,7 @@ basic_v6_head()
{
atf_set descr 'Basic SCTP connection over IPv6'
atf_set require.user root
+ atf_set require.kmods sctp
}
basic_v6_body()
@@ -186,6 +185,7 @@ reuse_head()
{
atf_set descr 'Test handling dumb clients that reuse source ports'
atf_set require.user root
+ atf_set require.kmods sctp
}
reuse_body()
@@ -244,6 +244,7 @@ abort_v4_head()
{
atf_set descr 'Test sending ABORT messages'
atf_set require.user root
+ atf_set require.kmods sctp
}
abort_v4_body()
@@ -302,6 +303,7 @@ abort_v6_head()
{
atf_set descr 'Test sending ABORT messages over IPv6'
atf_set require.user root
+ atf_set require.kmods sctp
}
abort_v6_body()
@@ -360,6 +362,7 @@ nat_v4_head()
{
atf_set descr 'Test NAT-ing SCTP over IPv4'
atf_set require.user root
+ atf_set require.kmods sctp
}
nat_v4_body()
@@ -412,6 +415,7 @@ nat_v6_head()
{
atf_set descr 'Test NAT-ing SCTP over IPv6'
atf_set require.user root
+ atf_set require.kmods sctp
}
nat_v6_body()
@@ -464,6 +468,7 @@ rdr_v4_head()
{
atf_set descr 'Test rdr SCTP over IPv4'
atf_set require.user root
+ atf_set require.kmods sctp
}
rdr_v4_body()
@@ -531,6 +536,7 @@ pfsync_head()
{
atf_set descr 'Test pfsync-ing SCTP connections'
atf_set require.user root
+ atf_set require.kmods carp sctp
}
pfsync_body()
@@ -563,10 +569,6 @@ pfsync_body()
sctp_init
pfsynct_init
vnet_init_bridge
- if ! kldstat -q -m carp
- then
- atf_skip "This test requires carp"
- fi
j="sctp:pfsync"
@@ -722,6 +724,7 @@ timeout_head()
{
atf_set descr 'Test setting and retrieving timeout values'
atf_set require.user root
+ atf_set require.kmods sctp
}
timeout_body()
@@ -753,6 +756,7 @@ related_icmp_head()
{
atf_set descr 'Verify that ICMP messages related to an SCTP connection are allowed'
atf_set require.user root
+ atf_set require.kmods sctp
}
related_icmp_body()
diff --git a/tests/sys/netpfil/pf/src_track.sh b/tests/sys/netpfil/pf/src_track.sh
index d86b4ce6c466..1b09030f6174 100755
--- a/tests/sys/netpfil/pf/src_track.sh
+++ b/tests/sys/netpfil/pf/src_track.sh
@@ -588,6 +588,79 @@ mixed_af_cleanup()
pft_cleanup
}
+atf_test_case "check_valid" "cleanup"
+check_valid_head()
+{
+ atf_set descr 'Test if source node is invalidated on change in redirection pool'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+check_valid_body()
+{
+ setup_router_server_nat64
+
+ # Clients will connect from another network behind the router.
+ # This allows for using multiple source addresses.
+ jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester}
+
+ jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:1/128 alias
+ jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:2/128 alias
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set debug loud " \
+ "set state-policy if-bound" \
+ "table <targets> { ${net_server1_6}::42:1 }" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server1}a <targets>) } \
+ sticky-address \
+ proto tcp \
+ keep state"
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4201
+
+ # A source node is created using the original redirection target
+ nodes=$(mktemp) || exit 1
+ jexec router pfctl -qvvsS | normalize_pfctl_s > $nodes
+ node_regexp='2001:db8:44::1 -> 2001:db8:4201::42:1 .* states 1,.* route sticky-address'
+ grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
+
+ # Change contents of the redirection table
+ echo ${net_server1_6}::42:2 | jexec router pfctl -Tr -t targets -f -
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4202
+
+ # The original source node was deleted, a new one was created.
+ # It has 1 states.
+ jexec router pfctl -qvvsS | normalize_pfctl_s > $nodes
+ node_regexp='2001:db8:44::1 -> 2001:db8:4201::42:2 .* states 1,.* route sticky-address'
+ grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4203
+
+ # Without redirection table change the source node is reused.
+ # It has 2 states.
+ jexec router pfctl -qvvsS | normalize_pfctl_s > $nodes
+ node_regexp='2001:db8:44::1 -> 2001:db8:4201::42:2 .* states 2,.* route sticky-address'
+ grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
+}
+
+check_valid_cleanup()
+{
+ pft_cleanup
+}
+
+
atf_init_test_cases()
{
atf_add_test_case "source_track"
@@ -598,4 +671,5 @@ atf_init_test_cases()
atf_add_test_case "sn_types_compat"
atf_add_test_case "sn_types_pass"
atf_add_test_case "mixed_af"
+ atf_add_test_case "check_valid"
}
diff --git a/tests/sys/netpfil/pf/syncookie.sh b/tests/sys/netpfil/pf/syncookie.sh
index fad90f3b2618..460c923179a3 100644
--- a/tests/sys/netpfil/pf/syncookie.sh
+++ b/tests/sys/netpfil/pf/syncookie.sh
@@ -253,6 +253,9 @@ Creativity, no.
__EOF__
nc -l $addr $port >out &
+ # Give the background nc time to start
+ sleep 1
+
atf_check nc -N $addr $port < in
atf_check -o file:in cat out
@@ -307,7 +310,7 @@ loopback_v6_body()
loopback_test ::1 8080
epair=$(vnet_mkepair)
- atf_check ifconfig ${epair}a inet6 2001:db8::1/64
+ atf_check ifconfig ${epair}a inet6 2001:db8::1/64 no_dad
loopback_test 2001:db8::1 8081
}
diff --git a/tests/sys/netpfil/pf/table.sh b/tests/sys/netpfil/pf/table.sh
index 69fe12fc9804..6761ce652beb 100644
--- a/tests/sys/netpfil/pf/table.sh
+++ b/tests/sys/netpfil/pf/table.sh
@@ -747,6 +747,67 @@ in_anchor_cleanup()
pft_cleanup
}
+atf_test_case "replace" "cleanup"
+replace_head()
+{
+ atf_set descr 'Test table replace command'
+ atf_set require.user root
+}
+
+replace_body()
+{
+ pft_init
+ pwd=$(pwd)
+
+ epair_send=$(vnet_mkepair)
+ ifconfig ${epair_send}a 192.0.2.1/24 up
+
+ vnet_mkjail alcatraz ${epair_send}b
+ jexec alcatraz ifconfig ${epair_send}b 192.0.2.2/24 up
+ jexec alcatraz pfctl -e
+
+ pft_set_rules alcatraz \
+ "table <foo> counters { 192.0.2.1 }" \
+ "block all" \
+ "pass in from <foo> to any" \
+ "pass out from any to <foo>" \
+ "set skip on lo"
+
+ atf_check -s exit:0 -o ignore ping -c 3 192.0.2.2
+
+ # Replace the address
+ atf_check -s exit:0 -e "match:1 addresses added." -e "match:1 addresses deleted." \
+ jexec alcatraz pfctl -t foo -T replace 192.0.2.3
+ atf_check -s exit:0 -o "match:192.0.2.3" \
+ jexec alcatraz pfctl -t foo -T show
+ atf_check -s exit:2 -o ignore ping -c 3 192.0.2.2
+
+ # Negated address
+ atf_check -s exit:0 -e "match:1 addresses changed." \
+ jexec alcatraz pfctl -t foo -T replace "!192.0.2.3"
+
+ # Now add 500 addresses
+ for i in `seq 1 2`; do
+ for j in `seq 1 250`; do
+ echo "1.${i}.${j}.1" >> ${pwd}/foo.lst
+ done
+ done
+ atf_check -s exit:0 -e "match:500 addresses added." -e "match:1 addresses deleted." \
+ jexec alcatraz pfctl -t foo -T replace -f ${pwd}/foo.lst
+
+ atf_check -s exit:0 -o "not-match:192.0.2.3" \
+ jexec alcatraz pfctl -t foo -T show
+
+ # Loading the same list produces no changes.
+ atf_check -s exit:0 -e "match:no changes." \
+ jexec alcatraz pfctl -t foo -T replace -f ${pwd}/foo.lst
+}
+
+replace_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4_counters"
@@ -765,4 +826,5 @@ atf_init_test_cases()
atf_add_test_case "large"
atf_add_test_case "show_recursive"
atf_add_test_case "in_anchor"
+ atf_add_test_case "replace"
}
diff --git a/tests/sys/netpfil/pf/tftpd_inetd.conf b/tests/sys/netpfil/pf/tftpd_inetd.conf
new file mode 100644
index 000000000000..3554d0a7fb08
--- /dev/null
+++ b/tests/sys/netpfil/pf/tftpd_inetd.conf
@@ -0,0 +1,28 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -S -s /tmp
+tftp dgram udp6 wait root /usr/libexec/tftpd tftpd -l -S -s /tmp
diff --git a/tests/sys/netpfil/pf/tftpd_proxy_inetd.conf b/tests/sys/netpfil/pf/tftpd_proxy_inetd.conf
new file mode 100644
index 000000000000..aa5f000f3bba
--- /dev/null
+++ b/tests/sys/netpfil/pf/tftpd_proxy_inetd.conf
@@ -0,0 +1,27 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+tftp dgram udp wait root /usr/libexec/tftp-proxy tftp-proxy