mirror of
https://github.com/yarrick/iodine.git
synced 2025-12-05 20:01:50 +00:00
Applied patch from #88, thanks a lot!
This commit is contained in:
committed by
Erik Ekman
parent
1a26a91db3
commit
b177901d38
299
README
299
README
@@ -11,12 +11,12 @@ 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
|
||||
- On your server, run: ./iodined -f 10.0.0.1 test.com
|
||||
(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)
|
||||
- On the client, run: ./iodine -f -r 192.168.0.1 test.com
|
||||
(Replace 192.168.0.1 with your 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
|
||||
@@ -26,113 +26,196 @@ To actually use it through a relaying nameserver, see below.
|
||||
|
||||
HOW TO USE:
|
||||
|
||||
Note: server and client are required to speak the exact same protocol. In most
|
||||
cases, this means running the same iodine version. Unfortunately, implementing
|
||||
backward and forward protocol compatibility is usually not feasible.
|
||||
|
||||
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:
|
||||
To use this tunnel, you need control over a real domain (like mydomain.com),
|
||||
and a server with a public IP address to run iodined on. If this server
|
||||
already runs a DNS program, change its listening port and then use iodined's
|
||||
-b option to let iodined forward the DNS requests. (Note that this procedure
|
||||
is not advised in production environments, because iodined's DNS forwarding
|
||||
is not completely transparent.)
|
||||
|
||||
tunnel1host IN A 10.15.213.99
|
||||
tunnel1 IN NS tunnel1host.mytunnel.com.
|
||||
Then, delegate a subdomain (say, t1.mydomain.com) to the iodined server.
|
||||
If you use BIND for your domain, add two lines like these to the zone file:
|
||||
|
||||
Do not use CNAME instead of A above.
|
||||
If your server has a dynamic IP, use a dynamic dns provider:
|
||||
t1 IN NS t1ns.mydomain.com. ; note the dot!
|
||||
t1ns IN A 10.15.213.99
|
||||
|
||||
tunnel1 IN NS tunnel1host.mydyndnsprovider.com
|
||||
The "NS" line is all that's needed to route queries for the "t1" subdomain
|
||||
to the "t1ns" server. We use a short name for the subdomain, to keep as much
|
||||
space as possible available for the data traffic. At the end of the "NS" line
|
||||
is the name of your iodined server. This can be any name, pointing anywhere,
|
||||
but in this case it's easily kept in the same zone file. It must be a name
|
||||
(not an IP address), and that name itself must have an A record (not a CNAME).
|
||||
|
||||
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.
|
||||
If your iodined server has a dynamic IP, use a dynamic dns provider. Simply
|
||||
point the "NS" line to it, and leave the "A" line out:
|
||||
|
||||
t1 IN NS myname.mydyndnsprovider.com. ; note the dot!
|
||||
|
||||
Then reload or restart your nameserver program. Now any DNS queries for
|
||||
domains ending in t1.mydomain.com will be sent to your iodined server.
|
||||
|
||||
Finally start iodined on your server. The first argument is the IP address
|
||||
inside the tunnel, which can be from any range that you don't use yet (for
|
||||
example 192.168.99.1), and the second argument is the assigned domain (in this
|
||||
case t1.mydomain.com). Using the -f option will keep iodined running in the
|
||||
foreground, which helps when testing. iodined will open a virtual interface
|
||||
("tun device"), and will 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.
|
||||
|
||||
If there is a chance you'll be using an iodine tunnel from unexpected
|
||||
environments, start iodined with a -c option.
|
||||
|
||||
Resulting commandline in this example situation:
|
||||
./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com
|
||||
|
||||
Client side:
|
||||
All the setup is done, just start iodine. It takes up to two arguments, the
|
||||
All the setup is done, just start iodine. It takes one or 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.
|
||||
you used (t1.mydomain.com). If you don't specify the first argument, the
|
||||
system's current DNS setting will be consulted.
|
||||
|
||||
If DNS queries are allowed to any computer, you can directly give the iodined
|
||||
server's address as first argument (in the example: t1ns.mydomain.com or
|
||||
10.15.213.99). In that case, it may also happen that _any_ traffic is allowed
|
||||
to the DNS port (53 UDP) of any computer. Iodine will detect this, and switch
|
||||
to raw UDP tunneling if possible. To force DNS tunneling in any case, use the
|
||||
-r option (especially useful when testing within your own network).
|
||||
|
||||
The client's tunnel interface will get an IP close to the server's (in this
|
||||
case 192.168.99.2 or .3 etc.) and a suitable MTU. Enter the same password as
|
||||
on the server either as commandline option or after the client has started.
|
||||
Using the -f option will keep the iodine client running in the foreground.
|
||||
|
||||
Resulting commandline in this example situation:
|
||||
./iodine -f -P secretpassword t1.mydomain.com
|
||||
(add -r to force DNS tunneling even if raw UDP tunneling would be possible)
|
||||
|
||||
From either side, you should now be able to ping the IP address on the other
|
||||
end of the tunnel. In this case, ping 192.168.99.1 from the iodine client, and
|
||||
192.168.99.2 or .3 etc. from the iodine server.
|
||||
|
||||
|
||||
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.
|
||||
It is possible to route all traffic through the DNS tunnel. To do this, first
|
||||
add a host route to the nameserver used by iodine over the wired/wireless
|
||||
interface with the default gateway as gateway. Then replace the default
|
||||
gateway with the iodined server's IP address inside the DNS tunnel, and
|
||||
configure the server to do NAT.
|
||||
|
||||
However, note that the tunneled data traffic is not encrypted at all, and can
|
||||
be read and changed by external parties relatively easily. For maximum
|
||||
security, run a VPN through the DNS tunnel (=double tunneling), or use secure
|
||||
shell (SSH) access, possibly with port forwarding. The latter can also be used
|
||||
for web browsing, when you run a web proxy (for example Privoxy) on your
|
||||
server.
|
||||
|
||||
Testing:
|
||||
The iodined server replies to NS requests sent for subdomains of the tunnel
|
||||
domain. If your iodined subdomain is t1.mydomain.com, send a NS request for
|
||||
foo123.t1.mydomain.com to see if the delegation works. dig is a good tool
|
||||
for this:
|
||||
dig -t NS foo123.t1.mydomain.com
|
||||
|
||||
Also, the iodined server will answer requests starting with 'z' for any of the
|
||||
supported request types, for example:
|
||||
dig -t TXT z456.t1.mydomain.com
|
||||
dig -t SRV z456.t1.mydomain.com
|
||||
dig -t CNAME z456.t1.mydomain.com
|
||||
The reply should look like garbled text in all these cases.
|
||||
|
||||
Operational info:
|
||||
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 DNS hostnames are normally used up to their maximum length, 255 characters.
|
||||
Some DNS relays have been found that answer full-length queries rather
|
||||
unreliably, giving widely varying (and mostly very bad) results of the
|
||||
fragment size autoprobe on repeated tries. In these cases, use the -M switch
|
||||
to reduce the DNS hostname length to for example 200 characters, which makes
|
||||
these DNS relays much more stable. This is also useful on some "de-optimizing"
|
||||
DNS relays that stuff the response with two full copies of the query, leaving
|
||||
very little space for downstream data (also not capable of EDNS0). The -M
|
||||
switch can trade some upstream bandwidth for downstream bandwidth. Note that
|
||||
the minimum -M value is about 100, since the protocol can split packets (1200
|
||||
bytes max) in only 16 fragments, requiring at least 75 real data bytes per
|
||||
fragment.
|
||||
|
||||
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 upstream data is sent gzipped encoded with Base32; or Base64 if the relay
|
||||
server supports mixed case and '+' in domain names; or Base64u if '_' is
|
||||
supported instead; or Base128 if high-byte-value characters are supported.
|
||||
This upstream encoding is autodetected. The 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.
|
||||
Several DNS request types are supported, with the NULL type expected to provide
|
||||
the largest downstream bandwidth. Other available types are TXT, SRV, MX,
|
||||
CNAME and A (returning CNAME), in decreasing bandwidth order. Normally the
|
||||
"best" request type is autodetected and used. However, DNS relays may impose
|
||||
limits on for example NULL and TXT, making SRV or MX actually the best choice.
|
||||
This is not autodetected, but can be forced using the -T option. It is
|
||||
advisable to try various alternatives especially when the autodetected request
|
||||
type provides a downstream fragment size of less than 200 bytes.
|
||||
|
||||
Note that SRV, MX and A (returning CNAME) queries 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 queries can be encoded with the same set of codecs
|
||||
as upstream data. This is normally also autodetected, but no fully exhaustive
|
||||
tests are done, so some problems may not be noticed when selecting more
|
||||
advanced codecs. In that case, you'll see failures/corruption in the fragment
|
||||
size autoprobe. In particular, several DNS relays have been found that change
|
||||
replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when that
|
||||
hostname exceeds ca. 180 characters. In these and similar cases, use the -O
|
||||
option to try other downstream codecs; Base32 should always work.
|
||||
|
||||
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 .
|
||||
slow down the quiescent ping requests to 4 second intervals by default, and
|
||||
possibly much slower. In fact, the main purpose of the pings now is to force
|
||||
a reply to the previous ping, and prevent DNS server timeouts (usually at
|
||||
least 5-10 seconds per RFC1035). Some DNS servers are more impatient and will
|
||||
give SERVFAIL errors (timeouts) in periods without tunneled data traffic. All
|
||||
data should still get through in these cases, but iodine will reduce the ping
|
||||
interval to 1 second anyway (-I1) to reduce the number of error messages. This
|
||||
may not help for very impatient DNS relays like dnsadvantage.com (ultradns),
|
||||
which time out in 1 second or even less. Yet data will still get trough, and
|
||||
you can ignore the SERVFAIL errors.
|
||||
|
||||
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.
|
||||
If you are running on a local network without any DNS server in-between, try
|
||||
-I 50 (iodine and iodined close the connection after 60 seconds of silence).
|
||||
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.
|
||||
|
||||
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.
|
||||
The delayed answering in lazy mode will cause some "carrier grade" commercial
|
||||
DNS relays to repeatedly re-send the same DNS query to the iodined server.
|
||||
If the DNS relay is actually implemented as a pool of parallel servers,
|
||||
duplicate requests may even arrive from multiple sources. This effect will
|
||||
only be visible in the network traffic at the iodined server, and will not
|
||||
affect the client's connection. Iodined will notice these duplicates, and send
|
||||
the same answer (when its time has come) to both the original query and the
|
||||
latest duplicate. After that, the full answer is cached for a short while.
|
||||
Delayed duplicates that arrive at the server even later, get a reply that the
|
||||
iodine client will ignore (if it ever arrives there).
|
||||
|
||||
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.
|
||||
like tcpdump or ethereal/wireshark, 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:
|
||||
@@ -165,13 +248,16 @@ 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.
|
||||
Measurements were done in protocol 00000502 in lazy mode; upstream encoding
|
||||
always Base128; iodine -M255; iodined -m1130. Network conditions were not
|
||||
extremely favorable; results are not benchmarks but a realistic indication of
|
||||
real-world performance that can be expected in similar situations.
|
||||
|
||||
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.
|
||||
explains why some 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.
|
||||
|
||||
@@ -185,43 +271,28 @@ Laptop -> Wifi AP -> Home server -> DSL provider -> Datacenter
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
iodine -> Wifi AP :53
|
||||
-Tnull (= -Oraw) 982 39.3 148.5 26.7 3.1 26.6 3.0
|
||||
-Tnull (= -Oraw) 982 43.6 131.0 28.0 4.6 26.8 3.4
|
||||
|
||||
iodine -> Home server :53
|
||||
-Tnull (= -Oraw) 1174 43.6 174.7 25.2 4.0 25.5 3.4
|
||||
-Tnull (= -Oraw) 1174 48.0 305.8 26.6 5.0 26.9 8.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
|
||||
-Tnull (= -Oraw) 1174 56.7 367.0 20.6 3.1 21.2 4.4
|
||||
-Ttxt -Obase32 730 56.7 174.7*
|
||||
-Ttxt -Obase64 874 56.7 174.7
|
||||
-Ttxt -Obase128 1018 56.7 174.7
|
||||
-Ttxt -Oraw 1162 56.7 358.2
|
||||
-Tsrv -Obase128 910 56.7 174.7
|
||||
-Tcname -Obase32 151 56.7 43.6
|
||||
-Tcname -Obase128 212 56.7 52.4
|
||||
|
||||
iodine -> DSL provider :53
|
||||
wired (no Wifi) -Tnull 1174 65.5 244.6 17.7 1.9 17.8 1.6
|
||||
wired (no Wifi) -Tnull 1174 74.2 585.4 20.2 5.6 19.6 3.4
|
||||
|
||||
[192.2* : nice, because still 2frag/packet]
|
||||
[174.7* : these all have 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
|
||||
|
||||
@@ -229,9 +300,9 @@ Laptop -> Wifi+vpn / wired -> Home server
|
||||
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
|
||||
wifi + openvpn -Tnull 1186 166.0 1022.3 6.3 1.3 6.6 1.6
|
||||
|
||||
wired -Tnull 1186 685.9 2350.5 1.3 0.1 1.4 0.4
|
||||
wired -Tnull 1186 677.2 2464.1 1.3 0.2 1.3 0.1
|
||||
|
||||
|
||||
Performance is strongly coupled to low ping times, as iodine requires
|
||||
|
||||
Reference in New Issue
Block a user