-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Proposal for NAT UDP hole-punching #433
Comments
It's a good choice for UDP hole-punching. We had done TCP hole-punching experiments and found it's so difficult. |
Inspired by this comment(ipfs/kubo#5511 (comment)), I read a little about ICE(https://tools.ietf.org/html/rfc8445) and found the problem already solved systematically. https://gortc.io/ looks like a promising golang implement. |
I posted the final piece of hole-punching logic at #490 |
Closing since we now have proper hole punching in libp2p, which works on TCP and on QUIC. |
Reason
To increase connectivity between nodes as much as we can.
Relay is good, but is not so "peer-to-peer", and at the cost of community maintained relay servers. Also, as we have tested, many of our customers are behind some kind of NATs. Hopefully hole-punching would solve some other percents of the problem.
Technical details
Hole-punching is better understood at protocol level. To track an NAT mapping, a gateway(or some other device) would record at least 3 addresses(and ports): local internal address, local external address and remote external address. For an outbound packet, the gateway would replace its local internal address with local external address; for a inbound packet, the gateway would replace its local external address with local internal address. From the perspective of a internal node, the connection is between local internal address and remote external address.
If a gateway only do some translations, the problem would be much easier. But a gateway would also apply some restrictions to inbound packets, mainly for security reasons. This wiki lists 4 types of NATs and their restrictions for inbound packets, and theoretically UDP hole-punching could solve 3 types. For TCP packets, I observed additional restrictions, like sequence number check, so UDP is a better choice.
The diagram below is a punching example.
Node1
andNode2
are two nodes behind different NAT gateways, with internal address192.168.0.1:4001
and10.0.0.2:4001
, respectively. A helper node with public IP3.0.0.1
would assist connection establishment, but not relay data for them.For the first step, the public IP node would see
Node1
has external address100.100.0.1:10000
,Node2
has200.200.0.1:20000
, and send this information to one another side. Knowing the other's external address,Node1
would send packets to200.200.0.1:20000
, on receivingNode1
's packet,NAT1
would allow inbound packets from200.200.0.1:20000
(otherwise normal communication is disturbed).Node2
andNAT2
are the same. The first 1 or more packets might be dropped because of timing (inbound packets not already allowed), but eventually a 2-way communication would be established.And for multiple layers of NATs, the situation is similar, only take longer time.
Limitations
Implementation
I noticed inside libp2p ecosystem, we already have port reuse and QUIC transport, both are great technologies. The missing parts include:
I'd like to know if someone is also digging on the problem, or some work is done or on-going? I plan to code for it very soon.
The text was updated successfully, but these errors were encountered: