<div dir="ltr"><div>Hi again</div><div><br></div><div>I took another look at this problem, and now I'm even more convinced that what we really need is IP_BIND_ADDRESS_NO_PORT. Here's why.<br></div><div><br></div><div></div><div>If torrc OutboundBindAddress is configured, tor calls bind(2) on every outgoing connection:<br></div><div><a href="https://gitlab.torproject.org/tpo/core/tor/-/blob/tor-0.4.7.12/src/core/mainloop/connection.c#L2245">https://gitlab.torproject.org/tpo/core/tor/-/blob/tor-0.4.7.12/src/core/mainloop/connection.c#L2245</a></div><div>with sockaddr_in.sin_port set to 0 on #L2438.</div><div><br></div><div>The kernel doesn't know that we'll not be using this socket for listen(2), so the kernel attempts to find an unused local two-tuple (according to [1]. Actually a three-tuple: <protocol, source ip, source port>):</div><div><br></div><div>The bind syscall is handled by inet_bind:<br></div><div><a href="https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/af_inet.c#L438">https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/af_inet.c#L438</a></div><div>which calls __inet_bind that in turn calls sk->sk_prot->get_port on #L531 (notice the if on #L529).</div><div><br></div><div>get_port is implemented by inet_csk_get_port in inet_connection_sock.c:</div><div><a href="https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/inet_connection_sock.c#L362">https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/inet_connection_sock.c#L362</a></div><div>On #L375, we call inet_csk_find_open_port (defined on #L190) to find a free port.<br></div><div><br></div><div>inet_csk_find_open_port gets the local port range on #L206 (i.e net.ipv4.ip_local_port_range), selects a random starting point (L#222), and loops through all the ports until it finds one that is free (#L230). For every port candidate, if it is already in use (#L240) it calls inet_csk_bind_conflict (#L241), which is defined on #L133. As far as I understand, it is inet_csk_bind_conflict's job is to determine if it is safe to bind to the port anyway (ex, the existing connection could be in TCP_TIME_WAIT and SO_REUSEPORT set on the socket). This is where your server spend so much time. Increasing net.ipv4.ip_local_port_range doesn't solve the problem, but makes it more likely to find a port that is free.<br></div><div><br></div><div>Lets trace back to the "if" in __inet_bind on #L529:</div><div><a href="https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/af_inet.c#L529">https://elixir.bootlin.com/linux/v5.15.56/source/net/ipv4/af_inet.c#L529</a></div><div>Since we call bind with sockaddr_in.sin_port set to 0, snum is 0, and we can avoid the whole call chain by setting inet->bind_address_no_port to 1. I.e this patch:</div><div><a href="https://gitlab.torproject.org/tpo/core/tor/-/merge_requests/579/diffs?commit_id=b65ffa6f06b2d7bc313e0780f3d76a8acb499ac9#a65580094313324792dd24fed1904263b271abd5_2227_2230">https://gitlab.torproject.org/tpo/core/tor/-/merge_requests/579/diffs?commit_id=b65ffa6f06b2d7bc313e0780f3d76a8acb499ac9#a65580094313324792dd24fed1904263b271abd5_2227_2230</a></div><div>That should allow the kernel to use already in use src ports as long as the TCP <span class="gmail-ILfuVd" lang="en"><span class="gmail-hgKElc">4-tuple is unique.<br></span></span></div><div><br></div><div>Please include it in the next tor release! :)<br></div><div><br></div><div>[1]: <a href="https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/">https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/</a></div><div><br></div><div>- Anders<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Dec 9, 2022 at 10:47 AM Alexander Færøy <<a href="mailto:ahf@torproject.org">ahf@torproject.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 2022/12/01 20:35, Christopher Sheats wrote:<br>
> Does anyone have experience troubleshooting and/or fixing this problem?<br>
<br>
Like I wrote in [1], I think it would be interesting to hear if the<br>
patch from pseudonymisaTor in ticket #26646[2] would be of any help in<br>
the given situation. The patch allows an exit operator to specify a<br>
range of IP addresses for binding purposes for outbound connections. I<br>
would think this could split the load wasted on trying to resolve port<br>
conflicts in the kernel amongst the set of IP's you have available for<br>
outbound connections.<br>
<br>
All the best,<br>
Alex.<br>
<br>
[1]: <a href="https://mastodon.social/@ahf/109382411984106226" rel="noreferrer" target="_blank">https://mastodon.social/@ahf/109382411984106226</a><br>
[2]: <a href="https://gitlab.torproject.org/tpo/core/tor/-/issues/26646#note_2795959" rel="noreferrer" target="_blank">https://gitlab.torproject.org/tpo/core/tor/-/issues/26646#note_2795959</a><br>
<br>
-- <br>
Alexander Færøy<br>
_______________________________________________<br>
tor-relays mailing list<br>
<a href="mailto:tor-relays@lists.torproject.org" target="_blank">tor-relays@lists.torproject.org</a><br>
<a href="https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays" rel="noreferrer" target="_blank">https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays</a><br>
</blockquote></div>