From: Sriram Yagnaraman <sriram.yagnaraman@xxxxxxxx> This patch introduces a new proc entry to disable source port randomization for SCTP connections. As specified in RFC9260 all transport addresses used by an SCTP endpoint MUST use the same port number but can use multiple IP addresses. That means that all paths taken within an SCTP association should have the same port even if they pass through different NAT/middleboxes in the network. Disabling source port randomization provides a deterministic source port for the remote SCTP endpoint for all paths used in the SCTP association. On NAT/middlebox restarts we will always end up with the same port after the restart, and the SCTP endpoints involved in the SCTP association can remain transparent to restarts. Of course, there is a downside as this makes it impossible to have multiple SCTP endpoints behind NAT that use the same source port. But, this is a lesser of a problem than losing an existing association altogether. Reported-by: kernel test robot <lkp@xxxxxxxxx> Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@xxxxxxxx> --- include/net/netns/conntrack.h | 1 + net/netfilter/nf_conntrack_proto_sctp.c | 3 +++ net/netfilter/nf_conntrack_standalone.c | 13 +++++++++++++ net/netfilter/nf_nat_core.c | 10 +++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index e1290c159184..097bed663805 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -60,6 +60,7 @@ struct nf_dccp_net { #ifdef CONFIG_NF_CT_PROTO_SCTP struct nf_sctp_net { unsigned int timeouts[SCTP_CONNTRACK_MAX]; + u8 sctp_no_random_port; }; #endif diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 5a936334b517..5e4d3215dcf6 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -699,6 +699,9 @@ void nf_conntrack_sctp_init_net(struct net *net) * 'new' timeout, like udp or icmp. */ sn->timeouts[0] = sctp_timeouts[SCTP_CONNTRACK_CLOSED]; + + /* leave source port randomization as true by default */ + sn->sctp_no_random_port = 0; } const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp = { diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 4ffe84c5a82c..e35876ce418d 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -602,6 +602,7 @@ enum nf_ct_sysctl_index { NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_SENT, NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_ACKED, + NF_SYSCTL_CT_PROTO_SCTP_NO_RANDOM_PORT, #endif #ifdef CONFIG_NF_CT_PROTO_DCCP NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST, @@ -892,6 +893,14 @@ static struct ctl_table nf_ct_sysctl_table[] = { .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, + [NF_SYSCTL_CT_PROTO_SCTP_NO_RANDOM_PORT] = { + .procname = "nf_conntrack_sctp_no_random_port", + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, #endif #ifdef CONFIG_NF_CT_PROTO_DCCP [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST] = { @@ -1037,6 +1046,10 @@ static void nf_conntrack_standalone_init_sctp_sysctl(struct net *net, XASSIGN(HEARTBEAT_SENT, sn); XASSIGN(HEARTBEAT_ACKED, sn); #undef XASSIGN +#define XASSIGN(XNAME, rval) \ + table[NF_SYSCTL_CT_PROTO_SCTP_ ## XNAME].data = (rval) + XASSIGN(NO_RANDOM_PORT, &sn->sctp_no_random_port); +#undef XASSIGN #endif } diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 18319a6e6806..cdcff0ed094c 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -19,6 +19,7 @@ #include <net/netfilter/nf_conntrack_bpf.h> #include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_helper.h> +#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_seqadj.h> #include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_nat.h> @@ -422,10 +423,17 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple, } goto find_free_id; #endif + case IPPROTO_SCTP: + /* SCTP port randomization disabled, try to use the same source port + * as in the original packet. Drop packets if another endpoint tries + * to use same source port behind NAT. + */ + if (nf_sctp_pernet(nf_ct_net(ct))->sctp_no_random_port) + return; + fallthrough; case IPPROTO_UDP: case IPPROTO_UDPLITE: case IPPROTO_TCP: - case IPPROTO_SCTP: case IPPROTO_DCCP: if (maniptype == NF_NAT_MANIP_SRC) keyptr = &tuple->src.u.all; -- 2.34.1