Add IPv6 pinhole support using UPnP / NAT-PMP #17012

issue Sjors openend this issue on October 1, 2019
  1. Sjors commented at 5:00 pm on October 1, 2019: member

    Our current UPnP support works for IPv4 by requesting a port forward. It doesn’t work with IPv6 when the user is behind a firewall (which was the default for my modem at least).

    More recent versions of libupnp support requesting a IPv6 pinhole.

    I haven’t checked if the same could be done with NAT-PMP (#11902). That may be preferable to updating libupnp.

    UPnP is baked into the GUI release binaries, though it’s turned off by default in the settings dialog.

  2. Sjors added the label Feature on Oct 1, 2019
  3. fanquake added the label P2P on Oct 1, 2019
  4. Sjors commented at 1:00 pm on September 6, 2022: member
    Meanwhile NAT-PMP support is there, but it has no IPv6 pinhole support.
  5. laanwj assigned laanwj on Apr 11, 2024
  6. laanwj commented at 1:41 pm on April 25, 2024: member

    Indeed, UPnP has an explicit command AddPinhole (https://upnp.org/specs/gw/UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf) that’s seperate from Add(Any)PortMapping.

    The PCP (succssor to NAT-PMP) RFC (https://datatracker.ietf.org/doc/html/rfc6887) doesn’t say anything about pinholes (although they do mention “Simple firewall control” but it’s unclear to me how that maps to opcodes). Though i would guess the MAP opcode allows that, and more, it just leaves it up to the router how the external to internal mapping should be. Ideally.

    It’s kind of annoying if the client has to aware of the network state, ideally it doesn’t really care how the port gets there, as long as it gets there.

  7. laanwj commented at 1:45 pm on April 25, 2024: member

    FWIW the version of libUPnP in depends (2.2.2) does have the Pinhole commands:

    0upnpcommands.h:                         int * inboundPinholeAllowed);
    1upnpcommands.h:UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
    2upnpcommands.h:UPNP_AddPinhole(const char * controlURL, const char * servicetype,
    3upnpcommands.h:UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
    4upnpcommands.h:UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
    5upnpcommands.h:UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
    6upnpcommands.h:UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
    
  8. laanwj commented at 5:08 pm on April 25, 2024: member

    Manually creating an IPv6 pinhole seems to work here:

     0$ export ROUTER_IPV6_ADDR=...
     1$ export MY_IPV6_ADDR=...
     2$ upnpc -6 -u 'http://[${ROUTER_IPV6_ADDR}]:5000/rootDesc.xml' -A  "" 0 $MY_IPV6_ADDR 1234 tcp 30
     3upnpc : miniupnpc library test client, version 2.2.4.
     4 (c) 2005-2022 Thomas Bernard.
     5Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
     6for more information.
     7Found valid IGD : http://[...]:5000/ctl/IPConn
     8Local LAN ip address : ...
     9AddPinhole: ([]:0 -> [...]:1234) / Pinhole ID = 13
    10$ nc -6l 1234
    

    (but only when connecting to it using IPv6 with the correct globally routable address, when connecting to the IPv4 UPnP address, or a link-scoped IPv6 address, it gives failed with code 606 (Action not authorized). Seems like this problem: https://github.com/miniupnp/miniupnp/issues/600#issuecomment-1133602620)

    Then connecting to it from another host, and sending some text, appears to work:

    0$ nc $MY_IPV6_ADDR 1234
    1.......
    

    I’ll try to integrate it into bitcoin. If i can find the right incantation.

  9. laanwj commented at 10:21 am on April 28, 2024: member

    The UPnP side of this is progressing, though i’ve ran into a possible bug/limitaton in miniupnp: https://github.com/miniupnp/miniupnp/issues/731#issuecomment-2081257515

    Meanwhile NAT-PMP support is there, but it has no IPv6 pinhole support.

    i looked into this too, we’ll actually have to implement PCP support ourselves to do this. The good part is that it’s just a matter of sending one fixed-size binary UDP packet to the default gateway and parsing the result. Not worth taking on a dependency for. (see https://github.com/moonlight-stream/GS-IPv6-Forwarder/blob/master/GSv6Fwd/pcp.cpp for an example implementation of IPv6 pinholing) Can’t begin to describe how much simpler than UPnP this is. No XML, no discovery, no HTTP. However, router support is probably less, so we still might want to support both.

  10. Sjors commented at 8:36 am on April 29, 2024: member

    The good part is that it’s just a matter of sending one fixed-size binary UDP packet to the default gateway and parsing the result.

    Nice!

  11. laanwj commented at 9:05 am on April 29, 2024: member

    Nice!

    If you’d like to test, i have a branch here: https://github.com/laanwj/bitcoin/tree/2024-04-pcp-pinhole-test

    It is a PoC that adds a ipv6-pinhole-test program that (on Linux only for now):

    • Enumerates local publicly routable IPv6 addresses
    • Gets the default gateway to get the PCP endpoint
    • Requests pinholes for 100 seconds to port 1234 on all addreses, and prints the result

    i’ve tried it on two routers (Turris Omnia and Fritz!Box) and there it worked.

  12. ffrediani commented at 4:23 pm on September 26, 2024: none

    Great to see this was catch up.

    IPv6 is present on majority of big and medium size Broadband Providers, with some countries having over 50% of IPv6 connectivity and this can contribute significantly to network performance and robustness allowing more nodes to contribute back by accepting incoming connections from other nodes. Bitnodes.org reports over 7400 nodes with IPv6 connectivity and this can help to enhance that greatly.

    Most users that run home nodes don’t have more advanced technical knowledge to allow this incoming IPv6 connection and some routers may not even have this very clear in their web interface, but by having PCP support to understand these requests solves this.

    As CGNAT usages grows overtime due to IPv4 exhaustion this enables nodes to communicate on native IPv6 rather than other slower and more problematic networks as Tor and I2P and enhance nodes connectivity and performance restoring end to end connectivity.

    Eager to see this committed and users being able to take advantage.

  13. achow101 closed this on Sep 30, 2024

  14. AngusP referenced this in commit c33eb2360e on Sep 30, 2024
  15. ffrediani commented at 9:22 pm on September 30, 2024: none

    @laanwj @Sjors I know how UPnP has been controversy over the years (and now PCP maybe inherit this), but what is your view at some point to start having this option enabled by default ? This could enhance significantly the P2P data exchange between peers and reduce a lot the need to use slower and more problematic networks as Tor and I2P, mainly because many residential Broadband connections have working IPv6 and routers that understand it so it will enables a fair amount of nodes to contribute back to the network on a native and much faster protocol.

    Some fair concerns that may come to mind are: 1) data usage/control where there are tighter limits, 2) people who may wish to only use privacy protocols as Tor and I2P (remove onlynet for ipv4 and ipv6 and use the proxy option). I personally don’t consider a security concern as it only allows traffic on a specific port and towards the node. An observation also is that the usage of this option in a Datacenter/VPS environment may not take any effect as these firewalls/routers normally will not have UPnP/PCP running.

    Guess if this may be considered to be enabled by default people can be enough clarified about these points in order they can have the freedom to adjust as they like.

  16. Sjors commented at 7:20 am on October 1, 2024: member
    @ffrediani it might make sense to turn this on by default in the future. But first we should wait a while to make sure there’s no bugs in #30043. Afaik there’s currently no shortage of listening nodes, but that could change over time.
  17. laanwj commented at 10:32 am on October 1, 2024: member

    An observation also is that the usage of this option in a Datacenter/VPS environment may not take any effect as these firewalls/routers normally will not have UPnP/PCP running.

    Yes, you’re right. As mentioned in #30043 the goal of enabling it by default would be to have more connectable nodes outside datacenters. In datacenters, this will do nothing, their default gateways ignore PCP/NATPMP packets.

    That said there is no hurry. Better to let this sit for.a release so that remaining issues can be hammered out.

    i’m already happy that this is merged now that would have been a much harder sell enabling it by default at the same time.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-26 15:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me