MatrixAI / Polykey

Polykey Core Library
https://polykey.com
GNU General Public License v3.0
29 stars 4 forks source link

Verify IPv6 NAT Punchthrough Behaviour #669

Open CMCDragonkai opened 7 months ago

CMCDragonkai commented 7 months ago

While I was on a separate network that was capable of IPv6 I noticed a few differences in behaviour for NAT punchthrough.

Basically if the home network (or office network) is one of the latest ones, the general configuration is to give every device that's connected to the router a unique IPv6 address, while the router itself is given an IPv4 address.

For IPv6 capable systems, IPv6 is preferred. So when you do look up https://whatismyipaddress.com/ the IPv6 address appears first.

Furthermore using ip addr you can see the local IPv4 address as well as a scope global temporary dynamic address - looks like this:

    inet6 2603:8080:26f0:c2e0:c424:cb1f:5f7c:a4d6/64 scope global temporary dynamic 
       valid_lft 86368sec preferred_lft 82168sec

From the perspective of NAT punch-through, for IPv4, it's the problem of finding the right port between peers, which is why you need the help of a signaller.

But for IPv6, finding the right port is only 1 part of the problem, you also have to find the right IPv6 address.

So for 2 peers on IPv4, neither of which knows their public IPv4 address (because that's assigned to the router), and neither knows each others port, the signaller helps coordinate both pieces of information.

For 2 peers on IPv6, both peers knows their public IPv6 address, as such addresses are specific to the device. But neither know each other's public IPv6 address AND neither knows each other's port. The signaller again has to do the same thing.

So in effect, in both cases, the end result should be the same. One should prefer to contact the IPv6 address if it is possible on the machine.

However as we talked about before, connecting between v6 and v4 cannot be done directly, which requires a dual stack relay.

Tests for this need to be part of the Polykey-Simulation.

Now what is interesting here is that if you have IPv6, if you can configure the router, you can ask the router to basically fully DMZ the IPv6 address for a given device. That exposes the device to the internet fully allowing home networks to easily run hosted services now without the need to have to coordinate a limited number of ports (or to distinguish ports between different instances of the same service). Each host just has their own unique IPv6 address that is globally/publically routable. This is pretty cool, and enables alot more peer to peer things. In fact because of this, it is possible for IPv6-hosts to just use the same port and use signaller to find the right public IPv6s...

Tasks

CMCDragonkai commented 7 months ago

Some additional notes here, in order to realise this, it turns out using nc and curl and socat might report "permission denied" if the NAT is blocking unknown IPv6 packets. Simply shutting off the v6 NAT solves this or allowing the device through.

image

nc -6 -l 55555
nc -6 2403:5807:597a:0:a897:baad:b81:61d1 -v 55555
socat tcp6-listen:55555,reuseaddr -
socat STDIO 'TCP6:[2603:8080:26f0:c2e0:c424:cb1f:5f7c:a4d6]:55555'
CMCDragonkai commented 7 months ago

Use this to get it on the CLI:

curl -6 https://ifconfig.co
tegefaulkes commented 7 months ago

I just want to note that IPv6 connections would be formed using the direct method. That is to say we don't need a signaller, we only need to find the address:port for that node.

So when we connect to a node and request it's closest nodes to the target, if it has a record of our target in it's node graph we can just use that. The node we're requesting from doesn't need an active connection to the target. We don't need a 3rd party node to coordinate the connection.

That said, the information would still be somewhat ephemeral. While the address information will be un-changed for much longer than the natted scenario. The port is only static for the duration the socket is bound and the address if dynamic IPv6 will change over time too.

CMCDragonkai commented 7 months ago

Don't you still need the signaller to still have the information of the public IPv6 addresses?

tegefaulkes commented 7 months ago

We don't need a signaller since we're not dealing with a NAT in the usual sense. A signaller can tell us about a node's IPv6 information. But we could find this information from any node's node graph.

I guess it's semantics? This is if a signaller explicitly refers to a node that has an active connection to the target. With IPv6 we should be able to form a direct connection without any in-between so long as we learn the host:port from somewhere. We can learn it from any node that has connected to the target before.

CMCDragonkai commented 7 months ago

To me a signaller is any node that has both side's information.

CMCDragonkai commented 7 months ago

We still need to simulate cases of information change frequency. How ephemeral IP addresses and ports are impacts the robustness of the network.

tegefaulkes commented 7 months ago

Totally, I'd love to get around to a whole bunch of simulation and testing of the network.

I think for IPv6, it's safe to assume the port will be unchanged for the duration the node is up. So it's likely to change between node restarts if not specified. And the address being dynamic will be unchanged for the duration that the machine is running. Actually, let me check that...

It seems that IPv6 have a lifetime associated with it.

2: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether |REDACTED| brd ff:ff:ff:ff:ff:ff
    inet |REDACTED|/24 brd |REDACTED| scope global dynamic noprefixroute wlp0s20f3
       valid_lft 862503sec preferred_lft 862503sec
    inet6 |REDACTED|/64 scope global temporary dynamic 
       valid_lft 6765sec preferred_lft 3164sec
    inet6 |REDACTED|/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 6765sec preferred_lft 3164sec
    inet6 |REDACTED|/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

We can see here that the dynamic addresses have a timeout of about 1 hour left. While the link local address is permanent. It will probably depend on the device but I think we can assume IPv6 information to be correct for about 1 hour.

It should be noted that the address itself is more ephemeral than the ipv4 addresses and could potentially roll over when in use. I wonder how that affects active quic connections when they roll over? Would we want to implement the path support in quic? Would it even matter since Polykey is meant to be tolerant to connection drops?