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

NAT Autodetection #4993

Closed
whyrusleeping opened this issue May 2, 2018 · 24 comments
Closed

NAT Autodetection #4993

whyrusleeping opened this issue May 2, 2018 · 24 comments

Comments

@whyrusleeping
Copy link
Member

I'm thinking about having nodes, on startup, check if they are publicly dialable via some libp2p 'can you dial me?' service, and if they find that they are not dialable, running with DHTclient mode (and maybe some other options set, like only announcing relay addresses for themselves).

If this were deployed widely, it would essentially 'solve' the dht connectivity problem.

cc @vyzo @Stebalien @Kubuxu @mgoelzer

@vyzo
Copy link
Contributor

vyzo commented May 2, 2018

If this were deployed widely, it would essentially 'solve' the dht connectivity problem.

At the expense of network reach unfortunately :(
It also only cures the symptoms, this affects all aspects of ipfs (eg bitswap).

The NAT autodetection concept is very useful regardless - and it would work best with relay infrastructure in place.
So the logic would be, test for NAT, and if you are not NATed then don't announce relay addresses and don't bother establishing permanent connections to any relays.
If on the other hand you discover impenetrable NAT (the expected outcome of the test), then connect to relays and announce relay addresses.

It is arguable whether we want to announce any other addresses by default when NATed, but I think we shouldn't unless the user plans to test and interconnect with other local network nodes; at which point he probably knows what he is doing at a deeper level than most and can configure his node accordingly. Also. mdns discovery should connect nodes in the LAN without the need to announce internal addresses.

@ghost
Copy link

ghost commented May 2, 2018

on startup, check if they are publicly dialable

This state of being dialable can change dramatically within minutes - home routers restart, crash, or forget NAT mappings all the time.

A simpler version of this would be "do I have a publicly routable IP address".

@whyrusleeping
Copy link
Member Author

@lgierth Do you have a simple heuristic for 'publicly routable' ?

@vyzo
Copy link
Contributor

vyzo commented May 2, 2018

I think we can just test dial from a background host (or different process).

@ghost
Copy link

ghost commented May 2, 2018

Do you have a simple heuristic for 'publicly routable' ?

Basically anything that's not included in the list of ranges we block in the server profile :) We'd have to double-check that list against the IANA address range lists, but whether an IPv4/IPv6 address is routable on the internet is generally pretty well defined. (Whether anyone is announcing it is a different question, but I think we can ignore that case.)

On another note, whois lookups for non-public address blocks seem to to return empty, but I've only tested that for 192.168.0.0/16 and 127.0.0.0/8 and the particular whois server my queries ended up at. (It's probably part of some spec.)

@vyzo
Copy link
Contributor

vyzo commented May 2, 2018

@lgierth is right, let's just filter everything that's not IANA routable.

@kevina
Copy link
Contributor

kevina commented May 2, 2018

Unless I am missing something the removal of non-routable addresses will prevent the use of IPFS on an internal network. The easiest way to resolve this is to add a config option for the removal of non-routable addresses.

@Kubuxu
Copy link
Member

Kubuxu commented May 2, 2018

I would be careful with that. I also feel that we are treating symptoms and not the underlying cause. From my experience go-ipfs' NAT traversal has a lot yet to learn.

Using only "I have a socket open on publicly routable IP" for DHT will significantly hurt offline and overlay network scenarios.
It will also cause problems in container/docker environments.

@vyzo
Copy link
Contributor

vyzo commented May 2, 2018

I would be careful with that.

Agreed; there should certainly be options for node operators to configure as they see fit for their environment.

I also feel that we are treating symptoms and not the underlying cause.

We are also looking forward to integrating with the browser world.

From my experience go-ipfs' NAT traversal has a lot yet to learn.

Yes, of course! It's a long term project to achieve reliable NAT penetration at the transport layer.

@ghost
Copy link

ghost commented May 2, 2018

Ah yes, I wouldn't want to generally run in dhtclient mode if we don't have a public IP (nor when behind NAT), for the same reasons as @kevina and @Kubuxu mention - it hurts offline and community networks use cases. I was mainly just thinking about "how do we detect the presence of NAT". haveInternet && !havePublicIP is still an okay heuristic for that.

