From 79b69575d838f40a96b3ef68aa633a84da04c9df Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Fri, 27 Oct 2023 16:45:07 +0200 Subject: [PATCH] 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 @@ pf_sctp_multihome_delayed(struct pf_pdesc *pd, int off, struct pfi_kkif *kif, 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;