{"id":23914412,"url":"https://github.com/dlemel8/tunneler","last_synced_at":"2025-04-11T15:50:32.553Z","repository":{"id":46751737,"uuid":"354471468","full_name":"dlemel8/tunneler","owner":"dlemel8","description":"Tunnel TCP or UDP traffic over TCP, (mutual) TLS or DNS (authoritative server or direct connection), implemented in Rust","archived":false,"fork":false,"pushed_at":"2021-11-09T19:29:48.000Z","size":879,"stargazers_count":74,"open_issues_count":1,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-25T11:52:25.916Z","etag":null,"topics":["ansible","asynchronous","dns","dns-tunneling","docker","docker-compose","networking","proxy","rust","tcp","tcp-tunnel","terraform","tls","tls-tunnel","tunnel","udp"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/tunneler","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dlemel8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-04T06:19:52.000Z","updated_at":"2025-03-21T06:52:11.000Z","dependencies_parsed_at":"2022-09-26T20:41:16.448Z","dependency_job_id":null,"html_url":"https://github.com/dlemel8/tunneler","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlemel8%2Ftunneler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlemel8%2Ftunneler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlemel8%2Ftunneler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dlemel8%2Ftunneler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dlemel8","download_url":"https://codeload.github.com/dlemel8/tunneler/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248434461,"owners_count":21102843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","asynchronous","dns","dns-tunneling","docker","docker-compose","networking","proxy","rust","tcp","tcp-tunnel","terraform","tls","tls-tunnel","tunnel","udp"],"created_at":"2025-01-05T10:13:42.128Z","updated_at":"2025-04-11T15:50:32.527Z","avatar_url":"https://github.com/dlemel8.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tunneler\nThis repo contains client and server that allow you to tunnel TCP and UDP traffic over other network protocols.\n\nCurrently, supported tunnels are:\n* DNS (authoritative server or direct connection)\n* TLS (mutual authentication)\n* TCP\n\nMain tool is written in Rust and end-to-end tests are written in Python.\n\n## Installation\n### Option 1: client and server docker images\n```sh\ndocker pull ghcr.io/dlemel8/tunneler-server:latest\ndocker pull ghcr.io/dlemel8/tunneler-client:latest\n```\n### Option 2: compile from source code\n```sh\ncargo --version || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\ncargo build --release\n```\nThere is also a [docker file](Dockerfile) if you prefer to build a local docker image\n\n## Usage\n### Option 1: client and server docker images\n```sh\ndocker run -e LOCAL_PORT=45301 \\\n           -e REMOTE_PORT=5201 \\\n           -e REMOTE_ADDRESS=localhost \\\n           -e TUNNELED_TYPE=udp \\\n           --rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp\n```\n### Option 2: locally compiled binary\n```sh\n./target/release/client \\\n  --tunneled-type tcp \\\n  --remote-address 1.1.1.1 \\\n  --remote-port 53 \\\n  --log-level debug \\\n  dns \\\n  --read-timeout-in-milliseconds 100 \\\n  --idle-client-timeout-in-milliseconds 30000\n```\nRun docker image or compiled binary with `--help` for more information\n\n## Testing\n### Run Unit Tests\n```sh\ncargo test --all-targets\n```\n### Run End-to-End Tests\n```sh\npython3 -m pip install -r e2e_tests/requirements.txt\nPYTHONPATH=. python3 -m pytest -v\n```\n\n## Examples\nThis repo contains a few server deployment examples using Docker Compose:\n* Speed Test - iperf3 server exposed via all supported tunnels, allow you to compare tunnels speed.\n* Authoritative DNS - Redis server exposed via DNS tunnel on port UDP/53. Since tunnel does not verify clients, Redis\n  authentication is needed.\n* Pipeline - Redis server exposed via TLS tunnel that itself exposed via DNS tunnel. Since tunnel does verify clients, \n  Redis authentication is not used.\n\nYou can run each example locally or deploy it using Terraform and Ansible. See more information [here](examples/README.md).\n\n## Architecture\n![Architecture](architecture.jpg?raw=true \"Architecture\")\nEach executable contains 2 components communicating via a channel of client streams (a tuple of bytes reader and writer):\n* Client Listener binds a socket and convert incoming and outgoing traffic to a new stream.\n* Client Tunneler translate stream reader and writer to the tunnel protocol.\n* Server Untunneler binds a socket according to tunnel protocol and translate tunneled traffic back to original stream.\n* Server Forwarder converts stream writer and reader back to traffic. \n\nTCP based traffic is trivially converted to stream. UDP based traffic conversion depends on the tunnel protocol. \n\nUDP based traffic also need a way to identify existing clients to continue their sessions. The solution is an in-memory \nClients Cache that maps an identifier of the client to its stream.\n\n## Protocols\n### Tunneled UDP\nIn order to convert UDP traffic to a stream, a 2 bytes size header (in big endian) precedes each packet payload.\n\nUDP Listener uses incoming packet peer address as a key to its Clients Cache. \n\n### DNS tunneling\nWe have a few challenges here:\n* DNS payload must be alphanumeric.\n* Every message requires a response before we can send next message.\n* Each DNS query uses randomized source port and transaction ID, so we can't use them as Client Cache key.\n\nTo solve those challenges, each client session starts with generating a random Client ID (4 alphanumeric chars). Client \nreads data to tunnel and run it via a pipeline of encoders: \n* Data is encoded in hex. \n* Client ID is appended.\n* Client suffix is appended. In case the server is running on your authoritative DNS server, suffix is \".\\\u003cyour domain\u003e\".\n\nEncoded data is then used as the name of a TXT DNS query.\n\nIf you own an authoritative DNS server, client can send the request to a recursive DNS resolver. Resolver will get your \nIP from your domain name registrar and forward the request to your IP. Another option (faster but more obvious to any \ntraffic analyzer) is configuring client to send the request directly to your IP (on port UDP/53 or any other port server \nis listening to).\n\nServer decodes data (ignoring any non client traffic) and uses Client ID as a key to its Clients Cache.\n\nIn order to handle large server responses and empty TCP ACKs, read timeout is used in both client and server. If read \ntimeout is expired, empty message will be sent. Both client and server use idle timeout to stop forwarding and cleanup \nlocal resources.\n\n### TLS tunneling\nTo implement mutual authentication, we use a private Certificate Authority:\n* A self-signed CA certificate is generated from a private key.\n* Server private key is randomly generated and its public part is used in a certificate signed by the CA certificate.\n* Client private key is randomly generated and its public part is used in a certificate signed by the CA certificate.\n\nBoth client and server are configured to use their key and certificate in TLS handshake. The CA certificate is used as \nroot certificate.\n\nSince Server Name Indication extension is used, client is requesting a specific server name and server is serving its \ncertificate only if that name was requested. The server name must also be part of the certificate, for example as a \nSubject Alternative Name.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdlemel8%2Ftunneler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdlemel8%2Ftunneler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdlemel8%2Ftunneler/lists"}