https://cmptrnb.github.io

DNSTT tunnel over DNS

Here are practical instructions for tunneling your internet traffic as DNS requests and responses on port 53. This sometimes works in tightly restricted network environments. This post expands on the developer's documentation from https://www.bamsoftware.com/software/dnstt.

0. Prerequisites and limitations

Before you begin, you will need:

A discussion on https://github.com/net4people/bbs/issues/586 indicates further limitations in environments that are tightly restricted. To fly under the radar, use your DNSTT tunnel only for text files or small images (no videos or gaming).

1. Create DNS entries

Go into your name registrar's configuration panel.

Create a record for your server's host name (replacing example.com below by your actual domain). The tns is just an example. Since all the tutorials use this example, if you want to disguise your server, you might be better using a different value. Keep it short. Example:

A tns.example.com points to your server's IPv4 address

If you are using IPv6 then also create an AAAA record for your server's host name (replacing example.com by your actual domain):

AAAA tns.example.com points to your server's IPv6 address

Now add an NS record, which defines your server as the nameserver for everything in the t.example.com DNS zone (replacing example.com by your actual domain). The t subdomain is just an example. Since all the tutorials use this example, if you want to disguise your server, you might be better using a different value. Keep it short. Example:

NS t.example.com is managed by tns.example.com

Depending on your registrar and on how much use your domain has previously had, you will need to allow some time for these new entries to propagate.

2. Open firewall on server

Input DNS requests will arrive on port udp/53. To avoid having dnstt-server needing to listen on this privileged port, input on port udp/53 will be redirected to port udp/5300, where dnstt-server will listen.

Open the firewall for IPv4 input (assuming your primary network interface is named eth0):

sudo iptables -I INPUT -p udp --dport 5300 -j ACCEPT

sudo iptables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300

If necessary, open the firewall for IPv6 input (assuming your primary network interface is named eth0):

sudo ip6tables -I INPUT -p udp --dport 5300 -j ACCEPT

sudo ip6tables -t nat -I PREROUTING -i eth0 -p udp --dport 53 -j REDIRECT --to-ports 5300

Persist these rules across reboots. There are several ways to do this. As just one example, if you have already installed iptables-persistent, then reconfigure iptables-persistent like this:

sudo dpkg-reconfigure iptables-persistent

3. Install Go language on server

In a browser on your local workstation, visit https://go.dev/dl to determine the most recent version of the Go language compiler. We will use version 1.26.1 in our examples. You may need to change this version number at the time you run this tutorial.

In your SSH session with your server, change up to your home directory:

cd ~

Download the most recent Go language tarball:

curl -OL https://go.dev/dl/go1.26.1.linux-amd64.tar.gz

Remove any previous installations of the Go language:

sudo rm -rf /usr/local/go

Extract the tarball into /usr/local:

sudo tar -C /usr/local -xzf go1.26.1.linux-amd64.tar.gz

Add /usr/local/go/bin to your PATH environment variable. You can do this by adding the following line to your ~/.profile or /etc/profile (for a system-wide installation):

export PATH=$PATH:/usr/local/go/bin

Save the file.

The easiest way to make this effective immediately is to log off and log on again.

Verify that you've installed Go by opening a command prompt and typing the following command:

go version

You will see a response such as:

go version go1.26.1 linux/amd64

Verify that the command prints the installed version of Go.

4. Build DNSTT on server

In a browser on your local workstation, visit https://www.bamsoftware.com/software/dnstt to determine the most recent version of the DNSTT source code.

Download to your server the most recent source for DNSTT:

sudo apt install -y git

git clone https://www.bamsoftware.com/git/dnstt.git

Change into the source code directory for dnstt-server:

cd dnstt

cd dnstt-server

Build the Go program for dnstt-server:

go build

You will see output that looks something like this:

go: downloading github.com/xtaci/kcp-go/v5 v5.6.8
go: downloading github.com/xtaci/smux v1.5.24
go: downloading github.com/klauspost/reedsolomon v1.12.0
go: downloading github.com/pkg/errors v0.9.1
go: downloading github.com/templexxx/xorsimd v0.4.2
go: downloading github.com/tjfoc/gmsm v1.4.1
go: downloading golang.org/x/crypto v0.21.0
go: downloading golang.org/x/net v0.23.0
go: downloading github.com/flynn/noise v1.0.0
go: downloading github.com/klauspost/cpuid/v2 v2.2.6
go: downloading github.com/templexxx/cpu v0.1.0
go: downloading golang.org/x/sys v0.18.0

