nimbus-eth2 icon indicating copy to clipboard operation
nimbus-eth2 copied to clipboard

Improve external ip / nat configuration

Open kdeme opened this issue 5 years ago • 7 comments

Current default is to use upnp / nat pmp to discover external ip and to configure the port forwarding ( =mapping). This is not useful for systems not behind NAT as thus not a great default for those configurations. Additionally, we might no want to recommend upnp first option either for those behind NAT?

Discoveryv5 can help figuring out the external IP when https://github.com/status-im/nim-eth/issues/207 gets implemented. When the user is behind NAT, it would still require for manual port mapping or to be used in combination with upnp/natpmp

Regarding the --nat option:

  • The --nat:extip: option can still be used for those that want to hard set the ip and not rely on peers.
  • The none option could be implemented such that the routable interface is discovered and its ip address is used (if not local address).
  • any would be a mix, and could thus e.g. rely on upnp + discv5 or finding of routable interface + discv5.

Default could still be any option.

Defaults:

  • In case of a system with a public IP (upnp could be run, but wouldn't do any thing.) It would be enough to have the IP discovered through discovery v5. Additionally, the routable interface could be searched for and its IP could be used, but this would not be necessary. No port forwarding is needed.
  • In case of a system behind a NAT:
    • Either we don't default to use upnp: Discovery finds public IP. Users need to be instructed to configure their router manual for the port forwarding
    • Or we do allow for upnp to be used default: upnp finds public IP & does port mapping. Discovery checks ip and keeps it updated?

Other clients:

  • prysm: flag for setting external ip https://docs.prylabs.network/docs/prysm-usage/p2p-host-ip#setting-the---p2p-host-ip-flag + instructions to do the port forwarding.
  • lh: port forwarding default through upnp: https://lighthouse-book.sigmaprime.io/advanced_networking.html#nat-traversal-port-forwarding , also discovery v5 based external ip configuration.

kdeme avatar Dec 07 '20 20:12 kdeme

To make clear, in the current code with current options, the only real viable options are:

Systems not behind NAT:

  • use --nat:extip:x.x.x.x

Systems behind NAT:

  • use --nat:extip:x.x.x.x and make manually configure port forwarding in the router/gateway.
  • use the default (or set upnp or pmp) and make sure this functionality is enabled in your router. Port forwarding and external ip discovery will happen automated (but more issues might occur because of this).

Thinking about it further, the any option (defaulted), should basically allow for any of the two cases to work automatically. However, not guaranteed of course and issues may arise. It would be more important to have proper INF and WRN logs for this and educate the users into these message (in the book). This would mean still using the upnp/pmp solution default & also discv5 solution. Basically what LH is doing. (And perhaps we can also implement the none solution from above as backup).

kdeme avatar Dec 08 '20 12:12 kdeme

Thinking about it further, the any option (defaulted), should basically allow for any of the two cases to work automatically. However, not guaranteed of course and issues may arise. It would be more important to have proper INF and WRN logs for this and educate the users into these message (in the book). This would mean still using the upnp/pmp solution default & also discv5 solution. Basically what LH is doing.

As discussed offline, I think this is the cleanest approach.

unixpi avatar Dec 08 '20 12:12 unixpi

I think before starting NAT mechanism we should check our interfaces and routing table using chronos utilities. This will allow us to detect situation when we already have public IP address and we do not need to start NAT mechanism.

https://github.com/status-im/nim-chronos/blob/master/tests/testnet.nim#L477-L482

Using getBestRoute with some globally available IP address will reveal you interface's address which will be used to connect to this IP address. If this IP address is globally routable you can use it as "extip".

The only problem is that currently chronos is missing primitive to check if specific IP is actually global routable IP address.

cheatfate avatar Jan 13 '21 14:01 cheatfate

Using getBestRoute with some globally available IP address will reveal you interface's address which will be used to connect to this IP address. If this IP address is globally routable you can use it as "extip".

Great, this is what I meant with:

* the routable interface could be searched for and its IP could be used, but this would not be necessary.

I wasn't aware that there was a getBestRoute call available in chronos already. It does seems to require sending an actual message, is that correct? Is there a version that just checks routable interface?

kdeme avatar Jan 13 '21 15:01 kdeme

@kdeme this call do not send any messages, it just query OS for the BEST route. Because there could be many routable interfaces actually...

cheatfate avatar Jan 13 '21 15:01 cheatfate

The bulk of this feature is being implemented here: https://github.com/status-im/nim-eth/pull/323

The current (new) logic is as follows:

  • any:
    1. If a specific (not 0.0.0.0) listener address (bindIP) is given, and this IP is public, use this IP in the ENR (advertised IP). (not sure if we should still help the user here and check if this is also best route IP, or allow for more exotic uses).
    2. Else, check for best route IP and check if this IP is public. If so, use this IP in the ENR (advertised IP).
    3. Else, try UPnP and NAT-PMP to discover IP and do port mapping on gateway.
    4. If 1, 2 and 3 fails, no IP is set and warning is given.
  • upnp: Try UPnP to discover IP and do port mapping. If it fails, no IP is set, warning is given.
  • pmp: Try NAT-PMP to discover IP and do port mapping. If it fails, no IP is set, warning is given.
  • none:
    1. If a specific (not 0.0.0.0) listener address (bindIP) is given, and this IP is public, use this IP in the ENR (advertised IP). (not sure if we should still help the user here and check if this is also best route IP, or allow for more exotic uses). Else warn that --none option should not be used.
    2. Else, check for best route IP and check if this IP is public. If so, use this IP in the ENR (advertised IP). Else warn that --none option should not be used.
  • extip:<IP address>: Use this IP in ENR. Nothing else is done. This will allow for private IP usage also. (We use this in testing)

Additionally, external IP discovery should be added in discv5 protocol (and allowed to be disabled). This will help with dynamic IP that get changed and also in the case that external IP can not be found correctly (e.g. Container / VM usages or cases where the best route IP findings would go wrong?).

Now, some questions:

  1. The current --nat:... options stem from geth. Are these clear enough for the user? I think they are not very self explanatory and it might be rather difficult to understand what to use here. On the other hand, the default is any and that should be fine for the typical user. But we could decide to change to more individual based options however too, e.g. with the same default results (and keep the current options also available for a certain period for backwards compatibility)
  2. Currently port mapping is always 1:1. Should we also support a different port mapping on host device <-> external ports. (Perhaps this can be useful for certain Docker/VM setups? LH supports this from what I can see in the options)

Some different use cases:

  • User running nimbus on device behind gateway (NAT): Will need to "discover" external IP and setup port forwarding
  • User running nimbus on server with public IP (for example cloud offerings): public IP to be used.
  • User running nimbus on container on server with public IP: Will need to "discover" external IP, port mapping would normally be done at setup and can be 1:1 but also can be different ports
  • User running nimbus on container on device behind gateway (NAT): Will need to "discover" external IP and setup port forwarding.
  • ...

I'm leaving out IPv6 cases for now.

kdeme avatar Jan 19 '21 09:01 kdeme

From my experience PMP works better than UPNP because PMP can give you other external port in case the requested one is already taken. But seems nimbus is trying UPNP first and errors out without fallback to PMP.

chfast avatar Oct 27 '23 07:10 chfast