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

Reply via email to