Use IP_BIND_ADDRESS_NO_PORT when dialing the ORPort on Linux

David Fifield requested to merge dcf/snowflake:ip_bind_address_no_port into main

All the programs in the snowflake server chain (snowflake-server, haproxy, extor-static-cookie) bind to an explicit source IP address before connecting to the next link in the chain, in order free up more 4-tuples: because if everything were on there would not be enough ephemeral port numbers for as many connections as we have. tor itself also binds to a source address before connecting to middle relays when the OutboundBindAddress option is set, as it is on the snowflake-01 bridge.

There is a socket option IP_BIND_ADDRESS_NO_PORT you can set when doing this bind-before-connect pattern that enables better port number reuse and helps conserve ephemeral ports further. But there is a problem when some programs use IP_BIND_ADDRESS_NO_PORT and some do not: the ones that do will be starved of ephemeral ports. See extensive past analysis:

Because formerly tor did not use IP_BIND_ADDRESS_NO_PORT, we had fallen into an equilibrium of all the snowflake programs similarly not using the socket option. But now that tor always uses IP_BIND_ADDRESS_NO_PORT when OutboundBindAddress is set, we need to flip the other way, and make all the snowflake programs set IP_BIND_ADDRESS_NO_PORT. See #40270 (closed).

The necessary change has already been made in extor-static-cookie. In haproxy, it only requires a configuration change to start using IP_BIND_ADDRESS_NO_PORT. This merge request is to make the necessary change in snowflake-server.

IP_BIND_ADDRESS_NO_PORT is a Linux-only option. The patch defines a dialerControl function that sets IP_BIND_ADDRESS_NO_PORT on Linux and is a no-op on other platforms.

Merge request reports