Package: iodine
Version: 0.4.1-3
Severity: wishlist
I wrote a little script to set up an iodine DNS tunnel. It tries to
figure out the situation and do the right thing, and also to give some
reasonable diagnostics, and it is externally configurable and also
has a rudementary debugging facility (run as non-root with
continue_on_error=true). Thought I'd share it, in case others might
find it useful.
--Barak.
--
Barak A. Pearlmutter
Hamilton Institute & Dept Comp Sci, NUI Maynooth, Co. Kildare, Ireland
http://www.bcl.hamilton.ie/~barak/
#! /bin/bash
## Cause script to bail immediately on failed command
set -e
## OPTIONS TO SET
echo "${iodine_client_rc:=/etc/default/iodine-client}" > /dev/null
if [ -r ${iodine_client_rc} ]; then
. ${iodine_client_rc}
else
echo WARNING: Cannot read ${iodine_client_rc}
fi
echo "${subdomain:=your-subdomain.example.com}" > /dev/null
echo "${passwd:=yourpassword}" > /dev/null
echo "${testhost:=slashdot.org}" > /dev/null
echo "${bounce_localnet:=true}" > /dev/null
echo "${test_ping_localnet:=true}" > /dev/null
echo "${test_ping_tunnel:=true}" > /dev/null
echo "${test_ping_final:=true}" > /dev/null
echo "${default_router}" > /dev/null
echo "${continue_on_error:=false}" > /dev/null
## DEBIAN PACKAGES TO INSTALL:
## iodine (for /usr/sbin/iodine)
## iproute (for /bin/ip)
## ipcalc (for /usr/bin/ipcalc)
## dnsutils (for /usr/bin/dig)
## fping (for /usr/bin/fping)
## If local DNS server restricts to 512 byte packets then do this:
# ifconfig ${d} mtu 220
## default MTU is 1024
## Remaining issues:
## - avoid double ping when DNS server and local router are the same
echo ==== Creating IP-over-DNS tunnel over local network connection...
## Find a network interface
if [ -z ${interface} ]; then
interface=$(tail --lines=+3 /proc/net/wireless \
| head -1 | tr -d : | awk '{print $1}')
fi
if [ -z ${interface} ]; then
interface=$(ifconfig -a | egrep '^[^ ].*encap:Ethernet' \
| head -1 | awk '{print $1}')
fi
if [ -z ${interface} ]; then
echo ERROR: No network interface found
exit 1
fi
echo ==== Local network interface: ${interface}
## Down any existing DNS tunnel (wish there were "approved" way to do this)
echo ==== Killing existing DNS tunnels...
if killall --quiet --wait --verbose --signal HUP iodine; then
sleep 2
fi
## Stabilize local network
if ${bounce_localnet}; then
echo ==== Bouncing local network connection...
ifdown --force ${interface} || true
ifup ${interface} || ${continue_on_error}
fi
## Fetch some information about the local network
addr=$(ip -4 addr show dev ${interface} scope global | tail -1 | awk '{print
$2}')
prefix_len=$(echo ${addr} | sed 'sX^.*/XX')
local_net=$(ipcalc --nobinary ${addr} | awk '$1=="Network:" {print $2}')
echo ==== Local address: ${addr}
echo ==== Local network: ${local_net}
router=$(ip -4 route list dev ${interface} | awk '$1=="default" {print $3}' |
head -1)
if [ -z ${router} ]; then
## This can happen when the default local route is already deleted
echo WARNING: no default route, guessing local router IP address
if [ -z ${default_router} ]; then
## Minimum address on local net is usually right
router=$(ipcalc --nobinary ${addr} | awk '$1=="HostMin:" {print $2}')
else
## But sometimes ned to hardwire...
router=${default_router}
fi
fi
echo ==== Local network router: ${router}
## Test DNS service
testhost_ip=$(dig +short -t A -q ${testhost})
if [ -z ${testhost_ip} ]; then
echo WARNING: Failure on DNS lookup of ${testhost}
fi
## fetch DNS servers
nameservers=$(awk '$1=="nameserver" {print $2}' /etc/resolv.conf)
if [ -n "${nameservers}" ]; then
echo ==== DNS servers: ${nameservers}
else
echo ERROR: No DNS servers found
exit 1
fi
## Test if local network is up
if ${test_ping_localnet}; then
echo ==== Ping test of local network router and DNS servers...
fping -C1 ${router} ${nameservers} \
|| echo WARNING: Ping test failed.
fi
## Add point-to-point routes for any non-local DNS servers
for n in ${nameservers}; do
n_net=$(ipcalc --nobinary ${n}/${prefix_len} | awk '$1=="Network:" {print
$2}')
if [ "${n_net}" != "${local_net}" ]; then
echo ==== Adding point-to-point route for DNS server ${n}
ip -4 route add ${n}/32 via ${router} || ${continue_on_error}
fi
done
## Bring up DNS tunnel
echo ==== Creating IP-over-DNS tunnel...
iodine -P ${passwd} ${subdomain} || ${continue_on_error}
## Find DNS tunnel interface
tunnel_interface=$(ifconfig -a | egrep '^dns' | awk '{print $1}' | head -1)
if [ -z "${tunnel_interface}" ]; then
echo WARNING: Cannot find DNS tunnel interface, using default.
tunnel_interface=dns0
fi
echo ==== DNS tunnel interface: ${tunnel_interface}
## Figure out router at other end of tunnel, assuming router uses final octet .1
## (There should be some way to get this information out of iodine, since
## it *prints* it as it sets up the tunnel, so it does know it.)
tunnel_remote=$(ip -4 address show dev ${tunnel_interface} \
| awk '$1=="inet" {print gensub("[.][0-9]*/.*", ".1", 1, $2)}' | head -1)
if [ -z ${tunnel_remote} ]; then
echo ERROR: Cannot find DNS tunnel remote endpoint.
${continue_on_error}
## set something random if debugging
tunnel_remote=192.168.253.1
fi
echo ==== DNS tunnel remote endpoint: ${tunnel_remote}
if ${test_ping_tunnel}; then
echo ==== Ping test of local router, nameserver, and DNS tunnel...
fping -C1 ${router} ${nameservers} ${tunnel_remote} \
|| echo WARNING: Ping test failed.
fi
## Modify routing table to send trafic via DNS tunnel
echo ==== Setting default route through DNS tunnel...
## Remove default route via local router
ip -4 route del default via ${router} || ${continue_on_error}
## Add default via tunnel
ip -4 route add default via ${tunnel_remote} || ${continue_on_error}
## Test if all is well
if ${test_ping_final}; then
echo ==== Ping test of local router, nameserver, DNS tunnel, and external
test host...
fping -C1 ${router} ${nameservers} ${tunnel_remote}
${testhost_ip:-${testhost}} \
|| echo WARNING: Ping test failed.
fi