git: 79b69575d838 - stable/13 - pf: support SCTP-specific timeouts

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Tue, 07 Nov 2023 15:47:26 UTC
The branch stable/13 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=79b69575d838f40a96b3ef68aa633a84da04c9df

commit 79b69575d838f40a96b3ef68aa633a84da04c9df
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-10-27 14:45:07 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-11-07 15:25:02 +0000

    pf: support SCTP-specific timeouts
    
    Allow SCTP state timeouts to be configured independently from TCP state
    timeouts.
    
    Reviewed by:    tuexen
    MFC after:      1 week
    Sponsored by:   Orange Business Services
    Differential Revision:  https://reviews.freebsd.org/D42393
    
    (cherry picked from commit ca9dbde88122beb079b55fb4580b200f73044da6)
---
 sbin/pfctl/pfctl.c               |  5 +++++
 sbin/pfctl/pfctl_parser.c        |  5 +++++
 sbin/pfctl/tests/files/pf1002.in |  5 +++++
 sbin/pfctl/tests/files/pf1002.ok |  5 +++++
 share/man/man5/pf.conf.5         | 19 ++++++++++++++++++-
 sys/netpfil/pf/pf.c              | 14 +++++++++-----
 sys/netpfil/pf/pf.h              | 41 +++++++++++++++++++++++++++++++---------
 sys/netpfil/pf/pf_ioctl.c        |  5 +++++
 8 files changed, 84 insertions(+), 15 deletions(-)

diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 645ba1d6fcaf..985cbe0771c0 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1856,6 +1856,11 @@ pfctl_init_options(struct pfctl *pf)
 	pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
 	pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
 	pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+	pf->timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+	pf->timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL;
