git: 3200a274272d - main - sctp: Allow to ignore iface type when determining address scope
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 22 Oct 2026 15:14:39 UTC
The branch main has been updated by pouria:
URL: https://cgit.FreeBSD.org/src/commit/?id=3200a274272d28cf6d2385a8ea46959f313866de
commit 3200a274272d28cf6d2385a8ea46959f313866de
Author: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-10-21 15:53:51 +0000
Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-10-22 15:13:42 +0000
sctp: Allow to ignore iface type when determining address scope
Scope restriction by loopback interface was not specified in
the draft-stewart-tsvwg-sctp-ipv4 draft and having global address
on loopback interface is common.
Therefore, allow to skip loopback interface type check in sctp.
Reviewed by: tuexen
Differential Revision: https://reviews.freebsd.org/D60938
---
share/man/man4/sctp.4 | 4 +++-
sys/netinet/sctp_asconf.c | 15 +++++++++++++++
sys/netinet/sctp_os_bsd.h | 3 ++-
sys/netinet/sctp_output.c | 10 ++++++++++
sys/netinet/sctp_pcb.c | 16 +++++++++++++++-
sys/netinet/sctp_sysctl.c | 10 ++++++++++
sys/netinet/sctp_sysctl.h | 6 ++++++
sys/netinet/sctp_usrreq.c | 8 ++++++++
sys/netinet/sctputil.c | 8 ++++++++
9 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/share/man/man4/sctp.4 b/share/man/man4/sctp.4
index 287e16f3b599..89d58a0e207f 100644
--- a/share/man/man4/sctp.4
+++ b/share/man/man4/sctp.4
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 21, 2023
+.Dd October 21, 2026
.Dt SCTP 4
.Os
.Sh NAME
@@ -605,6 +605,8 @@ Enable SCTP Auto-ASCONF.
Maximum incoming SCTP buffer size.
.It Va sendspace
Maximum outgoing SCTP buffer size.
+.It Va ignore_loopback_iftype
+Ignore interface type when determining loopback address scope.
.El
.El
.Sh SEE ALSO
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 6b98557c45a6..061e4ae0f271 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -2456,6 +2456,11 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
&sin->sin_addr) != 0) {
continue;
}
+
+ if (stcb->asoc.scope.loopback_scope == 0 &&
+ IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr))
+ continue;
+
if (stcb->asoc.scope.ipv4_local_scope == 0 &&
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
continue;
@@ -2494,6 +2499,9 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
&sin6->sin6_addr) != 0) {
continue;
}
+ if (stcb->asoc.scope.loopback_scope == 0 &&
+ IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+ continue;
if (stcb->asoc.scope.local_scope == 0 &&
IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
continue;
@@ -3095,6 +3103,9 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
&sin->sin_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr)))
+ continue;
if ((ipv4_scope == 0) &&
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
/* private address not in scope */
@@ -3109,6 +3120,10 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
&sin6->sin6_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))) {
+ continue;
+ }
if ((local_scope == 0) &&
(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
continue;
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 9cec02aa6a07..01f003c1ef4b 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -198,7 +198,8 @@ MALLOC_DECLARE(SCTP_M_MCORE);
#define SCTP_VRF_IFN_HASH_SIZE 3
#define SCTP_INIT_VRF_TABLEID(vrf)
-#define SCTP_IFN_IS_IFT_LOOP(ifn) ((ifn)->ifn_type == IFT_LOOP)
+#define SCTP_IFN_IS_IFT_LOOP(ifn) \
+ ((SCTP_BASE_SYSCTL(sctp_ignore_loopback_iftype) == 0) && ((ifn)->ifn_type == IFT_LOOP))
#define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_nh && (ro)->ro_nh->nh_ifa && (ro)->ro_nh->nh_ifa->ifa_ifp && (ro)->ro_nh->nh_ifa->ifa_ifp->if_type == IFT_LOOP)
/*
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 85513d32fedf..2021a31ca601 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -1883,6 +1883,11 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa,
/* not in scope , unspecified */
return (0);
}
+ if (scope->loopback_scope == 0 &&
+ ifa->src_is_loop == 1) {
+ /* not in scope , loopback */
+ return (0);
+ }
if ((scope->ipv4_local_scope == 0) &&
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
/* private address not in scope */
@@ -1914,6 +1919,11 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa,
/* skip unspecified addresses */
return (0);
}
+ if (scope->loopback_scope == 0 &&
+ ifa->src_is_loop == 1) {
+ /* not in scope , loopback */
+ return (0);
+ }
if ( /* (local_scope == 0) && */
(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
return (0);
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 2092f20e3c22..536f4aa80c60 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -768,6 +768,10 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
sin = &sctp_ifa->address.sin;
rsin = (struct sockaddr_in *)to;
+ if (loopback_scope == 0 &&
+ IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr)) {
+ continue;
+ }
if ((ipv4_local_scope == 0) &&
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
continue;
@@ -795,6 +799,10 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to)
&sin6->sin6_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
+ continue;
+ }
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;
@@ -3659,7 +3667,10 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
}
} else {
/* Validate the address is in scope */
- if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) &&
+ if (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr) &&
+ (stcb->asoc.scope.loopback_scope == 0)) {
+ addr_inscope = 0;
+ } else if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) &&
(stcb->asoc.scope.ipv4_local_scope == 0)) {
addr_inscope = 0;
}
@@ -5607,9 +5618,12 @@ sctp_pcb_init(void)
TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", &SCTP_BASE_SYSCTL(sctp_hashtblsize));
TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", &SCTP_BASE_SYSCTL(sctp_pcbtblsize));
TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", &SCTP_BASE_SYSCTL(sctp_chunkscale));
+ TUNABLE_INT_FETCH("net.inet.sctp.ignore_loopback_iftype",
+ &SCTP_BASE_SYSCTL(sctp_ignore_loopback_iftype));
VALIDATE_LOADER_TUNABLE(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE);
VALIDATE_LOADER_TUNABLE(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE);
VALIDATE_LOADER_TUNABLE(sctp_chunkscale, SCTPCTL_CHUNKSCALE);
+ VALIDATE_LOADER_TUNABLE(sctp_ignore_loopback_iftype, SCTPCTL_IGNORE_LOOPBACK_IFTYPE);
SCTP_BASE_INFO(sctp_asochash) = SCTP_HASH_INIT((SCTP_BASE_SYSCTL(sctp_hashtblsize) * 31),
&SCTP_BASE_INFO(hashasocmark));
SCTP_BASE_INFO(sctp_ephash) = SCTP_HASH_INIT(SCTP_BASE_SYSCTL(sctp_hashtblsize),
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index bd2f23f40727..27448533329b 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -128,6 +128,7 @@ sctp_init_sysctls(void)
#if defined(SCTP_DEBUG)
SCTP_BASE_SYSCTL(sctp_debug_on) = SCTPCTL_DEBUG_DEFAULT;
#endif
+ SCTP_BASE_SYSCTL(sctp_ignore_loopback_iftype) = SCTPCTL_IGNORE_LOOPBACK_IFTYPE_DEFAULT;
}
/* It returns an upper limit. No filtering is done here */
@@ -284,6 +285,10 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
&sin->sin_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr)) {
+ continue;
+ }
if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
continue;
}
@@ -305,6 +310,10 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
&sin6->sin6_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
+ continue;
+ }
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0) {
continue;
@@ -989,6 +998,7 @@ SCTP_UINT_SYSCTL(blackhole, sctp_blackhole, SCTPCTL_BLACKHOLE);
SCTP_UINT_SYSCTL(sendall_limit, sctp_sendall_limit, SCTPCTL_SENDALL_LIMIT);
SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE);
SCTP_UINT_SYSCTL(ootb_with_zero_cksum, sctp_ootb_with_zero_cksum, SCTPCTL_OOTB_WITH_ZERO_CKSUM);
+SCTP_UINT_SYSCTL_RDTUN(ignore_loopback_iftype, sctp_ignore_loopback_iftype, SCTPCTL_IGNORE_LOOPBACK_IFTYPE);
#ifdef SCTP_DEBUG
SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG);
#endif
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index 46c015b0b854..950f53b62051 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -118,6 +118,7 @@ struct sctp_sysctl {
#if defined(SCTP_DEBUG)
uint32_t sctp_debug_on;
#endif
+ uint32_t sctp_ignore_loopback_iftype;
};
/*
@@ -549,6 +550,11 @@ struct sctp_sysctl {
#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_MAX 1
#define SCTPCTL_OOTB_WITH_ZERO_CKSUM_DEFAULT 0
+#define SCTPCTL_IGNORE_LOOPBACK_IFTYPE_DESC "Ignore interface type when determining loopback address scope"
+#define SCTPCTL_IGNORE_LOOPBACK_IFTYPE_MIN 0
+#define SCTPCTL_IGNORE_LOOPBACK_IFTYPE_MAX 1
+#define SCTPCTL_IGNORE_LOOPBACK_IFTYPE_DEFAULT 1
+
#if defined(SCTP_DEBUG)
/* debug: Configure debug output */
#define SCTPCTL_DEBUG_DESC "Configure debug output"
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 7c615b4cd02c..4345c0cc6326 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -1099,6 +1099,10 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
&sin->sin_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ (IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr))) {
+ continue;
+ }
if ((ipv4_local_scope == 0) &&
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
continue;
@@ -1147,6 +1151,10 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
&sin6->sin6_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))) {
+ continue;
+ }
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 119fad13c3f0..05fef2a7fad3 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -7016,6 +7016,10 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
&sin->sin_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ IN4_ISLOOPBACK_ADDRESS(&sin->sin_addr)) {
+ continue;
+ }
if ((ipv4_local_scope == 0) &&
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
continue;
@@ -7040,6 +7044,10 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
&sin6->sin6_addr) != 0) {
continue;
}
+ if (loopback_scope == 0 &&
+ IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
+ continue;
+ }
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;