In local-ish and offline scenarios we want to have all the peer-to-peer firepower we can get. A node can be in the globally-connected and local-ish/offline scenarios at the same time though.

So maybe what we'd want is for some protocols to be aware of certain layers of locality (?). I want to have the full DHT dance with my local peers, but maybe don't want to part in the global DHT because my internet connection is bad.

@whyrusleeping
Copy link
Member Author

So I think what we want here is an option to turn on/off this 'automatic adaptive NAT mode'. Like it or not, the default behavior for the main network should be to run as dhtclient if you have a bad NAT. Users who want can circumvent this by setting the option, but the average user shouldnt have to be aware of this to not make the network worse

@ghost
Copy link

ghost commented May 3, 2018

Like it or not, the default behavior for the main network should be to run as dhtclient if you have a bad NAT

👍

It'd still be great to not make things worse for offline/local use cases though -- requiring flipping an option to make things work locally is meh.

I think this whole situation smells like a leaky abstraction. We treat all peers equally, but they really aren't equal. (In a similar sense as how Coral has latency-bounded rings.)

@Kubuxu
Copy link
Member

Kubuxu commented May 3, 2018

run as dhtclient if you have a bad NAT

This is different than what was being proposed here of going dhtclient if you don't have a public IP.

I think simple test "am I dialable" with bootstrap peer could be the best way forward. I think it could remove about 90-odd% of undialable peers.

@whyrusleeping
Copy link
Member Author

@lgierth

I think this whole situation smells like a leaky abstraction. We treat all peers equally, but they really aren't equal. (In a similar sense as how Coral has latency-bounded rings.)

Hrm... care to elaborate on where the right abstraction might be?

@Kubuxu

This is different than what was being proposed here of going dhtclient if you don't have a public IP.

read my original issue though

@ghost
Copy link

ghost commented May 3, 2018

Maybe the same havePublicIP heuristic can be the boundary. I'm not quite sure where to put this, but protocols on the libp2p Host would be able to see whether a peer is considered "global" or "local-ish", and treat it accordingly. This would potentially also help with preferring local Bitswap peers, choosing local relay nodes over distant ones, etc.

@ghost
Copy link

ghost commented May 3, 2018

Maybe the same havePublicIP heuristic can be the boundary

As in: if we're connected to the peer via their public IP, then they're probably a "global" peer.

@whyrusleeping
Copy link
Member Author

@lgierth I like that, want to open an issue somewhere in libp2p to suggest that?

@ghost
Copy link

ghost commented May 3, 2018

And it'd help with pushing the DHT towards a Coral-like model. But we'd probably want something more flexible/future-proof than a simple global/local binary.

Will file that issue when I'm back in a bit.

@vyzo
Copy link
Contributor

vyzo commented May 3, 2018

run as dhtclient if you have a bad NAT

I fear this would be like throwing out the baby with the bath water, if we blanket do that.
There is strength in numbers in the dht and it really doesn't need that much relay bandwidth.

@whyrusleeping
Copy link
Member Author

@vyzo hrm... youre right. Assuming we get connectivity with relays to be high, then the more the merrier.

@vyzo
Copy link
Contributor

vyzo commented May 8, 2018

Ambient NAT autodiscovery in libp2p/go-libp2p-autonat#1
The service is something the bootstrappers can provide.

@dryajov
Copy link
Member

dryajov commented May 11, 2018

So the logic would be, test for NAT, and if you are not NATed then don't announce relay addresses and don't bother establishing permanent connections to any relays.

Hmm... this might hurt the browsers badly. Relay is not only for NAT, its also to bridge the gap across different transports/runtimes - we need Relay to be able to dial browser nodes or any nodes that run on weird/incompatible transports (bluetooth, etc...)

@vyzo
Copy link
Contributor

vyzo commented Oct 20, 2018

An update:
The autoNAT package has been split into two:

The plan is to run the NAT service in the bootstrappers.
The ambient service uses passive discovery through connection events, all it takes is to open a connection to one of them to have functional NAT autodetection.

@johnnymatthews
Copy link
Contributor

Didn't this issue get closed in the 0.5.0 release?

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

No branches or pull requests

7 participants