Idea: let dnstt-server respond to any DNS zone

dnstt-server requires you to specify a single DNS zone for the tunnel (e.g. t.example.com). Only queries that are under the zone are processed for tunnel data; all others are discarded. Let’s discuss the possibility of letting dnstt-server process queries under any zone. That would make it possible to set up “aliases” for a single dnstt-server instance, under different DNS names. Such aliases could be set up by anyone, not only by the person who runs the dnstt-server.

I was thinking about this during the Kazakhstan shutdown. It was discovered that dnstt in plaintext UDP port 53 mode could get through the shutdown. The problem is that plaintext UDP port 53 mode is not covert. A censor can inspect the contents of DNS queries, and block the ones that are for a subdomain of a known dnstt server.

For example, I could run an instance of dnstt-server and set up DNS records pointing to it:

  • A tns.tunnel.example points to 203.0.113.2
  • NS t.tunnel.example is managed by tns.tunnel.example

If I posted publicly, “there is a dnstt-server running at t.tunnel.example,” any censor could read the post and add t.tunnel.example to its blocking rules. But if dnstt-server were modified to respond to queries for any domain, then anyone could set up their own DNS records, under a domain they control, pointing to the same IP addresses:

  • A tns.rhinoceros.example points to 203.0.113.2
  • NS t.rhinoceros.example is managed by tns.rhinoceros.example

They could then privately use dnstt-client with the DNS zone t.rhinoceros.example, a DNS name that the censor does not know about. If an alias gets discovered and blocked, you can make a new one, without needing to relocate the dnstt-server.

For this idea to work, you need to be using a recursive resolver located outside the censor’s area of control—otherwise the censor can just block the dnstt-server’s IP address. In the case of the Kazakhstan shutdown, 8.8.8.8 would have worked.

The reason the idea might work at all is that DNS queries do not contain the IP address of the eventual authoritative resolver, only its DNS name. A censor could block this scheme by working through the name abstraction, looking up NS records for DNS queries it observes, then matching them against a database of known DNS tunnel servers. In the example above, having seen a query for xxx.t.rhinoceros.example, a censor could look up the NS for rhinoceros.example, then ask that NS for the NS of t.rhinoceros.example, then resolve tns.rhinoceros.example to find the IP address 203.0.113.2. The censor could then match the IP address against a database of known tunnel proxies. These dynamic lookups are probably awkward to do at line rate for every query, but they could be made more practical by testing domains in batches, or probabilistically.

A tunnel that uses plaintext DNS, even with a DNS zone that is unknown to the censor, is still probably identifiable anyway, because of the distinctive kinds of DNS messages it uses.

I normally don’t like this kind of circumvention design, where success depends on the censor’s being ignorant. But in an extreme case like an Internet shutdown, where it’s difficult to get any kind of access, I think it’s justified to try things even if they are theoretically unsound.

User interface

Supposing we do permit dnstt-server to respond to queries for any domain, what should the user interface look like? Currently, the DNS zone is part of the command-line interface:

dnstt-client -udp HOST:PORT -pubkey-file FILENAME DOMAIN LOCALADDR:LOCALPORT

One way would be to make the DOMAIN argument optional. If dnstt-server gets only 1 non-option argument, it will not restrict the domain of incoming queries:

dnstt-client -udp HOST:PORT -pubkey-file FILENAME LOCALADDR:LOCALPORT

Another way would be to make the DOMAIN argument a wildcard. You could pass * to permit any domain.

dnstt-client -udp HOST:PORT -pubkey-file FILENAME * LOCALADDR:LOCALPORT

Or, we could add a new command line option that means to ignore the DOMAIN argument.

Wildcard option looks the best to me. Or move away from positional arguments to named ones.

From my tests many public DNS already implement rate limiting. Some ISPs also have rate limits in their DNS.
This can be the most effective measure to stop using bandwidth consuming content although unable to stop low bandwidth usage cases - messengers, email

Also it is important to not open DNS amplification to net scanners

Its likely if DNS tunnels become widespread they will block them. The fastest way to achieve this goal is to offer simple solution for everyone