Yes, DNS tunneling with OzymanDNS is slow (as described in my previous posting). Let’s try to speed it up a little bit.
If you have a closer look at the code, you’ll notice that the upstream is implemented by sending the data base32 encoded in long A DNS requests in chunks of 110 bytes (domain names may be up to 256 characters long, with dots at least every 64 characters). Due to base32 encoding and the required dots we can’t gain much here. Thankfully, in most cases we don’t need much upstream anyway.
What we are really interested in is increasing the downstream. In the original implementation, downstream packets are sent in TXT RDATA fields as answers to requests from the client. Each reply packet contains 2 TXT fields of (at most) 110 bytes base64 encoded data.
When reading the DNS RFC (RFC 1035), I noticed that it specifies a certain NULL RDATA format. It’s marked as experimental, but can – according to specification – hold 64 Kb worth of binary data. Unfortunately this is only a theoretical value. In practice, some DNS servers support longer packets, other not so long. I did some tests and a BIND server was able to send packets to up to 3 Kb, while the DNS server in my WLAN router only served 512 byte. A windows DNS server gave me up to 1,2 kB.
Even with WLAN DNS servers, we can increase to data transmitted per packet to up to approximately 350 bytes per packet, as it can hold binary information (as opposed to base64 encoded data) and don’t need to split the information into different TXT fields.
To get the most out of the DNS server at hands, I played a little bit around with OzymanDNS and added two functions to the server: testlargepacket and setpacketsize. testlargepacket takes a packet size as argument and sends out a reply with the according length. If the client receives a reply to a certain packet size, it uses the setpacketsize command to tell the server what packet size to use in the future. Net::DNS::RR has a small bug that removes any dots from the end of the field. This cost me a couple of hours to track, but in the end it worked fine in practice doubled the speed of my Socks-Proxy-over-SSH-over-DNS-VPN.
I’ll clean the code up a little bit and ask Dan Kaminsky if I may publish the updated code here. Perhaps I also find the time to have a look into WKS RDATA fields. They seem to be able to carry an arbitrary length of data, and are perhaps better implemented than NULL records. On the other hand, not even Net::DNS::RR has WKS records implemented.
If you have any ideas what we could further do to optimize the speed, please drop me a comment.
[Update: I've uploaded the source in the mean time and wrote about it here]
Picture of Formula 1 car by Gregor Rohrig
Tags: DNS, DNS Tunneling, IP over DNS, Optimize, Ozyman, Performance, Security, Tunnel, Tunneling, VPN
March 3, 2008 at 7:46 pm |
i have googling to find out how to speed up the ozyman, and i found this interesting topic, please email me the clean up code of ozyman. thank you
March 6, 2008 at 12:45 pm |
Can you email me the new script
March 8, 2008 at 8:11 pm |
[...] Tunneling – Updated Source Alright, so as I’ve been asked for the source of my changed Ozyman DNS source, I have now uploaded it. However WordPress does not allow me to upload .zip files, so I changed the [...]
July 3, 2008 at 1:45 am |
I like your way of thinking. Where are the dots removed? Can you send me the code for it please. I’d like to have a play around with the code and track down any bottlenecks.
July 3, 2008 at 1:47 am |
PS: I’ve already downloaded the clean code, it’s just where the RR dots are removed….in RR:opt?
July 8, 2008 at 12:06 pm |
ok, not sure if you are still interested , you stated
So the program spends almost 95% of it’s system time inside IO::Select::can_read (called by Net::DNS).
did you notice that if you had the file libresolv it would be faster according to the developer of Net::DNS?
quote “Net::DNS does not depend on any C libraries. However, if possible Net::DNS tries to link to the libresolv library. This provides a notable speed increase.”
I am going to solve this, but do not want to release it to the general public at this stage
don’t add this comment to your site
coder44
July 13, 2008 at 10:16 pm |
you need to edit the source of RR.pm. The function is called new_from_hash(). The regex removes the dot, which it should not. Just edit the regex.
July 27, 2008 at 3:41 pm |
In RR.pm, find new_from_hash(), around line 464, change it from:
( $self->{lc $key} = $val ) =~ s/\.+$// if defined $val;
to
( $self->{lc $key} = $val ) = $val;
You might also comment out the Devel::DProf; line in the beginning of nomde_fork.pl if you get an error message about perl -d. Rename nomde_fork.pl to nomde.pl, backup the original.
A 100 KB test I did on a name server supporting 405 bytes downstream and 110 upstream showed these speeds:
* Download: 11 kbits/s
* Upload: 4 kbits/s