-
Notifications
You must be signed in to change notification settings - Fork 953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(quic): improve listener socket selection when dialing #4259
Comments
I would like to work on this but I have a question. If using the same approach as in |
@mxinden Could you please help me with a question? Could we make it as simple as adding a separate field to a |
Thank you @arsenron for the fix. I will keep this issue open given that there is still the more sophisticated solution that go-libp2p follows.
@arsenron let me know in case you want to contribute more to the project. The above more sophisticated solution might be an option. Or any of the other |
Problem
Say the local node listens on
/ip4/0.0.0.0/udp/0/quic-v1
. One would expect a consecutive dial to/ip4/127.0.0.1/udp/42/quic-v1
to use one of the listen addresses as the source address of the dial.That is not the case today. Instead
libp2p-quic
will create a new quinn endpoint and thus a new UDP socket for the outgoing dial.Why?
In TCP we track the specific listen addresses, even if the user calls
listen_on
with an unspecified address (e.g.0.0.0.0
). If the user callslisten_on
with a specific IP address i.e. not a wildcard like0.0.0.0
but e.g.127.0.0.1
we track (here register) the specific address right away.rust-libp2p/transports/tcp/src/lib.rs
Line 394 in f10f1a2
In case where the user calls
listen_on
with an unspecified address (e.g.0.0.0.0
) we depend onif-watch
, more specificallypoll_if_watch
to provide us with the concrete addresses:rust-libp2p/transports/tcp/src/lib.rs
Lines 666 to 682 in f10f1a2
Either way, we end up tracking specific listen addresses with port-reuse enabled and can thus choose the right listener in
local_dial_addr
:rust-libp2p/transports/tcp/src/lib.rs
Lines 122 to 151 in f10f1a2
In
libp2p-quic
we only track the initial address that the user provided on thelisten_on
call.rust-libp2p/transports/quic/src/endpoint.rs
Lines 170 to 178 in f10f1a2
This might be a wildcard address. Later on, when dialing a
127.0.0.1
address, the checklisten_addr.ip().is_loopback() == socket_addr.ip().is_loopback()
discards the listener with the unspecified listen address, thus a new dial-only socket is used, even though one of the existing listener sockets is available.This is e.g. problematic when trying to dial a node on
127.0.0.1
with the expectation that the dial uses one of the listen addresses as a source address.How does go-libp2p solve this:
go-libp2p asks the OS for the correct interface given a destination address. It uses Google's routing package. See https://github.com/libp2p/go-libp2p/blob/260b9695cafdd8e35ec65b30ef153f0c15549c72/p2p/transport/quicreuse/reuse.go#L209 for concrete usage and implementation.
How to move forward?
I am not sure simply removing the
listen_addr.ip().is_loopback() == socket_addr.ip().is_loopback()
check is the way to go. This check is still helpful. E.g. say we have two listeners, one on localhost, one not on localhost. Ideally we would use the former when dialing.We could mirror what
libp2p-tcp
does. That is, track the specified listen addresses reported by if-watch. Later, when dialing, choose the listener with the right address.Ideally I would like to have the operating system choose. It has the most information about all available routes to each interface. In other words ideally we would do what go-libp2p does.
For now, I suggest we go with the
libp2p-tcp
approach. A second iteration would mirror what go-libp2p does.Originally posted by @mxinden in #3454 (comment)
Thank you @kpp for surfacing this bug.
Thank you @marten-seemann for the quick help, pointing me to how go-libp2p solves this issue.
The text was updated successfully, but these errors were encountered: