Skip to content
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

Do DNS queries for both A and AAAA simultaneously #302

Merged
merged 2 commits into from
Jul 10, 2024
Merged

Conversation

r-vdp
Copy link
Contributor

@r-vdp r-vdp commented Jun 27, 2024

We implement a basic version of RFC8305 (happy eyeballs) to establish the connection afterwards.

With this change, wstunnel connects over IPv6 if possible with a very fast (250ms) fallback to IPv4, as recommended by the RFC. This is what most browsers etc also do.

src/tcp.rs Outdated Show resolved Hide resolved
@erebe
Copy link
Owner

erebe commented Jun 28, 2024

Haha you discovered the Ipv4 and after Ipv6 🦝
Thanks for the PR, I am going to look at it this weekend when I get some time.

Feel free to re-ping next week, if I haven't done so

Copy link
Owner

@erebe erebe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, you only miss to do it for src/udp.rs also. There is a method that does dns resolution there

src/tcp.rs Outdated Show resolved Hide resolved
src/tcp.rs Outdated Show resolved Hide resolved
src/tcp.rs Outdated Show resolved Hide resolved
@r-vdp
Copy link
Contributor Author

r-vdp commented Jun 30, 2024

Looks good, you only miss to do it for src/udp.rs also. There is a method that does dns resolution there

Ok, this one is a bit more complicated though because there is no handshake with UDP, so when we created the socket, we do not know yet whether the connection is actually working, we'd need to send some data across and see if we get a reply to know if it worked.
I think we should probably do this on another level, with some retry logic when udp connections time out, so that we retry the connection in that case and if we got several addresses back from DNS, we try each of them, with a similar algorithm as we do for TCP.

What do you think?

@erebe
Copy link
Owner

erebe commented Jul 1, 2024

Alright, let's keep it simple for now.
If you can at least sort the sock addr in order to try ipv6 first, if any, to keep the same behavior as tcp regarding which come first.

@r-vdp
Copy link
Contributor Author

r-vdp commented Jul 6, 2024

Alright, let's keep it simple for now. If you can at least sort the sock addr in order to try ipv6 first, if any, to keep the same behavior as tcp regarding which come first.

The thing is, if I read the code correctly, we actually don't ever use the other UDP addresses. AFAIU, the UDP connect will always succeed since for UDP there is no handshake and so there is no way to check at the time that we do connect, that the other side is actually reachable. So the first attempt to do connect will simply set the address on the socket, and then we exit the loop and discard all other addresses.

So with this in mind, the sorting of addresses for UDP, really means which single address we will connect to, and if we choose ipv6, then we will cause issues on ipv4-only networks.

I think we have two options:

  1. Just pick the first ipv4 address, to maximise compatibility. This is basically what happens currently as well.
  2. Improve the implementation so that we can actually detect that we are not reading any replies from a UDP socket for a certain time, and in that case reconnect the socket to another address. This means that we retain all the addresses returned by DNS (and maybe redo the query after a certain time?), and that we need some logic to decide when to switch to another address.

@r-vdp
Copy link
Contributor Author

r-vdp commented Jul 6, 2024

The more I think about this, the more I think that there's actually no way to do this correctly from wstunnel's perspective. There is no requirement for a UDP remote to even ever answer, it's perfectly legal to have packages be forwarded to a UDP socket and to receive the response elsewhere on another socket, I think DHCPv4 for instance works this way, or to never even expect a response.

So I think that only the actual application that does the UDP requests can actually implement the logic to deal with multiple IP addresses, and ideally the application would be making UDP requests using IP addresses, and not using domain names.

Or am I missing something here?

In that case, the best we can probably do, is either select a random address in case a domain name was passed that resolves to multiple IP addresses, or select a random IPv4 address in an attempt to be as compatible as possible (for now, until IPv6-only networks become more common).

@erebe
Copy link
Owner

erebe commented Jul 8, 2024

You are right regarding UDP no even needing a response. It is perfectly legit to only send datagram without ever waiting for a response.

Regarding IPv4 only network, I think if you are in this case, and you try to connect to an IPv6 address it is going to return an error during the connect/bind of the socket https://github.com/erebe/wstunnel/blob/main/src/udp.rs#L356
Meaning, it would be fine to prefer IPv6 over IPv4.

I am going to check and let you know.

@r-vdp
Copy link
Contributor Author

r-vdp commented Jul 8, 2024

I'm not sure that the OS actually checks this during connect/bind. I think that for UDP, connect/bind just sets the address but it has no way of knowing if the address is actually reachable or not.

I may be wrong though :)

@erebe
Copy link
Owner

erebe commented Jul 9, 2024

hi,

I just tried and if you have no IPv6 interface at all the bind is failing with

called `Result::unwrap()` on an `Err` value: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }

and if you have no route for IPv6, the connect is failing with

called `Result::unwrap()` on an `Err` value: Os { code: 101, kind: NetworkUnreachable, message: "Network is unreachable" }

So let's make IPv6 the default there too, if people complain, I don't mind reverting this part later on.

@r-vdp
Copy link
Contributor Author

r-vdp commented Jul 9, 2024

Ok cool, I'll do it like that then, probably one of the next days.

We implement a basic version of RFC8305 (happy eyeballs) to establish
the connection afterwards.
@r-vdp
Copy link
Contributor Author

r-vdp commented Jul 10, 2024

Updated to also sort the addresses for UDP.

I wasn't entirely sure in which module to put the function now, we can also introduce a new module for socket-related stuff if you think that that would be better.

@erebe
Copy link
Owner

erebe commented Jul 10, 2024

Should be ok I think, thank you for the PR ;} 🎆

I am going to add a flag I think to allow to revert to IPv4 first if needed.
Will see when I have time to make a new release.

P.s: Will most likely check your other PR friday monday.

@erebe erebe merged commit 90d378e into erebe:main Jul 10, 2024
@tastypear
Copy link

hi,

I just tried and if you have no IPv6 interface at all the bind is failing with

called `Result::unwrap()` on an `Err` value: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }

and if you have no route for IPv6, the connect is failing with

called `Result::unwrap()` on an `Err` value: Os { code: 101, kind: NetworkUnreachable, message: "Network is unreachable" }

So let's make IPv6 the default there too, if people complain, I don't mind reverting this part later on.

So I meet this problem in the VPS(server) and Google Colab(client).

How to make it work again?😥

@erebe
Copy link
Owner

erebe commented Jul 20, 2024

Can you share the logs of the client/server ?

can you try release https://github.com/erebe/wstunnel/releases/tag/v9.7.4 ?

@tastypear
Copy link

OMG, it works🥳

I was just about to paste the log and then I got the update.

Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants