DNS Tunnel Client (dnstc)

March 1, 2026 · View on GitHub

A cross-platform CLI tool for managing DNS tunnel connections. Supports multiple transport and backend types with both interactive TUI and CLI interfaces.

Features

  • Transports: Slipstream and DNSTT
  • Backends: SOCKS, SSH (dynamic forwarding), and Shadowsocks (SIP003 plugin)
  • Import: Import tunnel configs from dnstm:// URLs generated by dnstm's tunnel share
  • Gateway proxy: Single SOCKS port routing to the active tunnel, switchable at runtime
  • Daemon: Systemd-managed daemon on Linux (dnstc daemon enable + dnstc daemon start)
  • Interactive TUI: Status viewer with tunnel management and configuration
  • Binary management: Install, update, and self-update via dnstc install and dnstc update
  • Named tunnels: Auto-generated adjective-noun tags (e.g. swift-tunnel)
  • Per-tunnel ports: Each tunnel gets its own local port, auto-assigned if not specified

Installation

go install github.com/net2share/dnstc@latest

Or build from source:

git clone https://github.com/net2share/dnstc.git
cd dnstc
go build -o dnstc .

Transport + Backend Combinations

TransportBackendDescriptionRequired Config
slipstreamshadowsocksSlipstream as Shadowsocks SIP003 plugindomain, ss-server, ss-password
slipstreamsocksSlipstream standalone SOCKS proxydomain
slipstreamsshSSH dynamic forwarding over Slipstreamdomain, ssh-user, ssh-password/key
dnsttsocksDNSTT standalone SOCKS proxydomain, pubkey (64-char hex)
dnsttsshSSH dynamic forwarding over DNSTTdomain, pubkey, ssh-user, ssh-password/key

Note: dnstt + shadowsocks is not a supported combination.

Usage

Interactive TUI

Run without arguments:

dnstc

Interactive menu with tunnel management, configuration, and live service status. The TUI auto-detects when a daemon starts or stops in another terminal.

Daemon Management

The daemon runs via systemd on Linux. First enable the service, then start it:

sudo dnstc daemon enable    # Install and enable systemd service (once)
dnstc daemon start          # Start service and tunnels
dnstc daemon stop           # Stop service (IPC graceful shutdown)
dnstc daemon status         # Show daemon and tunnel status
sudo dnstc daemon disable   # Stop and remove systemd service

Tunnels auto-start when the service starts (including after reboot). Config changes via CLI (tunnel add, tunnel remove, config edit, etc.) are automatically picked up by the running daemon.

Logs are available via journalctl -u dnstc.

CLI Commands

Install & Update

dnstc install             # Download and install required binaries
dnstc update              # Check and apply updates (binaries + self)
dnstc update --check      # Check only, don't apply
dnstc update --self       # Update dnstc only
dnstc update --binaries   # Update binaries only

Tunnel Management

# Import a tunnel from a dnstm:// URL (generated by dnstm tunnel share)
dnstc tunnel import dnstm://...

# Add a tunnel manually
dnstc tunnel add --transport slipstream --backend socks -d tunnel.example.com
dnstc tunnel add --transport dnstt --backend socks -d tunnel.example.com --pubkey <64-char-hex>
dnstc tunnel add --transport slipstream --backend shadowsocks -d tunnel.example.com \
  --ss-server 127.0.0.1:8388 --ss-password secret
dnstc tunnel add --transport slipstream --backend ssh -d tunnel.example.com \
  --ssh-user tunnel --ssh-password secret

# Add with a specific local port (auto-assigned if omitted)
dnstc tunnel add --transport slipstream --backend socks -d tunnel.example.com -p 9050

# List tunnels
dnstc tunnel list

# Show tunnel status
dnstc tunnel status -t <tag>

# Switch active tunnel (gateway routes to this tunnel)
dnstc tunnel activate -t <tag>

# Remove a tunnel
dnstc tunnel remove -t <tag> --force

Configuration

dnstc config show              # Display current config
dnstc config edit              # Open config in $EDITOR
dnstc config gateway-port -p 1080  # Set gateway proxy port

Uninstall

dnstc uninstall --force

Removes config, state, downloaded binaries, and systemd service.

Architecture

┌──────────────────────────┐
│         Gateway          │  Single port (default :1080)
│    SOCKS proxy entry     │  Accepts client connections
└───────────┬──────────────┘
            │ routes to active tunnel

┌──────────────────────────┐
│     Active Tunnel        │  Per-tunnel local port
│   (e.g. :41023)          │  Running transport binary
└───────────┬──────────────┘
            │ DNS queries → configured resolver

       Remote Server
  • The gateway is a TCP relay that listens on a single configurable port and forwards each connection to whichever tunnel is currently active.
  • Switching the active tunnel takes effect on the next connection — no restart needed.
  • Each tunnel runs as a child process (slipstream-client, dnstt-client, or sslocal) on its own local port. SSH backend tunnels additionally run an in-process SSH client with SOCKS5 dynamic forwarding.
  • DNS queries are sent directly to the configured resolver (default 1.1.1.1:53), avoiding any proxy-level reconstruction that could break tunnel protocols.

Configuration

Stored in ~/.config/dnstc/config.json:

{
  "listen": {
    "socks": "127.0.0.1:1080"
  },
  "resolvers": ["1.1.1.1:53"],
  "tunnels": [
    {
      "tag": "swift-tunnel",
      "transport": "slipstream",
      "backend": "shadowsocks",
      "domain": "tunnel.example.com",
      "port": 41023,
      "shadowsocks": {
        "server": "127.0.0.1:8388",
        "password": "your-password",
        "method": "chacha20-ietf-poly1305"
      }
    },
    {
      "tag": "cool-proxy",
      "transport": "dnstt",
      "backend": "socks",
      "domain": "dns.example.com",
      "port": 41024,
      "dnstt": {
        "pubkey": "0123456789abcdef..."
      }
    },
    {
      "tag": "ssh-tunnel",
      "transport": "slipstream",
      "backend": "ssh",
      "domain": "tunnel.example.com",
      "port": 41025,
      "ssh": {
        "user": "tunnel",
        "password": "secret"
      }
    }
  ],
  "route": {
    "active": "swift-tunnel"
  }
}
  • listen.socks — Gateway port. Auto-assigned if the default (1080) is unavailable.
  • resolvers — DNS resolvers used by tunnels (default 1.1.1.1:53). First entry is used.
  • tunnels[].port — Per-tunnel local SOCKS port. Auto-assigned when adding a tunnel.
  • tunnels[].resolver — Per-tunnel DNS resolver override.
  • route.active — Tag of the tunnel the gateway routes to.

File Locations

PurposePath
Configuration~/.config/dnstc/config.json
Versions~/.config/dnstc/versions.json
Process state~/.config/dnstc/state.json
IPC Socket~/.config/dnstc/engine.sock
Binaries~/.local/share/dnstc/bin/
Daemon logsjournalctl -u dnstc

Automatic migration from YAML config (config.yaml) to JSON is performed on first run.

  • dnstm — DNS Tunnel Manager (server-side)
  • go-corelib — Shared Go library