Crates.io | tunneler |
lib.rs | tunneler |
version | 0.4.1 |
source | src |
created_at | 2021-08-06 10:03:30.271382 |
updated_at | 2021-10-15 06:41:36.702727 |
description | Tunnel TCP or UDP traffic over TCP, (mutual) TLS or DNS (authoritative server or direct connection) |
homepage | |
repository | https://github.com/dlemel8/tunneler |
max_upload_size | |
id | 432397 |
size | 453,346 |
This repo contains client and server that allow you to tunnel TCP and UDP traffic over other network protocols.
Currently, supported tunnels are:
Main tool is written in Rust and end-to-end tests are written in Python.
docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest
cargo --version || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
There is also a docker file if you prefer to build a local docker image
docker run -e LOCAL_PORT=45301 \
-e REMOTE_PORT=5201 \
-e REMOTE_ADDRESS=localhost \
-e TUNNELED_TYPE=udp \
--rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp
./target/release/client \
--tunneled-type tcp \
--remote-address 1.1.1.1 \
--remote-port 53 \
--log-level debug \
dns \
--read-timeout-in-milliseconds 100 \
--idle-client-timeout-in-milliseconds 30000
Run docker image or compiled binary with --help
for more information
cargo test --all-targets
python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v
This repo contains a few server deployment examples using Docker Compose:
You can run each example locally or deploy it using Terraform and Ansible. See more information here.
Each executable contains 2 components communicating via a channel of client streams (a tuple of bytes reader and writer):
TCP based traffic is trivially converted to stream. UDP based traffic conversion depends on the tunnel protocol.
UDP based traffic also need a way to identify existing clients to continue their sessions. The solution is an in-memory Clients Cache that maps an identifier of the client to its stream.
In order to convert UDP traffic to a stream, a 2 bytes size header (in big endian) precedes each packet payload.
UDP Listener uses incoming packet peer address as a key to its Clients Cache.
We have a few challenges here:
To solve those challenges, each client session starts with generating a random Client ID (4 alphanumeric chars). Client reads data to tunnel and run it via a pipeline of encoders:
Encoded data is then used as the name of a TXT DNS query.
If you own an authoritative DNS server, client can send the request to a recursive DNS resolver. Resolver will get your IP from your domain name registrar and forward the request to your IP. Another option (faster but more obvious to any traffic analyzer) is configuring client to send the request directly to your IP (on port UDP/53 or any other port server is listening to).
Server decodes data (ignoring any non client traffic) and uses Client ID as a key to its Clients Cache.
In order to handle large server responses and empty TCP ACKs, read timeout is used in both client and server. If read timeout is expired, empty message will be sent. Both client and server use idle timeout to stop forwarding and cleanup local resources.
To implement mutual authentication, we use a private Certificate Authority:
Both client and server are configured to use their key and certificate in TLS handshake. The CA certificate is used as root certificate.
Since Server Name Indication extension is used, client is requesting a specific server name and server is serving its certificate only if that name was requested. The server name must also be part of the certificate, for example as a Subject Alternative Name.