Date Tags linux / bash

Since I run a server for hosting my websites and providing mail, I decided to setup tunnel service as well. Just in case I get stuck in an airport with limited internet access. Initially, I chose ICMP as the tunneling protocol, but more will follow later.

Server Setup

The server is used as the tunnel endpoint, and must always be running the tunnel service, as you never know when you will need it. To accomplish this, I installed hans and configured it using systemd.

First install by compiling from source or, if running Arch Linux, using the PKGBUILD. Then install the following systemd-service to /etc/systemd/system/hans.service:

hans.service download

Description=ICMP Tunneling Daemon


ExecStart=/usr/bin/hans -s $HANS_IP -d $HANS_DEV -p $HANS_PASS

ExecStartPost=/usr/bin/ip link set dev $HANS_DEV mtu 1200
ExecStartPost=/usr/bin/sysctl -w net.ipv4.ip_forward=1
ExecStartPost=/usr/bin/iptables -t nat -A POSTROUTING -o $HANS_WAN -j MASQUERADE
ExecStartPost=/usr/bin/iptables -A FORWARD -i $HANS_DEV -j ACCEPT

ExecStopPost=/usr/bin/iptables -D FORWARD -i $HANS_DEV -j ACCEPT
ExecStopPost=/usr/bin/iptables -t nat -D POSTROUTING -o $HANS_WAN -j MASQUERADE


The service file sets up hans and configures NAT-routing on virtual interface created by hans. It expects a config file in /etc/conf.d/hans:

hans download


Now change the password in /etc/conf.d/hans and test the service with systemctl:

# systemctl start hans

If systemd doesn't complain, you can enable the service at boot time:

# systemctl enable hans

The server is now ready to accept tunnel-connections from the outside.

Client Setup

Since we use ICMP tunneling only occasionally, we don't need hans to run as a service on our clients. Instead I cooked a little bash script to start hans and configure the network to use the tunnel as default internet connection: download


ip=$(host -t A $host | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
gw=$(ip route | grep default | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
wan=$(ip route | grep default | grep -E -o "dev [a-z]+[0-9]+")

if [ $UID -ne 0 ]; then
    echo Must be root
    exit 1

echo starting icmp tunnel
hans -c $host -p $pass -d $hans_dev || exit 1

echo decreasing mtu
ip link set dev $hans_dev mtu 1200 || exit 1

echo waiting for hans to connect
while sleep 1; do
    if ip addr show dev $hans_dev | grep -q inet; then

echo adding route to icmp server
if ip route | grep -q $ip; then
    ip route del $ip || exit 1
ip route add $ip via $gw $wan || exit 1

echo changing default route to icmp tunnel
if ip route | grep -q default; then
    ip route del default via $gw $wan || exit 1
ip route add default via $hans_gw dev $hans_dev || exit 1

echo "Done"
echo ""
echo "To revert to primary connection, execute the following:"
echo "  # killall hans"
echo "  # ip route add default via $gw $wan"

The script starts hans with the parameters in the top of the script (don't forget to change the hostname and password), and then configures a route to run the tunnel on, and finally sets the default route to use the tunnel for everything else.

Happy tunneling!