-
Notifications
You must be signed in to change notification settings - Fork 281
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
relay/dcutr/quic: Alternate host sending garbage UDP packet #487
Comments
I'm not sure I understand how this is supposed to work. |
A and B send their packets at the same time. On failure B retries the DCUtR flow.
https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol
Say that B is behind a symmetric NAT and A isn't. A sends a client hello to B which is dropped at B's NAT given that A does not know B's NATed port. B's random bytes make it through A's NAT through the hole punched by A's client hello. A discards B's random bytes. End result is no connection. Say that B is still behind a symmetric NAT and A isn't, BUT B sends a client hello to A and A sends random bytes to B. B's client hello will make it through A's NAT through the hole punched by A's random bytes. A's random bytes are dropped at B's NAT given that A does not know B's NATed port. The latter doesn't matter. A received B's client hello and responds with a server hello. End result is an established connection. By alternating on retry who sends the random bytes, we would succeed on the second try. Does the above make sense @marten-seemann? |
That makes sense, thank you for the clarification! Is the proposal to reduce the number retries to 2 (given that @dennis-tra's measurements show that there's no point in trying more than once), and alternate the roles after the first attempt? |
I am not yet sure what the best strategy would be. Alternating across (re-) tries was the first that came to my mind. Unfortunately, having both endpoints send client hellos from the start, might result in two connections. If that wouldn't be the case, this would be my favorite strategy, given that it is the fastest.
In my eyes, that is an orthogonal change. |
Typo? A is not? |
Thanks for the catch @MarcoPolo. Fixed. |
As you said Marten, the measurement results suggest that if it doesn't work with the first attempt it likely won't work with any subsequent one. So, I think the optimizations here would be to either
What Max suggests here is Switching roles of client/server makes sense to me for the reasons that Max explained. However, I have something to consider: If B is behind a symmetric NAT I'd assume that B won't be able to determine its |
My initial measurements had suggested that some conns do go through in the second retry. A more conservative approach is to do 2 retries, and then try switching the hello to punch through cone-symmetric scenarios, with 1 retry. |
@vyzo This is the data that we are referring to: https://www.notion.so/pl-strflt/NAT-Hole-punching-Success-Rate-2022-09-29-Data-Analysis-8e72705ca3cc49ab983bc5e8792e3e98#c76c6d5e25844bff8c7508b67f236827 This suggests that if we were not successful with the first attempt, there's only a ~3% chance that it'll work with a subsequent attempt. |
3% is not negligible, please be more conservative in your assessments! |
3% is indeed not negligible. My assumption is that the proposal we are discussing here wouldn't have a negative effect on the 3% for whom it worked with the second attempt but just increase the chances for the ones that weren't lucky with any subsequent attempt. Curious about what the others think. |
I think that’s correct. We also have some logic there to determine the NAT type there, maybe there’s some way to make use of that information?
We need to be careful how we do this in a backwards-compatible way. Legacy nodes will still want to punch multiple times without switching roles. Maybe that’s fine, but maybe we can find some clever way around that. |
This doesn't work. For A to holepunch through its firewall it needs to send a packet to B's symmetric NATed address. This is not what happens. A sends a packet to a port on B which is not the port that B sends packets out of. Consider the case: B tells A its port is Y but the port it'll actually send packets out of is X. A: P -> Y This packet from B: X->P can only work if A's firewall allows all incoming packets from B's IP address irrespective of the port. This firewall behaviour is probably in the minority because AutoNAT heavily relies on this behaviour and the metrics on bootstrappers do show them replying to a lot of nodes as private. |
I think there is a way to make this work in case the firewall on the asymmetric(nice) side is permissive. Let's assume the previous case: A: P -> Y If B sends a non quic packet, A can read this packet and get B's outgoing port Y. Now A can dial B at port Y. Having said that, I don't know what this means |
Today during direct connection upgrade on QUIC, A sends a client hello, B sends random bytes. The client hello makes it through B's firewall and/or NAT through the hole punched by the random bytes sent by B. B's consecutive server hello makes it through A's firewall and/or NAT through the hole punched by A's client hello.
https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol
Now assume that B is behind a symmetric NAT but A is not. A's client hello will not make it through B's NAT, given that it (most likely) does not have the same destination port as the translated source port of B's random bytes.
If we would alternate the roles on retries in DCUtR, e.g. have B be the one to send random bytes in round 1 and A be the one to send random bytes in round 2, the above scenario would succeed on the second try, given that B is not behind a symmetric NAT.
Note that we could as well have both A and B send client hellos in the first round. The downside is, that contrary with TCP and simultaneous open, we might end up with two QUIC connections. One from A to B and one from B to A.
//CC @elenaf9 and @dennis-tra as discussed today.
The text was updated successfully, but these errors were encountered: