libp2p / go-libp2p

libp2p implementation in Go
MIT License
6.02k stars 1.06k forks source link

Handle dial prioritisation for well known prefix IPv4 embedded IPv6 addresses #2349

Closed sukunrt closed 1 year ago

sukunrt commented 1 year ago

When implementing happy eyeballs logic to prefer QUIC IPv6 over QUIC IPv4 addresses, I've observed that a lot of the dial failures to IPv6 addresses are for addresses of this form 64:ff9b::192.0.2.33. These are https://datatracker.ietf.org/doc/html/rfc6052#section-3.1 addresses.

In most cases these nodes also report 192.0.2.33 as their address and the subsequent dial to that address succeeds. Can we just skip the dial to 64:ff9b::192.0.2.33?

If we cannot skip them, we should probably still rank them the same as IPv4 addresses and not prefer them to other IPv4 addresses.

Jorropo commented 1 year ago

It doesn't make sense for peoples to advertise things like 64:ff9b::192.0.2.33, on windows, linux, android, ios and macos (I havn't checked the rest) the os takes care of rewriting 64:ff9b::/96 addresses to IPv4 ones if you are using NAT64, I think what should happen is that when adding addresses to the peerstore if an ip6 component is in the 64:ff9b::/96 range multiaddr should actually store or load it as an ip4 component.

Note: I don't know who advertise this in the first place, might be a bug somewhere (golang encode ipv4 as 16 bytes 64:ff9b::/96). That smell someone doing:

switch len(ipaddr) {
case 4:
  // handle as ipv4
case 16:
  // handle as ipv6
}
sukunrt commented 1 year ago

What's happening here is: A is behind a NAT64 router R. B is a publicly reachable IPv4 only node with IPv4 addr 192.0.2.33

A connects to B via NAT64 router R From _A_s perspective it sees the address of B as 64:ff9b::192.0.2.33. It informs B about this address via identify. B will believe A that its address is this IPv6 address.

Note: B shouldn't believe this, but that's a separate issue in identify. Will open a separate issue for that.

@Jorropo Can you explain how the OS takes care of the rewrite? Let's only consider linux and go-libp2p. My understanding so far is that this requires some DNS64 like system for A to get a IPv4-converted IPv6 address like 64:ff9b::192.0.2.33

I ask because according to my understanding, A does need the address in the converted form to make the call to B. However if the system can be configured to do this automatically it is safe to drop this.

sukunrt commented 1 year ago

@marten-seemann Not taking this up for #2365 . We can handle this case in a follow up PR.

Jorropo commented 1 year ago

Can you explain how the OS takes care of the rewrite? Let's only consider linux and go-libp2p. My understanding so far is that this requires some DNS64 like system for A to get a IPv4-converted IPv6 address like 64:ff9b::192.0.2.33

There is this feature called 464XLAT CLAT (Customer side tranLATor) which instead of using a "lying" DNS layer which give you NAT64 compatible IPv6 addresses, the edge clients just do the rewriting themselves. I was under the impression this was widely available on updated OS, seems like I was wrong, this was mainly deployed for cecular mobile carriers but having it being used in all networks has been catching on and phones also support on wifi not just cellular. It is still based on NAT64 except now instead of relying on DNS64 rewriting, the host OS (computer, phone, ...) just knows it should rewrite it to an 64:ff9b address and just do it. In the wild deploying 464XLAT is as easy as having a valid route for your NAT64 64:ff9b which gets nated and phones and computers will try it if they see they lack ipv4 connectivity.

After digging:

Note there are details about how you combine different XLAT and do ipv6 over ipv4 back to ipv6 but for the final machine it's as easy as just sending ipv6 packets with the 64:ff9b header and terminated with an IPv4 address. *actually there might be some dhcp dark magic in enabling CLAT, I'm not exactly sure, overall last time I tried with an android phone it "just worked" with whatever default dhcp6 config I had setup.

sukunrt commented 1 year ago

NAT64 only nodes who are solely reliant on DNS64 will want to dial these addresses. So I propose:

  1. We filter these addresses when we receive them in identify. #2392
  2. We rank these addresses lower than IPv4 addresses in dial ranking. #2393