[Update] My own IPv6 tunnel broker.

Some days ago I needed to test a web application on its IPv6 support. But since my Internet service provider only gives me an IPv4 address, I was not able to test the application. So, I thought about registering at SixXS to get an IPv6 address. But then I thought about setting up my own broker. After some time I found a nearly perfect tutorial that uses OpenVPN.

I took the scripts from that tutorial and stored them on my server and client, set everything up as explained and … didn’t got it working :(. I must say, that I had limited time to completely understand what was going wrong, so I stop trying.

Last weekend I had some hours to work on the IPv6 tunnel broker again and finally got it working. So, here are my scripts and a short explanation.

Update: I did some improvements and enhancements on the scripts and pushed them to a Github repository. Feel free to fork and report issues.

Server

  • You need a dedicated OpenVPN account if your OpenVPN does not run as root. You must give this user full password-less sudo access to /sbin/ip: openvpn ALL=(ALL)  NOPASSWD: /sbin/ip

  • You must enable package forwarding for IPv6. Append net.ipv6.conf.all.forwarding = 1 to /etc/sysctl.conf.

    Warning

    If you automatically receive your IPv6 routes, you must set your v6 routes manually:

    $ ip -6 route add ::/0 via <IPv6-Gateway> dev <eth0>
    
  • You may need to activate Neighbor Discovery Proxy: Add net.ipv6.conf.all.proxy_ndp = 1 to your /etc/sysctl.conf

  • Copy the files client-connect-ipv6-broker.sh, client-disconnect-ipv6-broker.sh and ipv6-broker.sh to your server into the directory /etc/openvpn/ and make sure they are executable.

  • Append the lines from the server-ipv6.conf file to your OpenVPN server configuration.

Client

  • You need a dedicated OpenVPN account if your OpenVPN does not run as root. You must give this user full password-less sudo access to /sbin/ip: openvpn ALL=(ALL)  NOPASSWD: /sbin/ip
  • Copy the files up-ipv6-broker.sh, down-ipv6-broker.sh and ipv6-broker.sh to your client into the directory /etc/openvpn/ and make sure they are executable.
  • Append the lines from the client-ipv6.conf file to your OpenVPN client configuration.

The scripts

OpenVPN IPv6 Tunnel Broker

Copyright (c) 2012 Markus Holtermann

Copyright (c) 2011 Lyndsay Roger - https://www.zagbot.com/

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/.

ipv6-broker.sh

#!/bin/bash

# Your /64 Network prefix
export BASERANGE="1234:5678:90ab:cdef"
# The IPv4 address of your vpn server
export VPN_HOST="10.8.0.1"

export LOG_TAG="ipv6-broker"
export DEBUG=1

if [ -e "/etc/openvpn/client.conf" ] ; then
    export CLIENT=1
else
    export CLIENT=0
fi

if [ $CLIENT -eq 1 ] ; then
    export SITID="sit1"
    export V6NET="${BASERANGE}::$(echo ${ifconfig_local} | awk -F. '{printf "%02x%02x:%02x", $2, $3, $4}')"
else
    export SITID="sit$(echo ${ifconfig_pool_remote_ip} | awk -F. '{print $2"-"$3"-"$4}')"
    export V6NET="${BASERANGE}::$(echo ${ifconfig_pool_remote_ip} | awk -F. '{printf "%02x%02x:%02x", $2, $3, $4}')"
fi

client-connect-ipv6-broker.sh

#!/bin/bash

source /etc/openvpn/ipv6-broker.sh

# This is a script that is run each time a remote client connects
# to this openvpn server.
# it will setup the ipv6 tunnel depending on the ip address that was
# given to the client

# setup the sit between the local and remote openvpn addresses
test $DEBUG -eq 1 && echo "/sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}

# activate the tunnel device
test $DEBUG -eq 1 && echo "/sbin/ip link set dev ${SITID} up" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip link set dev ${SITID} up

# config routing for the new network
test $DEBUG -eq 1 && echo "/sbin/ip -6 addr add ${V6NET}01/124 dev ${SITID}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 addr add ${V6NET}01/124 dev ${SITID}

# add the route for the network
test $DEBUG -eq 1 && echo "/sbin/ip -6 route add ${V6NET}00/124 via ${V6NET}02 dev ${SITID} metric 1" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 route add ${V6NET}00/124 via ${V6NET}02 dev ${SITID} metric 1

# add neighbor discovering proxy for this interface
test $DEBUG -eq 1 && echo "/sbin/ip -6 neigh add proxy ${V6NET}02 dev eth0" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 neigh add proxy ${V6NET}02 dev eth0

# log to syslog
test $DEBUG -eq 1 && echo "${script_type} client_ip:${trusted_ip} common_name:${common_name} local_ip:${ifconfig_local} remote_ip:${ifconfig_pool_remote_ip} sit:${SITID} ipv6net:${V6NET}" | /usr/bin/logger -t $LOG_TAG
test $DEBUG -eq 1 && sudo /sbin/ip addr show | /usr/bin/logger -t $LOG_TAG
test $DEBUG -eq 1 && sudo /sbin/ip -6 route show | /usr/bin/logger -t $LOG_TAG

# needed for connection
exit 0

client-disconnect-ipv6-broker.sh

#!/bin/bash

source /etc/openvpn/ipv6-broker.sh

# remove neighbor discovering proxy again
test $DEBUG -eq 1 && echo "/sbin/ip -6 neigh del proxy ${V6NET}02 dev eth0" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 neigh del proxy ${V6NET}02 dev eth0

# remove the route
test $DEBUG -eq 1 && echo "/sbin/ip -6 route del ${V6NET}00/124 via ${V6NET}02 dev ${SITID} metric 1" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 route del ${V6NET}00/124 via ${V6NET}02 dev ${SITID} metric 1

# unset the ipv6 address
test $DEBUG -eq 1 && echo "/sbin/ip -6 addr del ${V6NET}01/124 dev ${SITID}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 addr del ${V6NET}01/124 dev ${SITID}

# deactivate the tunnel
test $DEBUG -eq 1 && echo "/sbin/ip link set dev ${SITID} down" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip link set dev ${SITID} down

# remove the tunnel interface
test $DEBUG -eq 1 && echo "/sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${ifconfig_pool_remote_ip} local ${ifconfig_local}

test $DEBUG -eq 1 && sudo /sbin/ip addr show | /usr/bin/logger -t $LOG_TAG
test $DEBUG -eq 1 && sudo /sbin/ip -6 route show | /usr/bin/logger -t $LOG_TAG

exit 0

up-ipv6-broker.sh

#!/bin/bash

source /etc/openvpn/ipv6-broker.sh

# script that is run on the client when it creates a tunnel to the remote OpenVPN server

test $DEBUG -eq 1 && echo "/sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${VPN_HOST} local ${ifconfig_local}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip tunnel add ${SITID} mode sit ttl 255 remote ${VPN_HOST} local ${ifconfig_local}

test $DEBUG -eq 1 && echo "/sbin/ip link set dev ${SITID} up" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip link set dev ${SITID} up

test $DEBUG -eq 1 && echo "/sbin/ip -6 addr add ${V6NET}02/124 dev ${SITID}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 addr add ${V6NET}02/124 dev ${SITID}

test $DEBUG -eq 1 && echo "/sbin/ip route add ::/0 via ${V6NET}01" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip route add ::/0 via ${V6NET}01

test $DEBUG -eq 1 && sudo /sbin/ip addr show | /usr/bin/logger -t $LOG_TAG
test $DEBUG -eq 1 && sudo /sbin/ip -6 route show | /usr/bin/logger -t $LOG_TAG

exit 0

down-ipv6-broker.sh

#!/bin/bash

source /etc/openvpn/ipv6-broker.sh

test $DEBUG -eq 1 && echo "/sbin/ip route del ::/0 via ${V6NET}01" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip route del ::/0 via ${V6NET}01

test $DEBUG -eq 1 && echo "/sbin/ip -6 addr del ${V6NET}02/124 dev ${SITID}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip -6 addr del ${V6NET}02/124 dev ${SITID}

test $DEBUG -eq 1 && echo "/sbin/ip link set dev ${SITID} down" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip link set dev ${SITID} down

test $DEBUG -eq 1 && echo "/sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${VPN_HOST} local ${ifconfig_local}" | /usr/bin/logger -t $LOG_TAG
sudo /sbin/ip tunnel del ${SITID} mode sit ttl 255 remote ${VPN_HOST} local ${ifconfig_local}

test $DEBUG -eq 1 && sudo /sbin/ip addr show | /usr/bin/logger -t $LOG_TAG
test $DEBUG -eq 1 && sudo /sbin/ip -6 route show | /usr/bin/logger -t $LOG_TAG

exit 0

Configuration

You finally need to add a few lines to your /etc/openvpn/server.conf

###########################################
# IPv6 tunnel broker
###########################################
script-security 2
client-connect /etc/openvpn/client-connect-ipv6-broker.sh
client-disconnect /etc/openvpn/client-disconnect-ipv6-broker.sh

And a few lines to your /etc/openvpn/client.conf:

#############################################
# IPv6 tunnel broker
#############################################
# need this so when the client disconnects it
# tells the server so the server can remove
# the ipv6 tunnel the client was using
explicit-exit-notify
script-security 2

# create the ipv6 tunnel
up /etc/openvpn/up-ipv6-broker.sh
down /etc/openvpn/down-ipv6-broker.sh