From bc5627fc5f3002866c25d816c842dbe580d301f6 Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Mon, 12 Aug 2024 18:18:36 +0200 Subject: [PATCH] pf: cope with SCTP port re-use Some SCTP implementations will abort connections and then later re-use the same port numbers (i.e. both src and dst) for a new connection, before pf has fully purged the old connection. Apply the same hack we already have for similarly misbehaving TCP implementations and forcibly remove the old state so we can create a new one. MFC after: 2 weeks Sponsored by: Rubicon Communications, LLC ("Netgate") (cherry picked from commit 82e021443a76b1f210cfb929a495185179606868) --- sys/netpfil/pf/pf.c | 9 ++++++ tests/sys/netpfil/pf/sctp.sh | 59 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 10a5b993fbb..c61fe8aa1eb 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -6122,6 +6122,15 @@ pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif, psrc = PF_PEER_DST; } + if ((src->state >= SCTP_SHUTDOWN_SENT || src->state == SCTP_CLOSED) && + (dst->state >= SCTP_SHUTDOWN_SENT || dst->state == SCTP_CLOSED) && + pd->sctp_flags & PFDESC_SCTP_INIT) { + pf_set_protostate(*state, PF_PEER_BOTH, SCTP_CLOSED); + pf_unlink_state(*state); + *state = NULL; + return (PF_DROP); + } + /* Track state. */ if (pd->sctp_flags & PFDESC_SCTP_INIT) { if (src->state < SCTP_COOKIE_WAIT) { diff --git a/tests/sys/netpfil/pf/sctp.sh b/tests/sys/netpfil/pf/sctp.sh index d07d1122048..95a780747d8 100644 --- a/tests/sys/netpfil/pf/sctp.sh +++ b/tests/sys/netpfil/pf/sctp.sh @@ -181,6 +181,64 @@ basic_v6_cleanup() pft_cleanup } +atf_test_case "reuse" "cleanup" +reuse_head() +{ + atf_set descr 'Test handling dumb clients that reuse source ports' + atf_set require.user root +} + +reuse_body() +{ + sctp_init + + j="sctp:reuse" + epair=$(vnet_mkepair) + + vnet_mkjail ${j}a ${epair}a + vnet_mkjail ${j}b ${epair}b + + jexec ${j}a ifconfig ${epair}a 192.0.2.1/24 up + jexec ${j}b ifconfig ${epair}b 192.0.2.2/24 up + # Sanity check + atf_check -s exit:0 -o ignore \ + jexec ${j}a ping -c 1 192.0.2.2 + + jexec ${j}a pfctl -e + pft_set_rules ${j}a \ + "block" \ + "pass in proto sctp to port 1234" + + echo "foo" | jexec ${j}a nc --sctp -N -l 1234 & + + # Wait for the server to start + sleep 1 + + out=$(jexec ${j}b nc --sctp -N -w 3 -p 1234 192.0.2.1 1234) + if [ "$out" != "foo" ]; then + atf_fail "SCTP connection failed" + fi + + # Now do the same thing again, with the same port numbers + jexec ${j}a pfctl -ss -v + + echo "foo" | jexec ${j}a nc --sctp -N -l 1234 & + + # Wait for the server to start + sleep 1 + + out=$(jexec ${j}b nc --sctp -N -w 3 -p 1234 192.0.2.1 1234) + if [ "$out" != "foo" ]; then + atf_fail "SCTP connection failed" + fi + jexec ${j}a pfctl -ss -v +} + +reuse_cleanup() +{ + pft_cleanup +} + atf_test_case "abort_v4" "cleanup" abort_v4_head() { @@ -691,6 +749,7 @@ atf_init_test_cases() { atf_add_test_case "basic_v4" atf_add_test_case "basic_v6" + atf_add_test_case "reuse" atf_add_test_case "abort_v4" atf_add_test_case "abort_v6" atf_add_test_case "nat_v4"