Outgoing connections bound with IP_BIND_ADDRESS_NO_PORT

The socket of a connection to the destination is bound to the external
address before connect(), with port 0. bind() then takes an ephemeral
port for the socket alone: not one in use towards another destination,
nor one of a connection still closing in TIME_WAIT, which connect()
would reuse. With many connections the range runs out and bind() fails,
result 12, or searches long for a port: 7 ms a call was seen.

Where the system has IP_BIND_ADDRESS_NO_PORT (Linux 4.2), the port is
left to connect() for a socket that is going to connect: chosen for the
pair with the destination.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-25 16:34:25 +03:00
parent c1159251c5
commit bc79fca154

View File

@ -799,6 +799,22 @@ int doconnect(struct clientparam * param){
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
#endif
if(extbindtodevice(param, param->remsock)) return 12;
#ifdef IP_BIND_ADDRESS_NO_PORT
/* A port the kernel chooses is chosen by connect(), for the pair with
the destination: one in use towards another destination, or closing
from an earlier connection, does as well. bind() would take one of
its own, and with many connections find none left, or search long
for it. */
if((param->operation >= 256 || (param->operation & CONNECT) || param->redirected)
# ifdef WITH_UN
&& *SAFAMILY(&param->sinsl) != AF_UNIX
# endif
){
int one = 1;
param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, (char *)&one, sizeof(one));
}
#endif
#ifdef WITH_UN
if(*SAFAMILY(&param->sinsl) != AF_UNIX)
#endif