After a few minutes, the build completes without errors.

5. Run DNSTT on server

Create a new screen session named dnstt-server:

screen -S dnstt-server

Generate private and public keys for the end-to-end tunnel encryption:

./dnstt-server -gen-key -privkey-file server.key -pubkey-file server.pub

You will see feedback:

privkey written to server.key
pubkey  written to server.pub

If you wish, you can view the contents of server.pub:

cat server.pub

You will see 64 hexadecimal characters, looking something like this:

67a58d7ac70500b99c26669f7c3b56d0986e59f7da3c2b80aa7671ef79dba442

Start the dnstt-server program running, listening on localhost port udp/5300, and forwarding traffic to localhost port tcp/8000. Replace t.example.com by your own domain name and issue the command:

./dnstt-server -udp :5300 -privkey-file server.key t.example.com 127.0.0.1:8000

You will see feedback that looks something like this:

pubkey 67a58d7ac70500b99c26669f7c3b56d0986e59f7da3c2b80aa7671ef79dba442
effective MTU 932

Detach from the screen session by pressing the keys Ctrl+a immediately followed by d.

You will see feedback that looks something like this:

[detached from 2377.dnstt-server]

6. Open SOCKS listener on server

Make sure that password authentication is allowed (PasswordAuthentication yes) in both /etc/ssh/sshd_config and in any configuration files under /etc/ssh/sshd_config.d.

Create a new screen session named ssh:

screen -S ssh

A moment ago, you started the dnstt-server program to forward incoming connections to port tcp/8000.

Now make a localhost SSH connection, using the -D switch (dynamic port forwarding), to open a SOCKS listener on port tcp/8000:

ssh -N -D 127.0.0.1:8000 -o NoHostAuthenticationForLocalhost=yes 127.0.0.1

Enter the password for your user on this server.

Detach from the screen session by pressing the keys Ctrl+a immediately followed by d.

You will see feedback that looks something like this:

[detached from 2389.ssh]

7. Copy public key to client

Now you must copy the public key file server.pub from the server to your client.

There are many ways to do this. One example would be to exit your SSH session:

exit

Then use the scp command on your workstation. For example:

scp youruserid@tns.example.com:dnstt/dnstt-server/server.pub Downloads

Since this is a public key, it does not need to be kept private or copied securely.

Instead of physically transferring the file, you could alternatively paste its contents (64 hexadecimal characters) into an email and recreate the file server.pub on the client end.

8. Download DNSTT client for Windows

Visit https://dnstt.network.

Download the most recent Windows client Windows x64 for Intel/AMD 64-bit processors.

Normally this will be a file named dnstt-client-windows-amd64.exe in your Downloads folder (the same folder as you put the server.pub file).

9. Run DNSTT on Windows client

Visit https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers.

Choose a DNS-over-HTTPS (DoH) resolver. (As explained in the developer's documentation, you could alternatively use a DNS-over-TLS resolver).

Our example here will be https://cloudflare-dns.com/dns-query.

Open a Command Prompt window and navigate to your folder Downloads.

Start dnstt-client-windows-amd64.exe running. It listens on localhost port tcp/7000. Replace t.example.com in the following by your actual subdomain. Also substitute in your choice of DoH resolver:

.\dnstt-client-windows-amd64.exe -doh https://cloudflare-dns.com/dns-query -pubkey-file server.pub t.example.com 127.0.0.1:7000

You will see messages such as:

uTLS fingerprint Chrome 102
effective MTU 135
begin session 13108795

Leave the Command Prompt window open with dnstt-client-windows-amd64.exe running in it.

10. Firefox client

Now you will specify a SOCKS 5 proxy for Firefox on port tcp/7000, which will actually send traffic through the tunnel to the SSH listener on the server.

In Firefox, go to Settings, General, then Network settings (sometimes called Proxy settings).

Select the radio button for Manual proxy configuration.

Specify SOCKS Proxy 127.0.0.1 and Port 7000.

Select SOCKS v5.

Check the box to proxy DNS while using SOCKS5.

Click OK.