mirror of
https://github.com/yarrick/iodine.git
synced 2024-12-22 21:33:33 +02:00
285 lines
13 KiB
Text
285 lines
13 KiB
Text
|
|
iodine - http://code.kryo.se/iodine
|
|
|
|
***********************************
|
|
|
|
This is a piece of software that lets you tunnel IPv4 data through a DNS
|
|
server. This can be usable in different situations where internet access is
|
|
firewalled, but DNS queries are allowed.
|
|
|
|
|
|
QUICKSTART:
|
|
|
|
Try it out within your own LAN! Follow these simple steps:
|
|
- On your server, run: ./iodined -f 10.0.0.1 test.asdf
|
|
(If you already use the 10.0.0.0 network, use another internal net like
|
|
172.16.0.0)
|
|
- Enter a password
|
|
- On the client, run: ./iodine -f 192.168.0.1 test.asdf
|
|
(Replace 192.168.0.1 with the server's ip address)
|
|
- Enter the same password
|
|
- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
|
|
- Try pinging each other through the tunnel
|
|
- Done! :)
|
|
To actually use it through a relaying nameserver, see below.
|
|
|
|
|
|
HOW TO USE:
|
|
|
|
Server side:
|
|
To use this tunnel, you need control over a real domain (like mytunnel.com),
|
|
and a server with a public IP number. If the server already runs a DNS
|
|
server, change the listening port and then use the -b option to let
|
|
iodined forward the DNS requests. Then, delegate a subdomain
|
|
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
|
|
add these lines to the zone file:
|
|
|
|
tunnel1host IN A 10.15.213.99
|
|
tunnel1 IN NS tunnel1host.mytunnel.com.
|
|
|
|
Do not use CNAME instead of A above.
|
|
If your server has a dynamic IP, use a dynamic dns provider:
|
|
|
|
tunnel1 IN NS tunnel1host.mydyndnsprovider.com
|
|
|
|
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
|
|
to your server. Start iodined on the server. The first argument is the tunnel
|
|
IP address (like 192.168.99.1) and the second is the assigned domain (in this
|
|
case tunnel1.mytunnel.com). The -f argument will keep iodined running in the
|
|
foreground, which helps when testing. iodined will start a virtual interface,
|
|
and also start listening for DNS queries on UDP port 53. Either enter a
|
|
password on the commandline (-P pass) or after the server has started. Now
|
|
everything is ready for the client.
|
|
|
|
Client side:
|
|
All the setup is done, just start iodine. It takes up to two arguments, the
|
|
first is the local relaying DNS server (optional) and the second is the domain
|
|
used (tunnel1.mytunnnel.com). If DNS queries are allowed to any computer, you
|
|
can use the tunnel endpoint (example: 10.15.213.99 or tunnel1host.mytunnel.com)
|
|
as the first argument. The tunnel interface will get an IP close to the servers
|
|
(in this case 192.168.99.2) and a suitable MTU. Enter the same password as on
|
|
the server either by argument or after the client has started. Now you should
|
|
be able to ping the other end of the tunnel from either side.
|
|
|
|
|
|
MISC. INFO:
|
|
|
|
Routing:
|
|
The normal case is to route all traffic through the DNS tunnel. To do this, first
|
|
add a route to the nameserver you use with the default gateway as gateway. Then
|
|
replace the default gateway with the servers IP address within the DNS tunnel,
|
|
and configure the server to do NAT.
|
|
|
|
The DNS-response fragment size is normally autoprobed to get maximum bandwidth.
|
|
To force a specific value (and speed things up), use the -m option.
|
|
|
|
The iodined server replies to NS requests sent for subdomains of the tunnel
|
|
domain. If your domain is tunnel.com, send a NS request for foo.tunnel.com
|
|
to see if the delegation works. dig is a good tool for this:
|
|
dig -t NS foo123.tunnel.com
|
|
|
|
The upstream data is sent gzipped encoded with Base32, or Base64 if the relay
|
|
server support '+' in domain names. DNS protocol allows one query per packet,
|
|
and one query can be max 256 chars. Each domain name part can be max 63 chars.
|
|
So your domain name and subdomain should be as short as possible to allow
|
|
maximum upstream throughput.
|
|
|
|
The default is to use DNS NULL-type queries, as this provides the largest
|
|
downstream bandwidth. If your DNS server blocks NULL requests, try TXT or
|
|
CNAME queries via the -T option. Also supported are A (returning CNAME) and
|
|
MX requests, but these may/will cause additional lookups by "smart" caching
|
|
nameservers to get an actual IP address, which may either slow down or fail
|
|
completely. DNS responses for non-NULL are Base32 encoded by default, which
|
|
should always work. For more bandwidth, try Base64 or Raw (TXT only) via the
|
|
-O option. If Base64/Raw doesn't work, you'll see many failures in the
|
|
fragment size autoprobe.
|
|
|
|
Normal operation now is for the server to _not_ answer a DNS request until
|
|
the next DNS request has come in, a.k.a. being "lazy". This way, the server
|
|
will always have a DNS request handy when new downstream data has to be sent.
|
|
This greatly improves (interactive) performance and latency, and allows to
|
|
slow down the quiescent ping requests to 4 second intervals by default.
|
|
In fact, the main purpose of the pings now is to force a reply to the previous
|
|
ping, and prevent DNS server timeouts (usually 5-10 seconds per RFC1035).
|
|
In the unlikely case that you do experience DNS server timeouts (SERVFAIL),
|
|
decrease the -I option to 1. If you are running on a local network without
|
|
any DNS server in-between, try -I 50 (iodine and iodined time out after 60
|
|
seconds). The only time you'll notice a slowdown, is when DNS reply packets
|
|
go missing; the iodined server then has to wait for a new ping to re-send the
|
|
data. You can speed this up by generating some upstream traffic (keypress,
|
|
ping). If this happens often, check your network for bottlenecks and/or run
|
|
with -I1 .
|
|
|
|
Some DNS servers appear to be quite impatient and start retrying DNS requests
|
|
(with _different_ DNS ids!) when an answer does not appear within a few
|
|
milliseconds. Usually they scale back retries when iodined's lazy mode
|
|
repeatedly takes several seconds to answer; and they scale up retries again
|
|
when iodined answers fast during heavy data transfer. Some commercial DNS
|
|
servers advertise this as "carrier-grade adaptive retransmission techniques".
|
|
The effect will only be visible in the network traffic at the iodined server,
|
|
and will not affect the client's connection. Iodined has rather elaborate
|
|
logic to deal with (i.e., ignore) these unwanted duplicates.
|
|
|
|
Other DNS servers, notably the opendns.com network, seem to regard iodined's
|
|
lazyness as incompetency, and will start shuffling requests around, possibly
|
|
in an attempt to reduce iodined's workload. The resulting out-of-sequence DNS
|
|
traffic works quite badly for lazy mode. The iodine client will detect this,
|
|
and switch back to legacy mode ("immediate ping-pong") automatically. In these
|
|
cases, start the iodine client with -L0 to prevent it from operating in lazy
|
|
mode altogether. Note that this will negatively affect interactive performance
|
|
and latency, especially in the downstream direction.
|
|
|
|
If you have problems, try inspecting the traffic with network monitoring tools
|
|
and make sure that the relaying DNS server has not cached the response. A
|
|
cached error message could mean that you started the client before the server.
|
|
The -D (and -DD) option on the server can also show received and sent queries.
|
|
|
|
|
|
TIPS & TRICKS:
|
|
|
|
If your port 53 is taken on a specific interface by an application that does
|
|
not use it, use -p on iodined to specify an alternate port (like -p 5353) and
|
|
use for instance iptables (on Linux) to forward the traffic:
|
|
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
|
|
(Sent in by Tom Schouten)
|
|
|
|
Iodined will reject data from clients that have not been active (data/pings)
|
|
for more than 60 seconds. Similarly, iodine will exit when no downstream
|
|
data has been received for 60 seconds. In case of a long network outage or
|
|
similar, just restart iodine (re-login), possibly multiple times until you get
|
|
your old IP address back. Once that's done, just wait a while, and you'll
|
|
eventually see the tunneled TCP traffic continue to flow from where it left
|
|
off before the outage.
|
|
|
|
With the introduction of the downstream packet queue in the server, its memory
|
|
usage has increased with several megabytes in the default configuration.
|
|
For use in low-memory environments (e.g. running on your DSL router), you can
|
|
decrease USERS and undefine OUTPACKETQ_LEN in user.h without any ill conse-
|
|
quence, assuming at most one client will be connected at any time. A small
|
|
DNSCACHE_LEN is still advised, preferably 2 or higher, however you can also
|
|
undefine it to save a few more kilobytes.
|
|
|
|
|
|
PERFORMANCE:
|
|
|
|
This section tabulates some performance measurements. To view properly, use
|
|
a fixed-width font like Courier.
|
|
|
|
Measurements were done in protocol 00000500 with lazy mode unless indicated
|
|
otherwise. Upstream encoding always Base64.
|
|
Upstream/downstream throughput was measured by scp'ing a file previously
|
|
read from /dev/urandom (i.e. incompressible), and measuring size with
|
|
"ls -l ; sleep 30 ; ls -l" on a separate non-tunneled connection. Given the
|
|
large scp block size of 16 kB, this gives a resolution of 4.3 kbit/s, which
|
|
explains why many values are exactly equal.
|
|
Ping round-trip times measured with "ping -c100", presented are average rtt
|
|
and mean deviation (indicating spread around the average), in milliseconds.
|
|
|
|
|
|
Situation 1:
|
|
Laptop -> Wifi AP -> Home server -> DSL provider -> Datacenter
|
|
iodine DNS "relay" bind9 DNS cache iodined
|
|
|
|
downstr. upstream downstr. ping-up ping-down
|
|
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
|
------------------------------------------------------------------------------
|
|
|
|
iodine -> Wifi AP :53
|
|
-Tnull (= -Oraw) 982 39.3 148.5 26.7 3.1 26.6 3.0
|
|
|
|
iodine -> Home server :53
|
|
-Tnull (= -Oraw) 1174 43.6 174.7 25.2 4.0 25.5 3.4
|
|
|
|
iodine -> DSL provider :53
|
|
-Tnull (= -Oraw) 1174 52.4 200.9 20.3 3.2 20.3 2.7
|
|
-Ttxt -Obase32 730 52.4 192.2*
|
|
-Ttxt -Obase64 874 52.4 192.2
|
|
-Ttxt -Oraw 1162 52.4 192.2
|
|
-Tcname -Obase32 148 52.4 48.0
|
|
-Tcname -Obase64 181 52.4 61.1
|
|
|
|
iodine -> DSL provider :53
|
|
wired (no Wifi) -Tnull 1174 65.5 244.6 17.7 1.9 17.8 1.6
|
|
|
|
[192.2* : nice, because still 2frag/packet]
|
|
|
|
|
|
Situation 2:
|
|
Laptop -> (wire) -> (Home server) -> (DSL) -> opendns.com -> Datacenter
|
|
iodine DNS cache iodined
|
|
|
|
downstr. upstream downstr. ping-up ping-down
|
|
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
|
------------------------------------------------------------------------------
|
|
|
|
iodine -> opendns.com :53
|
|
-Tnull -L1 (lazy mode) 230 - - 404.4 196.2 663.8 679.6
|
|
(20% lost) (2% lost)
|
|
|
|
-Tnull -L0 (legacy mode) 230 5.6 7.4 197.3 4.7 610.8 323.5
|
|
|
|
[Note: Throughput measured over 300 seconds to get better resolution]
|
|
|
|
|
|
Situation 3:
|
|
Laptop -> Wifi+vpn / wired -> Home server
|
|
iodine iodined
|
|
|
|
downstr. upstream downstr. ping-up ping-down
|
|
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
|
------------------------------------------------------------------------------
|
|
|
|
wifi + openvpn -Tnull 1186 183.5 611.6 5.7 1.4 7.0 2.7
|
|
|
|
wired -Tnull 1186 685.9 2350.5 1.3 0.1 1.4 0.4
|
|
|
|
|
|
Performance is strongly coupled to low ping times, as iodine requires
|
|
confirmation for every data fragment before moving on to the next. Allowing
|
|
multiple fragments in-flight like TCP could possibly increase performance,
|
|
but it would likely cause serious overload for the intermediary DNS servers.
|
|
The current protocol scales performance with DNS responsivity, since the
|
|
DNS servers are on average handling at most one DNS request per client.
|
|
|
|
|
|
PORTABILITY:
|
|
|
|
iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD
|
|
(ia64, x86), OpenBSD (x86), NetBSD (x86), MacOS X (ppc and x86, with
|
|
http://tuntaposx.sourceforge.net/). and Windows (with OpenVPN TAP32 driver, see
|
|
win32 readme file). It should be easy to port to other unix-like systems that
|
|
has TUN/TAP tunneling support. Let us know if you get it to run on other
|
|
platforms.
|
|
|
|
|
|
THE NAME:
|
|
|
|
The name iodine was chosen since it starts with IOD (IP Over DNS) and since
|
|
iodine has atomic number 53, which happens to be the DNS port number.
|
|
|
|
|
|
THANKS:
|
|
|
|
- To kuxien for FreeBSD and OS X testing
|
|
- To poplix for code audit
|
|
|
|
|
|
AUTHORS & LICENSE:
|
|
|
|
Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
|
|
|
Permission to use, copy, modify, and distribute this software for any purpose
|
|
with or without fee is hereby granted, provided that the above copyright notice
|
|
and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
MD5 implementation by L. Peter Deutsch (license and source in src/md5.[ch])
|
|
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|