+	pf->timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+	pf->timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+	pf->timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL;
 	pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
 	pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
 	pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index a3863cb23ac6..ed152eca0010 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -192,6 +192,11 @@ const struct pf_timeout pf_timeouts[] = {
 	{ "tcp.finwait",	PFTM_TCP_FIN_WAIT },
 	{ "tcp.closed",		PFTM_TCP_CLOSED },
 	{ "tcp.tsdiff",		PFTM_TS_DIFF },
+	{ "sctp.first",		PFTM_SCTP_FIRST_PACKET },
+	{ "sctp.opening",	PFTM_SCTP_OPENING },
+	{ "sctp.established",	PFTM_SCTP_ESTABLISHED },
+	{ "sctp.closing",	PFTM_SCTP_CLOSING },
+	{ "sctp.closed",	PFTM_SCTP_CLOSED },
 	{ "udp.first",		PFTM_UDP_FIRST_PACKET },
 	{ "udp.single",		PFTM_UDP_SINGLE },
 	{ "udp.multiple",	PFTM_UDP_MULTIPLE },
diff --git a/sbin/pfctl/tests/files/pf1002.in b/sbin/pfctl/tests/files/pf1002.in
index 5180e8395f9c..3fdde81be7de 100644
--- a/sbin/pfctl/tests/files/pf1002.in
+++ b/sbin/pfctl/tests/files/pf1002.in
@@ -1 +1,6 @@
 set timeout interval 10
+set timeout sctp.first 11
+set timeout sctp.opening 12
+set timeout sctp.established 13
+set timeout sctp.closing 14
+set timeout sctp.closed 15
diff --git a/sbin/pfctl/tests/files/pf1002.ok b/sbin/pfctl/tests/files/pf1002.ok
index 5180e8395f9c..3fdde81be7de 100644
--- a/sbin/pfctl/tests/files/pf1002.ok
+++ b/sbin/pfctl/tests/files/pf1002.ok
@@ -1 +1,6 @@
 set timeout interval 10
+set timeout sctp.first 11
+set timeout sctp.opening 12
+set timeout sctp.established 13
+set timeout sctp.closing 14
+set timeout sctp.closed 15
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index fa7bdc9587b2..6168bc3e8089 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -27,7 +27,7 @@
 .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd June 21, 2023
+.Dd October 27, 2023
 .Dt PF.CONF 5
 .Os
 .Sh NAME
@@ -281,6 +281,21 @@ can prevent blocking of such packets.
 The state after one endpoint sends an RST.
 .El
 .Pp
+SCTP timeout are handled similar to TCP, but with its own set of states:
+.Pp
+.Bl -tag -width xxxx -compact
+.It Ar sctp.first
+The state after the first packet.
+.It Ar sctp.opening
+The state before the destination host ever sends a packet.
+.It Ar sctp.established
+The fully established state.
+.It Ar sctp.closing
+The state after the first SHUTDOWN chunk has been sent.
+.It Ar sctp.closed
+The state after SHUTDOWN_ACK has been exchanged and the connection is closed.
+.El
+.Pp
 ICMP and UDP are handled in a fashion similar to TCP, but with a much more
 limited set of states:
 .Pp
@@ -3120,6 +3135,8 @@ fragmentation  = [ "fragment reassemble" ]
 timeout-list   = timeout [ [ "," ] timeout-list ]
 timeout        = ( "tcp.first" | "tcp.opening" | "tcp.established" |
                  "tcp.closing" | "tcp.finwait" | "tcp.closed" |
+                 "sctp.first" | "sctp.opening" | "sctp.established" |
+                 "sctp.closing" | "sctp.closed" |
                  "udp.first" | "udp.single" | "udp.multiple" |
                  "icmp.first" | "icmp.error" |
                  "other.first" | "other.single" | "other.multiple" |
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 278aa07fab75..7bac94f77a32 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4336,7 +4336,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
 	case IPPROTO_SCTP:
 		pf_set_protostate(s, PF_PEER_SRC, SCTP_COOKIE_WAIT);
 		pf_set_protostate(s, PF_PEER_DST, SCTP_CLOSED);
-		s->timeout = PFTM_TCP_FIRST_PACKET;
+		s->timeout = PFTM_SCTP_FIRST_PACKET;
 		break;
 	case IPPROTO_ICMP:
 #ifdef INET6
@@ -5326,7 +5326,7 @@ pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif,
 	if (pd->sctp_flags & PFDESC_SCTP_INIT) {
 		if (src->state < SCTP_COOKIE_WAIT) {
 			pf_set_protostate(*state, psrc, SCTP_COOKIE_WAIT);
-			(*state)->timeout = PFTM_TCP_OPENING;
+			(*state)->timeout = PFTM_SCTP_OPENING;
 		}
 	}
 	if (pd->sctp_flags & PFDESC_SCTP_INIT_ACK) {
@@ -5338,16 +5338,20 @@ pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif,
 	if (pd->sctp_flags & PFDESC_SCTP_COOKIE) {
 		if (src->state < SCTP_ESTABLISHED) {
 			pf_set_protostate(*state, psrc, SCTP_ESTABLISHED);
-			(*state)->timeout = PFTM_TCP_ESTABLISHED;
+			(*state)->timeout = PFTM_SCTP_ESTABLISHED;
 		}
 	}
 	if (pd->sctp_flags & (PFDESC_SCTP_SHUTDOWN | PFDESC_SCTP_ABORT |
 	    PFDESC_SCTP_SHUTDOWN_COMPLETE)) {
 		if (src->state < SCTP_SHUTDOWN_PENDING) {
 			pf_set_protostate(*state, psrc, SCTP_SHUTDOWN_PENDING);
-			(*state)->timeout = PFTM_TCP_CLOSING;
+			(*state)->timeout = PFTM_SCTP_CLOSING;
 		}
 	}
+	if (pd->sctp_flags & (PFDESC_SCTP_SHUTDOWN_COMPLETE)) {
+		pf_set_protostate(*state, psrc, SCTP_CLOSED);
+		(*state)->timeout = PFTM_SCTP_CLOSED;
+	}
 
 	if (src->scrub != NULL) {
 		if (src->scrub->pfss_v_tag == 0) {
@@ -5627,7 +5631,7 @@ again:
 					psrc = PF_PEER_DST;
 				}
 				pf_set_protostate(sm, psrc, SCTP_SHUTDOWN_PENDING);
-				sm->timeout = PFTM_TCP_CLOSING;
+				sm->timeout = PFTM_SCTP_CLOSING;
 				PF_STATE_UNLOCK(sm);
 			}
 			break;
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 0b0e9f05251e..89162ded3ef0 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -66,14 +66,37 @@ enum	{ PF_PEER_SRC, PF_PEER_DST, PF_PEER_BOTH };
  * Note about PFTM_*: real indices into pf_rule.timeout[] come before
  * PFTM_MAX, special cases afterwards. See pf_state_expires().
  */
-enum	{ PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
-	  PFTM_TCP_CLOSING, PFTM_TCP_FIN_WAIT, PFTM_TCP_CLOSED,
-	  PFTM_UDP_FIRST_PACKET, PFTM_UDP_SINGLE, PFTM_UDP_MULTIPLE,
-	  PFTM_ICMP_FIRST_PACKET, PFTM_ICMP_ERROR_REPLY,
-	  PFTM_OTHER_FIRST_PACKET, PFTM_OTHER_SINGLE,
-	  PFTM_OTHER_MULTIPLE, PFTM_FRAG, PFTM_INTERVAL,
-	  PFTM_ADAPTIVE_START, PFTM_ADAPTIVE_END, PFTM_SRC_NODE,
-	  PFTM_TS_DIFF, PFTM_MAX, PFTM_PURGE, PFTM_UNLINKED };
+enum	{
+	PFTM_TCP_FIRST_PACKET	= 0,
+	PFTM_TCP_OPENING	= 1,
+	PFTM_TCP_ESTABLISHED	= 2,
+	PFTM_TCP_CLOSING	= 3,
+	PFTM_TCP_FIN_WAIT	= 4,
+	PFTM_TCP_CLOSED		= 5,
+	PFTM_UDP_FIRST_PACKET	= 6,
+	PFTM_UDP_SINGLE		= 7,
+	PFTM_UDP_MULTIPLE	= 8,
+	PFTM_ICMP_FIRST_PACKET	= 9,
+	PFTM_ICMP_ERROR_REPLY	= 10,
+	PFTM_OTHER_FIRST_PACKET	= 11,
+	PFTM_OTHER_SINGLE	= 12,
+	PFTM_OTHER_MULTIPLE	= 13,
+	PFTM_FRAG		= 14,
+	PFTM_INTERVAL		= 15,
+	PFTM_ADAPTIVE_START	= 16,
+	PFTM_ADAPTIVE_END	= 17,
+	PFTM_SRC_NODE		= 18,
+	PFTM_TS_DIFF		= 19,
+	PFTM_OLD_MAX		= 20, /* Legacy limit, for binary compatibility with old kernels. */
+	PFTM_SCTP_FIRST_PACKET	= 20,
+	PFTM_SCTP_OPENING	= 21,
+	PFTM_SCTP_ESTABLISHED	= 22,
+	PFTM_SCTP_CLOSING	= 23,
+	PFTM_SCTP_CLOSED	= 24,
+	PFTM_MAX		= 25,
+	PFTM_PURGE		= 26,
+	PFTM_UNLINKED		= 27,
+};
 
 /* PFTM default values */
 #define PFTM_TCP_FIRST_PACKET_VAL	120	/* First TCP packet */
@@ -503,7 +526,7 @@ struct pf_rule {
 	pf_osfp_t		 os_fingerprint;
 
 	int			 rtableid;
-	u_int32_t		 timeout[PFTM_MAX];
+	u_int32_t		 timeout[PFTM_OLD_MAX];
 	u_int32_t		 max_states;
 	u_int32_t		 max_src_nodes;
 	u_int32_t		 max_src_states;
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index bd005893f7c8..44b0bccc7489 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -354,6 +354,11 @@ pfattach_vnet(void)
 	my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
 	my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
 	my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+	my_timeout[PFTM_SCTP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+	my_timeout[PFTM_SCTP_OPENING] = PFTM_TCP_OPENING_VAL;
+	my_timeout[PFTM_SCTP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+	my_timeout[PFTM_SCTP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+	my_timeout[PFTM_SCTP_CLOSED] = PFTM_TCP_CLOSED_VAL;
 	my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
 	my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
 	my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;