Test Ride
To get a feel for sods, its simple to try out:
git clone git://github.com/msantos/sods.git cd sods/sods ./configure make cd ../sdt ./configure make
Depending on your OS, you might need to adjust the Makefiles.
To test sods, you'll need to have an SSH server available somewhere and root privs on your test host. Start up the socket server:
$ sudo ./sods -d /tmp -L localhost:22 -vvv a.example.com
In another window, open an SSH session:
$ ssh -o ProxyCommand="./sdt -r 127.0.0.1 sshdns.a.example.com" 127.0.0.100
Real World SoDS
To use sods, you'll need a few things:
- A publicly addressable IP
- Something on which to run sods. The server doesn't need to be dedicated or high powered.
- A registered domain name
- A DNS server to host your domain
Well, that may seem to be waaaayyy too much bother, but it might not be as much work as it seems.
Publicly Available IP Address
You need an IP address that is reachable from the Internet or control of a device that can forward packets to your sods server.
The IP addresses the ISP assigns you tend to fall into 3 groups:
- the IP address is static and never (or rarely) changes
- the IP address changes infrequently, but the reverse lookup for the address is static
- the IP address and, consequently, the reverse address, changes frequently
You can work with any of these.
The IP address must be able to receive UDP packets on port 53 and send packets from port 53. If your ISP blocks port 53 (DNS), then you'll have to look around for another ISP, use a hosted service or maybe piggyback off of a friend.
A SoDS Server
You'll need sods to be running any time you might need it. SoDS doesn't require much in the way of resources, so I suggest using a low powered server that you can leave running all the time. The SoDS server might be the same device that you use for your gateway.
I use a Linksys WRT54gl as my home router and sods server. But any small, lower power device will do: I've also used a Linksys NSLU2, and, more recently, a Sheeva Plug.
A Registered Domain Name
If you're even thinking about setting this up, you probably already own a domain or two.
Another DNS Server
Finally, you will need another DNS server to delegate your domain name. This could be a DNS server you run on another IP address, a service provided by your registrar or one of the many free DNS services on the internet (there are a bunch, any of them should work, google for them).
Assuming your domain name is example.com with an IP address of 10.10.10.10, here is what you would have to set up.
- If you have a static IP address (or one that doesn't change too frequently to be inconvenient), delegate a name server for a subdomain (in this example, "a"):
example.com. IN A 10.10.10.10 a IN NS example.com.
- Some ISP's will change your IP, but maintain a consistent reverse DNS lookup for your IP address (something like a DHCP name). You can use this by setting a CNAME.
For example, if your IP address always resolves to:
macaddr-00-00-aa-bb-cc-dd.home.isp.com
You could set up your DNS entry as follows:
a.example.com. IN CNAME macaddr-00-00-aa-bb-cc-dd.home.isp.com.
- Finally, if your ISP gives you a dynamic IP address, you can use one of the dynamic DNS services. Many of these services are free and will provide a consistent reverse DNS entry that you can exploit as with the previous example.
Set Up Your SoDS Server
Set up your sods server and point it to whatever SSH or tcp servers you're interested in. These servers don't have to be publicly exposed; they could be running somewhere behind your firewall.
SoDS is configured from the command line, but its easy to wrap it in a script for system startup. Here is an example for OpenWRT:
/etc/default/sods:
OPTIONS="-D -L ssh.server1:22 -L ssh.server2:22 -L 65.55.21.250:22" DOMAIN="a.example.com"
/etc/init.d/sods:
#!/bin/sh /etc/rc.common # Copyright (C) 2006 OpenWrt.org START=50 BIN=sods DEFAULT=/etc/default/$BIN CHROOT_D=/var/chroot/sods start() { include /lib/network scan_interfaces config_load /var/state/network config_get ipaddr wan ipaddr [ -f $DEFAULT ] && . $DEFAULT [ ! -d $CHROOT_D ] && mkdir -p $CHROOT_D $BIN $OPTIONS -i $ipaddr $DOMAIN } stop() { killall sods }
Accessing Your DNS Tunnel
So next time you are enjoying a venti americano in your local coffee shop, you may think to pause from chatting with the cute barista to fire up your laptop or other mobile device and login to IRC. We're geeks, it happens.
$ ssh -o ProxyCommand="./sdt sshdns.a.example.com" 127.0.0.100
Since UDP is innately unreliable, for best results, wrap the ssh command in a script that reconnects on failure. On the server side, if you are using ssh, running everything within a GNU screen session provides seamless access to your console, in case your connection drops. See the example scripts for more details, but basically, all you need to do is use a named GNU screen session on your ssh server:
$ while [ "1" ]; do ssh -t -C -o ProxyCommand="./sdt sshdns.a.example.com" 127.0.0.100 "screen -drR sshdns"; done
SoDS Client
- sdt will try not to overwhelm the local DNS server and will back off. Some DNS servers throttle chatty clients.
To add some reliability to the protocol, both the client and server track sent packets and will re-send if they are lost. - If you are having problems connecting, run with multiple "-v" switches to see what's going on. It'll fill your screen with debug messages but will eventually stop. To control the number of debug messages displayed, use the "-V" switch (it defaults to 100).
- You can bounce your connection off of other DNS servers, beside your local DNS server, if they support recursion by using the "-r" flag. To see which servers sdt knows about, run:
sdt -v -h
To use a particular recursive server, choose it by name:
sdt -r google
To pick a random server, run:
sdt -r random
- sods supports tunnelling using TXT, CNAME and NULL records. The default is TXT records. I've found that some ISP's re-write TXT records and many DNS servers in the wild do not support NULL records at all. Using CNAME's seems to work with most networks.
NULL records have the lowest encoding overhead and the specification allows for a large packet size, reducing overhead further. Since sods does not support TCP, large packets aren't supported. - If you are on a mobile device, you probably want to conserve your battery. sdt polls for data at regular intervals by sending a request to the local DNS server to flush any pending data from your SoDS server.
You can control this polling (without much effect on latency) by using the "-b" option. Every time data is received polling ramps up and slowly decays as no new data is recieved.
If you happen to be on linux, powertop is a great tool for fine tuning the polling intervals. - Files can be transferred securely over DNS by using sftp, see the "sdftp" script in the examples. If you're brave, you can also run a fuse filesystem using sshfs.
Hi!
ReplyDeleteFirst, thanks for this. Looks amazing.
I was using ozyman until I found this and I want to change...
I want to use it with ubuntu and also in my WRT54gl.
To start, I'm trying to compile it in ubuntu.
Sods compiles OK but when I try to compile sdt I get:
$ make
gcc -DHAVE_ERR -DHAVE_SSL -g -Wall -lcrypto -o sdt sdt.c sdt_dns.c sdt_err.c sdt_rand.c base32.c base64.c /usr/lib/libresolv.a
sdt_rand.c:25:26: error: openssl/rand.h: No such file or directory
sdt_rand.c:26:25: error: openssl/err.h: No such file or directory
sdt_rand.c: In function ‘sdt_rand’:
sdt_rand.c:54: warning: implicit declaration of function ‘RAND_pseudo_bytes’
sdt_rand.c:55: warning: implicit declaration of function ‘ERR_error_string’
sdt_rand.c:55: warning: implicit declaration of function ‘ERR_get_error’
make: *** [all] Error 1
I have openssl installed. Do I need any package?
How can I compile it for wrt54gl?
Sorry for disturbing you.
Great work.
Thank you very much
Hey Diego!
ReplyDeleteYeah, sorry about that, the configure script isn't very smart. You can either install the openssl dev package (apt-get install libssl-dev) or just remove the "-DHAVE_SSL" and "-lcrypto" in the Makefile (SSL isn't a hard requirement for sdt).
To compiles sods for the WRT54GL, you'll need a cross compiler. I used the OpenWRT SDK:
http://wiki.openwrt.org/oldwiki/BuildingPackagesHowTo
It's sort of a pain to set up, so I put a compiled version of sods on github:
http://github.com/downloads/msantos/sods/sods-mips-wrt54gl.bz2
It's compiled for Kamikaze, hopefully it will work with newer versions. If you have to compile your own, it's easier to do it by hand, rather than using the Makefile:
mipsel-linux-gcc -g -Wall -DHAVE_SEND -o sods sods.c sods_handler.c sods_dns.c sods_io.c sods_q.c sods_sock.c sods_priv.c base32.c base64.c
mipsel-linux-strip sods
Hope that helps. If you have any questions or run into problems, feel free to post here or send an email (my email is on my github page).
Hi!
ReplyDeleteThank you very much for answering.
I've been able to compile it on Ubuntu and Debian and it works. By the way, it's way much faster than ozymandns. Great work!
Now, I'll try to use it on my wrt54gl and even on android. I'll let you know.
Thank you very much.
hello!
ReplyDeletei'm trying to run your compiled version (http://github.com/downloads/msantos/sods/sods-mips-wrt54gl.bz2) on my router with tomato 1.28 firmware, but i only get this:
# ./sods 123
User defined signal 1
do you have an idea of what is wrong? :S
and thanks a lot for the program, i've been using it successfully at overpriced hotspots for quite some time now :)
Try this version:
ReplyDeletehttps://github.com/downloads/msantos/sods/sods-mips-wrt54gl-static.bz2
It's statically linked. If it doesn't work, you'll probably need to recompile sods under Tomato.
Very happy to hear sods has been useful for you!
thank you for your quick reply! unfortunately i still get the same error (User defined signal 1). im pretty new to compiling (ive only been using the automated make command so far), could you give me some suggestions as to how to compile it for tomato?
ReplyDeleteIf you clone the tomato git repository, there's a pre-compiled toolchain in tools/bcrm. Copy the toolchain to /opt/bcrm and run:
ReplyDeletemipsel-linux-gcc -DHAVE_SEND -o sods sods.c sods_handler.c sods_dns.c sods_io.c sods_q.c sods_sock.c sods_priv.c base32.c base64.c -lresolv
(Doesn't work with uclibc gcc yet, I should fix that some day).
Looked simple, so I compiled a version for tomato and put it here:
https://github.com/downloads/msantos/sods/sods-mips-tomato-1.27.bz2
I don't have tomato installed so let me know if you run into any problems!
thanks for compiling it! sadly, it still won't work :(, this happens:
ReplyDelete# sh sods-mips-tomato-1.27
sods-mips-tomato-1.27: line 1: syntax error: unexpected "("
It's a binary, not a shell script. Try:
ReplyDeletechmod +x sods
./sods
sorry for constantly bothering you... something very strange happens, file not found?! :S
ReplyDelete# ls
sods-mips-tomato-1.27
# chmod +x sods-mips-tomato-1.27
# ./sods-mips-tomato-1.27
-sh: ./sods-mips-tomato-1.27: not found
And another attempt :) This version is statically linked:
ReplyDeletehttps://github.com/downloads/msantos/sods/sods-mips-tomato-1.27-static.bz2
Thanks for you patience doing all these tests!
huge step forward, it runs now! :D however, i get this error when trying to start it:
ReplyDelete# ./sods -vvvv -d /tmp -L 127.0.0.1:22 sods.mydomain.com
Forwarded sessions = 1
Forward #0: 127.0.0.1:22
sods: bind(ss->s, (struct sockaddr *)&ss->local, sizeof(ss->local)): Address already in use
Awesome. About the bind error: you probably have another dns server (like dnsmasq) listening on port 53 on all interfaces. dnsmasq only needs to be listening on the LAN side and sods only needs to listen on the WAN side.
ReplyDeleteI start dnsmasq with the --bind-interfaces option and then start sods with -i $external_ip_address
you are right, i had dnsmasq running... now i added these 2 lines to its conf file:
ReplyDeleteexcept-interface=vlan1
bind-interfaces
the bind error seems to be gone now, but now this happens:
# ./sods -vvvv -d /tmp -L 127.0.0.1:22 -i 123.123.123.123 sods.domain.com
Forwarded sessions = 1
Forward #0: 127.0.0.1:22
sods: user does not exist: nobody
sods: Could not drop privs
Just add a sods (or nobody) user to /etc/passwd and a sods group to /etc/group. Also make sure the chroot directory exists (by default /var/chroot/sods). sods changes to an unprivileged user after startup.
ReplyDeleteThen start sods with the name/group. Something like:
./sods -u sods -g sods
with a /etc/passwd like:
sods:*:4321:4321:sods user:/:/bin/false
And for /etc/group something like:
sods:x:4321:
i'm sorry, i forgot to mention before that user nobody is already added:
ReplyDelete# cat /etc/passwd
root:x:0:0:root:/root:/bin/sh
nobody:x:65534:65534:nobody:/dev/null:/dev/null
# cat /etc/group
root:x:0:
nobody:x:65534:
# ./sods -vvvv -u nobody -g nobody -d /tmp -L 127.0.0.1:22 -i 123.123.123.123 sods.domain.com
Forwarded sessions = 1
Forward #0: 127.0.0.1:22
sods: user does not exist: nobody
sods: Could not drop privs
So it seems the binary needs to be dynamically linked to use getuid().
ReplyDeleteI recompiled the Tomato toolchain and made some changes to sods to get it to work with uclibc. I was able to use the result on OpenWRT.
Here it is, hope this one works for you!
https://github.com/downloads/msantos/sods/sods-uclibc-tomato-1.28.bz2
# ./sods
ReplyDelete./sods: can't load library 'libresolv.so.0'
:(
It seems libresolv in uclibc is just a wrapper and isn't needed.
ReplyDeleteHere are 2 versions without any other dependencies:
https://github.com/downloads/msantos/sods/sods-uclibc-tomato-1.28.bz2
https://github.com/downloads/msantos/sods/sods-uclibc-tomato-1.28-static.bz2
GOT IT TO WORK :D finally, thanks so much for all the help!! :)
ReplyDeleteif anyone else who wants to run sods on tomato is reading this, i found out you can't "forward" port 53 to the router with the webui (even though it says it's forwarded), you have to do it manually with iptables.
also, tomato rewrites iptables every time you change any settings or reboot, so you have to put this script in the webui (administration->scripts->firewall):
iptables -A wanin -p tcp -m tcp -d 192.168.1.1 --dport 53 -j ACCEPT
iptables -A wanin -p udp -m udp -d 192.168.1.1 --dport 53 -j ACCEPT
and of course, read the instructions above for dnsmasq - you have edit its conf file in the webui as well (advanced -> dhcp/dns)
Hi,
ReplyDeletethanks for that piece of software! I was always searching for a soluting that a) is able to use CNAME and b) is written in C. :-))
I managed to get it running for one service (SSH) like this:
server: sods -L 127.0.0.1:22 tun.mydom.com
client: sdt -t CNAME sshdns.tun.mydom.com
What I would like to do now is run it for two services (HTTPS and SSH). If I got it right, I have to use the "-L" switch several times:
sods -L 127.0.0.1:22 -L 127.0.0.1:443 tun.mydom.com
But: how do I tell the client (sdt) which service to use?
If I have only one service (https), is it possible to omit the "ssndns" prefix? Or is it always necessary?
What do the client options "-D" and "-s" do? I read the client's help, but I do not understand it.
Sorry for these dumb questions.
Best regards, Sven
Hey Sven!
ReplyDelete> I managed to get it running for one service (SSH) like this:
>
> server: sods -L 127.0.0.1:22 tun.mydom.com
> client: sdt -t CNAME sshdns.tun.mydom.com
>
> What I would like to do now is run it for two services (HTTPS and SSH). If
> I got it right, I have to use the "-L" switch several times:
>
> sods -L 127.0.0.1:22 -L 127.0.0.1:443 tun.mydom.com
Yup, that's right!
> But: how do I tell the client (sdt) which service to use?
Use the "-s" switch to sdt and the session number. The sessions are
numbered starting from 0, from left to right. So in your example, to
connect to port 22 you would use:
sdt -s 0 -t CNAME sshdns.tun.mydom.com
And to connect to port 443:
sdt -s 1 -t CNAME sshdns.tun.mydom.com
> If I have only one service (https), is it possible to omit the "ssndns"
> prefix? Or is it always necessary?
No, you can use any prefix. I just use a single character to keep the
byte count down, something like s.tun.mydom.com.
> What do the client options "-D" and "-s" do? I read the client's help,
> but I do not understand it.
-s: chooses the session to use (a session is the destination IP/port you want
to proxy). Session 0 is the default.
-D: dynamic forwarding
"-D" is experimental. It lets the client tell the server which IP
address/port it wants to go to. I'm thinking of setting up a service on
a virutal machine somewhere so people won't have to through the hassle
of installing sods and all the DNS entries.
The C version of sods doesn't support dynamic forwarding yet. The version
(in Erlang) that does is here:
https://github.com/msantos/seds
> Sorry for these dumb questions.
Those were great questions, thanks for taking the time to put them
together! And let me know if you run into any other problems.
Hi Michael,
ReplyDeletethank you for your quick and detailed reply. I shortened down "sshdns" to a single character. Using the "-s" parameter and the session numbers also work as you explained, I can now use multiple services. :-)
Very useful piece of software, thanks a lot! ;-)
Best regards, Sven
Hi,
ReplyDeleteI'm trying to get this to work on my phone but not quite getting it to.
The server side is setup ok as I've run the local test and this worked.
On the phone I get the error "res_search: unknown host" but this makes no sense (to me!) as if I ping the domain from the phone it resolves correctly.
On the SODS server I can see some packets coming through but I don't get connected to the SSH server on the server that SODS is running on.
I've likely made a noobie mistake but cannot work out what it is!
Hey Chris!
ReplyDeleteFor some reason which I haven't quite worked out yet, sdt on android is a bit flakey, so the first thing to try is rebooting your phone (I know, lame).
Here are some things you can try:
1. It looks as if the end to end connection to your sods server is good since you're seeing packets. Can you run sods in debug mode (sods -vvv) and paste the output here or email it to me? Feel free to sanitize the domain names.
2. Try specifying the IP of the dns server to rule out any problems in between (from an open network):
sdt -r x.x.x.x
3. And to rule out problems with Android, have you tested the tunnel on something besides the phone? What version of Android are you using?
4. Finally, what flags are you passing to sdt and sods?
Thanks!
Hi,
ReplyDeleteOn the SODS server I get :-
2012-01-09 09:11:10 knjuqljsfyyc2vdsnfwgkyleknjuqmskmf3gcxzsgezq2cq.36202-0.id-38592.up.tunnel.testdomain.com
2012-01-09 09:11:10 rejecting request for domain: testdomain.com
2012-01-09 09:11:10 0-36202.id-38592.down.tunnel.testdomain.com
2012-01-09 09:11:10 rejecting request for domain: testdomain.com
SODS Server:
[root@localhost sods]# ./sods -u nobody -g nobody -d /tmp -L 127.0.0.1:22 tunnel.testdomain.com -vvvv
SDT:
./sdt -t CNAME -r 8.8.8.8 -p 22220 -s 0 -vvvv tunnel.testdomain.com
I've used another IP over DNS program (not on the phone) and I found it best to set the "DNS Server" to be the actual server itself, rather than a real DNS server. When I do this with SDT I get a lot more packets through than going via google DNS but I get the same error.
I'm using a Samsung SGS 2 with GB 2.3.5
> 2012-01-09 09:11:10 knjuqljsfyyc2vdsnfwgkyleknjuqmskmf3gcxzsgezq2cq.36202-0.id-38592.up.tunnel.testdomain.com
ReplyDelete> 2012-01-09 09:11:10 rejecting request for domain: testdomain.com
Domain check was triggered. You can disable it by using the magic keyword "any":
./sods -u nobody -g nobody -d /tmp -L 127.0.0.1:22 any
Adding another domain component to sdt should make the tunnel work:
./sdt -t CNAME -r 8.8.8.8 -p 22220 -s 0 -vvvv s.tunnel.testdomain.com
(Added the subdomain "s" to tunnel.testdomain.com).
Hopefully that will work but let me know if you run into more problems!
This comment has been removed by the author.
ReplyDelete