mirror of https://gerrit.osmocom.org/libosmocore
socket: Add osmo_sock_init flag to enable SCTP ASCONF features
The SCTP_ASCONF_SUPPORTED sockopt, which enables ASCONF features for the SCTP associations managed by the SCTP socket, gets its default value from to sysctl "net.sctp.addip_enable", which, at least up to current kernel 6.4.8 is set to "0" (disabled) by default. As a result, ASCONF related features such as setsockopt(SCTP_SET_PEER_PRIMARY_ADDR) fail with -EPERM since ASNCONF extensions where not negotiated during the SCTP init handshake. This commit adds support for setting SCTP_ASCONF_SUPPORTED=1 during socket creation, since that needs to be applied before the first bind()/connect() (before first assoc is created). Furthermore, for ASCONF features to work properly, the assoc also needs to announce/use the AUTH extension, as per RFC5061 section 4.2.7. Otherwise, the peer receiving an SCTP INIT with ExtensionFeatures=ASCONF,ASCONF_ACK but without AUTH, will reject the assoc with an ABORT since it's not complying with spec (this behavior can be tweaked through sysctl "net.sctp.addip_noauth_enable"). The AUTH extension is enabled through sockopt SCTP_AUTH_SUPPORTED, and its default value is that of sysctl "net.sctp.auth_enable", which is also disabled (0) by default. Kernel support for those is relatively new: SCTP_FUTURE_ASSOC added in: 80df2704a375bb4b3c9c5cce9c00052361b16d61 Follows: v5.0-rc4 Precedes: v5.1-rc1 SCTP_ASCONF_SUPPORTED added in: df2c71ffdfae58961981d7cbcccea93688fc4e96 Follows: v5.3-rc5 Precedes: v5.4-rc1 SCTP_AUTH_SUPPORTED added in: 56dd525abd56f7acd7b44a52935726e3ada4916c Follows: v5.3-rc5 Precedes: v5.4-rc1 Related: OS#6076 Change-Id: Iac07031927b66a9d32d2bb2faab817e4c922a359
This commit is contained in:
parent
aea78a2483
commit
e83227f735
|
@ -94,6 +94,8 @@ char *osmo_sockaddr_to_str_c(void *ctx, const struct osmo_sockaddr *sockaddr);
|
|||
#define OSMO_SOCK_F_NO_MCAST_ALL (1 << 4)
|
||||
/*! use SO_REUSEADDR on UDP ports (required for multicast) */
|
||||
#define OSMO_SOCK_F_UDP_REUSEADDR (1 << 5)
|
||||
/*! use SCTP_AUTH_SUPPORTED + SCTP_ASCONF_SUPPORTED on SCTP socket (required for ASCONF / Peer Primary Address feature) */
|
||||
#define OSMO_SOCK_F_SCTP_ASCONF_SUPPORTED (1 << 6)
|
||||
|
||||
/*! use OSMO_SOCK_F_DSCP(x) to set IP DSCP 'x' for packets transmitted on the socket */
|
||||
#define OSMO_SOCK_F_DSCP(x) (((x)&0x3f) << 24)
|
||||
|
|
|
@ -696,6 +696,36 @@ static int addrinfo_to_sockaddr(uint16_t family, const struct addrinfo **result,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int setsockopt_sctp_auth_supported(int fd)
|
||||
{
|
||||
#ifdef SCTP_AUTH_SUPPORTED
|
||||
struct sctp_assoc_value assoc_val = {
|
||||
.assoc_id = SCTP_FUTURE_ASSOC,
|
||||
.assoc_value = 1,
|
||||
};
|
||||
return setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_SUPPORTED, &assoc_val, sizeof(assoc_val));
|
||||
#else
|
||||
#pragma message "setsockopt(SCTP_AUTH_SUPPORTED) not supported! some SCTP features may not be available!"
|
||||
LOGP(DLGLOBAL, LOGL_NOTICE, "Built without support for setsockopt(SCTP_AUTH_SUPPORTED), skipping\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int setsockopt_sctp_asconf_supported(int fd)
|
||||
{
|
||||
#ifdef SCTP_ASCONF_SUPPORTED
|
||||
struct sctp_assoc_value assoc_val = {
|
||||
.assoc_id = SCTP_FUTURE_ASSOC,
|
||||
.assoc_value = 1,
|
||||
};
|
||||
return setsockopt(fd, IPPROTO_SCTP, SCTP_ASCONF_SUPPORTED, &assoc_val, sizeof(assoc_val));
|
||||
#else
|
||||
#pragma message "setsockopt(SCTP_ASCONF_SUPPORTED) not supported! some SCTP features may not be available!"
|
||||
LOGP(DLGLOBAL, LOGL_NOTICE, "Built without support for setsockopt(SCTP_ASCONF_SUPPORTED), skipping\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! Initialize a socket (including bind and/or connect) with multiple local or remote addresses.
|
||||
* \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
|
||||
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
|
||||
|
@ -811,6 +841,29 @@ int osmo_sock_init2_multiaddr(uint16_t family, uint16_t type, uint8_t proto,
|
|||
goto ret_close;
|
||||
}
|
||||
|
||||
if (flags & OSMO_SOCK_F_SCTP_ASCONF_SUPPORTED) {
|
||||
/* RFC 5061 4.2.7: ASCONF also requires AUTH feature. */
|
||||
rc = setsockopt_sctp_auth_supported(sfd);
|
||||
if (rc < 0) {
|
||||
int err = errno;
|
||||
multiaddr_snprintf(strbuf, sizeof(strbuf), local_hosts, local_hosts_cnt);
|
||||
LOGP(DLGLOBAL, LOGL_ERROR,
|
||||
"cannot setsockopt(SCTP_AUTH_SUPPORTED) socket: %s:%u: %s\n",
|
||||
strbuf, local_port, strerror(err));
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
rc = setsockopt_sctp_asconf_supported(sfd);
|
||||
if (rc < 0) {
|
||||
int err = errno;
|
||||
multiaddr_snprintf(strbuf, sizeof(strbuf), local_hosts, local_hosts_cnt);
|
||||
LOGP(DLGLOBAL, LOGL_ERROR,
|
||||
"cannot setsockopt(SCTP_ASCONF_SUPPORTED) socket: %s:%u: %s\n",
|
||||
strbuf, local_port, strerror(err));
|
||||
goto ret_close;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build array of addresses taking first entry for each host.
|
||||
TODO: Ideally we should use backtracking storing last used
|
||||
indexes and trying next combination if connect() fails .*/
|
||||
|
|
Loading…
Reference in New Issue