P2P UDP Puncher
Connect two UDP applications behind NAT without the need of additional configurations.
Requirements
- Both parties behind NAT
- No Symmetric NAT
- A server reachable from both clients. This works as TURN server
Features
- Very Light: Single threaded when ran as TURN server and written in Rust with NO HEAP ALLOCATIONS!
- Small Overhead: Most of the packets are 2 bytes each. Keep alive packets are 1 byte.
- Works on Top of Other Programs: You don't need to change the code of other programs to use this program. Just change the destination address in them.
How it works
There are three components in each established connections:
- A client which initiates the connection. Must be behind NAT.
- Server which accepts the connections from clients. Must be behind NAT.
- A TURN server which connects clients with servers. This server must be reachable from all client and servers.
And the flow of a client connecting to a server follows:
- A TURN server is set up.
- Server creates a socket to TURN server. This will create a entry in its NAT. A keep alive packet is sent to TURN in order to keep the entry in NAT.
- A client connects to TURN server and requests the address of the server based on a key. TURN will give the address of the server to the client.
- TURN notifies the server with the address of the client.
- A three step handshake is then initiated:
- Server sends a packet to client. This punches the NAT of the server.
- Client does not receive the first packet of the server unless it is behind a Full-Cone NAT or no NAT at all. Thus, after one second, a packet is sent to server in order to punch the client's NAT.
- The packet from the client is received in server because of the punched NAT. Server finally responds with a last packet and the handshake is done.
- Server and client both proxy the connection of their socket to each other.
- Server then starts another socket and registers it in TURN server in order to accept other clients as well.
Usage
This program uses env_logger to log. You can configure the log level by environment variables like this before running the program: export RUST_LOG="p2p_udp_puncher=trace"
.
You can also run each subcommand without any arguments to get a help message.
TURN
Running the TURN server is easy as hell. You just need to specify the listening address.
./p2p_udp_puncher turn 0.0.0.0:12345
Above command runs a TURN server on 0.0.0.0:12345
.
Server
For running a server you need a key (which clients need to supply as well), the address of TURN server and the address to forward the packets of incoming clients to.
./p2p_udp_puncher server 127.0.0.1:1984 1.1.1.1:12345 test
Above commands runs a server. The packets of clients are forwarded to 127.0.0.1:1984
, TURN server used is located at 1.1.1.1:12345
and the key that clients use in order to connect is test
.
Client
For running a client you need the address of the TURN server, the key which server gave you and a local address to listen for incoming packets in order to forward them to server.
./p2p_udp_puncher client 127.0.0.1:54321 1.1.1.1:12345 test
Above commands runs a server. Incoming packets are expected to be sent to 127.0.0.1:54321
, TURN server used is located at 1.1.1.1:12345
and the key that server gave you is test
.