How NAT traversal and hole-punching work in IPFS

Background

The docs point out that NAT traversal is achieved with STUN. which includes using the SO_REUSEPORT flag and advertising of the ephemeral port (also known as the source port used by a node for dialling out) by external peers.

I’m trying to get a better understanding of NAT Traversal and hole punching and have some questions.

Questions

  1. What is the role of the SO_REUSEPORT in this and how does this actually work in practice given 3 nodes?
    Is the idea that after the first node’s dial out socket is created, another socket with the same port (which it can’t know so they wait until it’s advertised back to them by other nodes) is created to accept new incoming connections?

I added a diagram to try to describe my understanding of this process. Am I understanding this process correctly?

Broader question about the Identify protocol and AutoNAT

Assuming that I start new IPFS node on a server sitting behind NAT (without unup or port forwarding), how does it use the Identity (specs/identify at master · libp2p/specs · GitHub) protocol and AutoNAT ?

I’ve read the specs and still don’t understand how exactly the two protocols/specs are used.

After reading through the specs and the hole punching blog post I think I have a better idea of things.

  • Identity is used to exchange information about peers and is useful for determining a given node’s multiaddress (address and port) – this seems counterintuitive but the idea is that when node A opens a connection to node B the outgoing port from node A (“ephemeral port”) is known to other nodes but not the originating node. So Node B can share the Node A’s multiaddress with Node A which will advertise it if it’s reachable (determined by AutoNAT).
  • AutoNAT is a protocol to determine if a given node is dialable. Essentially a node shares its known multiaddress with other peers and they try to dial using a separate connection, if successful the node is considered dialable/reachable.
  • SO_REUSEPORT allows listening on the port that node A used to connect to node B in the beginning to accept incoming connections

Is that correct?

The blog post point this out

For the sake of simplicity, this post focuses on firewalls and won’t talk about Network Address Translation (NAT)

Is that really the case? If so, how is hole punching different with NAT?

That is not entirely correct. We use the libp2p identify and libp2p AutoNAT protocol to achieve the same as STUN would.

Yes. Though one does not differentiate in dialing and listening socket, but instead talks about it as a single socket.

Correct.

Correct.

Correct.

Note that this is only needed on TCP. On QUIC the same port is used anyways.

Just more complex. E.g. one has to keep ones port mappings on one’s firewall alive. One needs to worry about symetric NATs, …

Let me know in case the above is of some help.

1 Like