DNS Tunneling
A few years ago there was a proof-of-concept that it was possible to send and receive data packets over the Domain Name System (DNS). It utilizes the hostname for upstream data and the TXT-field for downstream data, and s smart queuing system to split and order the packets. The speed is not good, but it opens an alternate way to connect to the Internet.
The method mentioned here is based on perl and works on Linux, Mac OS X, and Windows via Cygwin.
Technical Overview
The DNS system is hierarchy structured, beginning with the 13 root servers for top-level-domains (TLD) i.e., com, net, org, down to the domain name, i.e. example.org, and then sub-domains, i.e. group.example.org. Each sub-domain can be delegated to another domain server at a different location.
Each domain is configured in a zone file, each zone file contains different types of records, i.e. A for address record, CNAME for alias to an A record, MX for the mail exchange server, NS for the zone's name server, TXT for plain text description. The interesting records here is the NS and TXT records. Entries ending with a dot means end of domain, while no dot means add $ORIGIN to entry.
example.org. IN NS ns1.nameserver.com. example.org. IN TXT "Example.org sample domain"
The length of the entire hostname is limited to 255 octets/bytes [1]. And the TXT record has the same 255 bytes limit. It's now somewhat apparent that it should be possible to transmit and receive data using the hostname and TXT records respectively, if a system or encoder/decoder is placed in each end to create a connection.
In addition, there is an experimental NULL record that allows 65535 octets (actual implementation is limited to 300 - 1200 octets) [2]. See alternate ozymandns package for modified version based on NULL records and finding optimal packet size.
Idea
Now, this DNS tunnel example is written in perl and includes a client and server. The fake DNS server runs on port 53 and will answer queries coming from the client (or anyone querying the hostname). A hostname has to be delegated to point to the server, e.g. the hostname of the server has to be the NS (record) for dtun.example.org. Thus any sub-domain query, e.g server.dtun.example.org, is forwarding (delegated) to the fake DNS server.
An upstream A record for a packet looks like this:
d6hsa2ar4hyinvdhgdv7nucwf5zkp3motntq3fmvn52kphqfn72kzyg24zui.6tuapj3frb6coby nav6zdvosvogvmvxouxfzebun3ga.17000-0.id-59037.up.sshdns.dns-inet.x-pec.com. 0 IN A 64.0.0.0
And a downstream NULL record looks like this:
8I8U4DiYSnstLODBg9GLva9NGo2TyE373SUAAS3snFWWf0jovz81s+foQO9KzBjxi8LslpxQiIYJ tafNvOw5TKtunYFqPoo0SIoytoFiJ4nzK4G4DTm0KMBpB2snO/+cVCIVH9VGVCHQGl7mufDxTVk7 RaGRBByTF+ia8tw0VOFLHp8SfnXeLdI5HZtqLF5kT3RzmWKa1w7awg+XI+xaGhQrA/aCtJa1p1B9 lL9TM+NErSWeQPYVyKwB3uUT1fkcVI9E/WqnY1iFd2epHtyWrRD83nRvEsCOl9sMZamCw+UQQBTE tcDKj8yXn3SAZBVdBCrEqowu9oVnVQ==
Delegating Zone
Since a fake name server server will handle all the sub-domain query traffic, the main name server for the domain (e.g. ns1.nameserver.com for example.org) has to have a NS record for the sub-domain (e.g. dtun.example.org) pointing to the address of the fake server.
A normal configuration would be this:
dtun.example.org. IN NS ns-dtun.example.org. ns-dtun.example.org IN A 89.193.59.119
The first line specifies the new name server for dtun.example.org (and everything under that sub-domain). The second line simply defines the static IP address of the fake server.
An alternate configuration if the hostname for the fake server is already known:
dtun.example.org. IN NS box.dyndns.org.
The last example works fine for dynamic IP services like DynDNS and No-IP.
Perl
A quick tutorial on Perl and CPAN (Comprehensive Perl Archive Network):
- Enter the CPAN shell:
- perl -MCPAN -e shell
- To re-configure the environment:
- o conf init
- Upgrade CPAN:
- perl -MCPAN -e 'install Bundle::CPAN'
- Install modules:
- perl -MCPAN -e 'install MIME::Base32'
The server and client depends on a couple of modules, to install them:
perl -MCPAN -e 'install MIME::Base32' perl -MCPAN -e 'install Net::DNS' perl -MCPAN -e 'install Digest::CRC' # For optimized version
Fake Name Server
The fake server will answer queries and transmit data back. It should on a computer will full unlimited Internet access, meaning no outbound firewall blocking and minimum 512 kilobits/s upstream and downstream. The server is tested and confirmed working on Linux and Mac OS X.
Linux
The nomde.pl server requires root-privileges to bind to port 53. The port also has be reachable from the Internet. Make sure UDP and TCP port 53 is allowed inbound in the firewall and/or NAT configuration.
- Download the ozymandns_src_0.2.tgz (local mirror) package from doxpara.com
- Create a new directory and extract the archive
- Start the server:
- sudo ./nomde.pl -i 0.0.0.0 dtun.example.org
- The server will create a new socket and listen on port 53
Make sure to replace the hostname with your own. If any perl errors is reported, make sure the modules listed is installed, Mime/Base32.pm converts to module Mime::Base32.
Mac OS X
Mac OS X already has a perl installed by default but lacks the build and compile tools. The Xcode development enviroment includes all the necessary utilities and is freely available on Apple's website (registration required).
Make sure to re-run the cpan configuration after Xcode is installed. The path to make and other tools will then be correctly set up.
- Download Xcode and install the package
- Open Terminal and enter the perl CPAN shell, perl -MCPAN -e shell
- Configure CPAN automatically or re-configure by o conf init, press Enter on all the questions to fix the paths to e.g. make
- Install the perl modules mentioned above, perl -MCPAN -e 'install Mime::Base32 and perl -MCPAN -e 'install Net::DNS
- Download the ozymandns_src_0.2.tgz (local mirror) package from doxpara.com
- Create a new directory and extract the archive
- Start the server:
- sudo ./nomde.pl -i 0.0.0.0 dtun.example.org
Of course change the hostname and install any missing modules, Mime/Base32.pm converts to module Mime::Base32.
Verify
An easy way to figure out if the server is ready is to manually query it. On Linux dig is handy and on Windows the nslookup utility does the job.
- Linux / Mac OS X:
- dig dtun.example.org
- Alternatively specify name server to use dig @192.168.1.1 dtun.example.org
The result should be:
;; QUESTION SECTION: ;dtun.example.org. IN A ;; ANSWER SECTION: dtun.example.org. 3600 IN A 0.0.0.0 ;; AUTHORITY SECTION: dtun.example.org. 10798 IN NS box.dyndns.org. ;; ADDITIONAL SECTION: box.dyndns.org. 42 IN A 89.193.59.119
- Windows:
- Open run => cmd.exe, and execute nslookup -q=ns dtun.example.org
- Alternatively nslookup -q=ns dtun.example.org 192.168.1.1
The result should look like:
Server: UnKnown Address: 192.168.1.1 Non-authoritative answer: dtun.example.org nameserver = box.dyndns.org