Skip to the content.

dns-tunnel

A SIP003 Shadowsocks plugin written in Rust that obfuscates traffic as standards-conformant DNS-over-QUIC (RFC 9250).

Shadowsocks TCP  ─►  sslocal  ─►  dns-tunnel (client)
                                       │
                                       ▼  QUIC, ALPN "doq"
                                  DNS messages
                                  (EDNS0-padded queries,
                                   HTTPS-record responses)
                                       │
                                       ▼
                            dns-tunnel (server)  ─►  ssserver  ─►  TCP target

Why

Most plugins that wrap shadowsocks in a “looks like X” envelope settle for X-ish: a TLS record here, an HTTP request there. DPI vendors classify on details — header field counts, message-ID values, record types in the answer section, presence of EDNS padding. dns-tunnel targets those details:

Detail What dns-tunnel does
DoQ stream framing one query + one response per QUIC bidi stream
DNS message ID 0 on every message (RFC 9250 §4.2.1)
Query QNAME <short-random>.<popular-cdn-tld>
Query QTYPE rotated among A, AAAA, HTTPS
Where payload hides (queries) EDNS0 OPT, OPTION-CODE 12 (PADDING, RFC 7830)
Where payload hides (responses) HTTPS resource record’s RDATA
Multi-message streams none — strict one-shot per stream

Quick start

cargo build --release

Server-side shadowsocks-rust config:

{
  "server": "0.0.0.0",
  "server_port": 853,
  "password": "secret",
  "method": "chacha20-ietf-poly1305",
  "plugin": "/usr/local/bin/dns-tunnel",
  "plugin_opts": "mode=server;sni=your.server.example;cert=/etc/ssl/fullchain.pem;key=/etc/ssl/privkey.pem"
}

Client-side:

{
  "server": "your.server.example",
  "server_port": 853,
  "local_address": "127.0.0.1",
  "local_port": 1080,
  "password": "secret",
  "method": "chacha20-ietf-poly1305",
  "plugin": "/usr/local/bin/dns-tunnel",
  "plugin_opts": "mode=client;sni=your.server.example"
}

Docs

Source

madeye/dns-tunnel on GitHub · MIT licensed.