NOTE: This article was replaced on 2019-03-12 by a github repository where I now use Vagrant instead of a Raspberry Pi, because I was having some power issues with my Raspberry Pi. Also, using this method means I can easily use an Ansible Playbook. The following config will still work(!) however I prefer this Vagrant/Ansible workflow for this, so won’t update this blog post any further.
Following an off-hand remark from a colleague at work, I decided I wanted to set up a Raspberry Pi as a Hurricane Electric IPv6 6in4 tunnel router. Most of the advice around (in particular, this post about setting up IPv6 on the Raspberry Pi Forums) related to earlier version of Raspbian, so I thought I’d bring it up-to-date.
I installed the latest available version of Raspbian Stretch Lite (2018-11-13) and transferred it to a MicroSD card. I added the file ssh
to the boot volume and unmounted it. I then fitted it into my Raspberry Pi, and booted it. While it was booting, I set a static IPv4 address on my router (192.168.1.252) for the Raspberry Pi, so I knew what IP address it would be on my network.
I logged into my Hurricane Electric (HE) account at tunnelbroker.net and created a new tunnel, specifying my public IP address, and selecting my closest HE endpoint. When the new tunnel was created, I went to the “Example Configurations” tab, and selected “Debian/Ubuntu
” from the list of available OS options. I copied this configuration into my clipboard.
I SSH’d into the Pi, and gave it a basic config (changed the password, expanded the disk, turned off “predictable network names”, etc) and then rebooted it.
After this was done, I created a file in /etc/network/interfaces.d/he-ipv6
and pasted in the config from the HE website. I had to change the “local” line from the public IP I’d provided HE with, to the real IP address of this box. Note that any public IPs (that is, not 192.168.x.x addresses) in the config files and settings I’ve noted refer to documentation addressing (TEST-NET-2 and the IPv6 documentation address ranges)
auto he-ipv6
iface he-ipv6 inet6 v4tunnel
address 2001:db8:123c:abd::2
netmask 64
endpoint 198.51.100.100
local 192.168.1.252
ttl 255
gateway 2001:db8:123c:abd::1
Next, I created a file in /etc/network/interfaces.d/eth0
and put the following configuration in, using the first IPv6 address in the “routed /64” range listed on the HE site:
auto eth0
iface eth0 inet static
address 192.168.1.252
gateway 192.168.1.254
netmask 24
dns-nameserver 8.8.8.8
dns-nameserver 8.8.4.4
iface eth0 inet6 static
address 2001:db8:123d:abc::1
netmask 64
Next, I disabled the DHCPd service by issuing systemctl stop dhcpcd.service
Late edit (2019-01-22): Note, a colleague mentioned that this should have actually been systemctl stop dhcpcd.service && systemctl disable dhcpcd.service
– good spot! Thanks!! This ensures that if, for some crazy reason, the router stops offering the right DHCP address to me, I can still access this box on this IP. Huzzah!
I accessed another host which had IPv6 access, and performed both a ping and an SSH attempt. Both worked. Fab. However, this now needs to be blocked, as we shouldn’t permit anything to be visible downstream from this gateway.
I’m using the Uncomplicated Firewall (ufw) which is a simple wrapper around IPTables. Let’s create our policy.
# First install the software
sudo apt update && sudo apt install ufw -y
# Permits inbound IPv4 SSH to this host - which should be internal only.
# These rules allow tailored access in to our managed services
ufw allow in on eth0 app DNS
ufw allow in on eth0 app OpenSSH
# These rules accept all broadcast and multicast traffic
ufw allow in on eth0 to 224.0.0.0/4 # Multicast addresses
ufw allow in on eth0 to 255.255.255.255 # Global broadcast
ufw allow in on eth0 to 192.168.1.255 # Local broadcast
# Alternatively, accept everything coming in on eth0
# If you do this one, you don't need the lines above
ufw allow in on eth0
# Setup the default rules - deny inbound and routed, permit outbound
ufw default deny incoming
ufw default deny routed
ufw default allow outgoing
# Prevent inbound IPv6 to the network
# Also, log any drops so we can spot them if we have an issue
ufw route deny log from ::/0 to 2001:db8:123d:abc::/64
# Permit outbound IPv6 from the network
ufw route allow from 2001:db8:123d:abc::/64
# Start the firewall!
ufw enable
# Check the policy
ufw status verbose
ufw status numbered
Most of the documentation I found suggested running radvd
for IPv6 address allocation. This basically just allocates on a random basis, and, as far as I can make out, each renewal gives the host a new IPv6 address. To make that work, I performed apt-get update && apt-get install radvd -y
and then created this file as /etc/radvd.conf
. If all you want is a floating IP address with no static assignment – this will do it…
interface eth0
{
AdvSendAdvert on;
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
prefix 2001:db8:123d:abc::/64
{
AdvOnLink on;
AdvAutonomous on;
};
route ::/0 {
};
};
However, this doesn’t give me the ability to statically assign IPv6 addresses to hosts. I found that a different IPv6 allocation method will do static addressing, based on your MAC address called SLAAC (note there are some privacy issues with this, but I’m OK with them for now…) In this mode assuming the prefix as before – 2001:db8:123d:abc::
and a MAC address of de:ad:be:ef:01:23
, your IPv6 address will be something like: 2001:db8:123d:abc:dead:beff:feef:0123
and this will be repeatably so – because you’re unlikely to change your MAC address (hopefully!!).
This SLAAC allocation mode is available in DNSMasq, which I’ve consumed before (in a Pi-Hole). To use this, I installed DNSMasq with apt-get update && apt-get install dnsmasq -y
and then configured it as follows:
interface=eth0
listen-address=127.0.0.1
# DHCPv6 - Hurricane Electric Resolver and Google's
dhcp-option=option6:dns-server,[2001:470:20::2],[2001:4860:4860::8888]
# IPv6 DHCP scope
dhcp-range=2001:db8:123d:abc::, slaac
I decided to move from using my router as a DHCP server, to using this same host, so expanded that config as follows, based on several posts, but mostly centred around the MAN page (I’m happy to have this DNSMasq config improved if you’ve got any suggestions ;) )
# Stuff for DNS resolution
domain-needed
bogus-priv
no-resolv
filterwin2k
expand-hosts
domain=localnet
local=/localnet/
log-queries
# Global options
interface=eth0
listen-address=127.0.0.1
# Set these hosts as the DNS server for your network
# Hurricane Electric and Google
dhcp-option=option6:dns-server,[2001:470:20::2],2001:4860:4860::8888]
# My DNS servers are:
server=1.1.1.1 # Cloudflare's DNS server
server=8.8.8.8 # Google's DNS server
# IPv4 DHCP scope
dhcp-range=192.168.1.10,192.168.1.210,12h
# IPv6 DHCP scope
dhcp-range=2001:db8:123d:abc::, slaac
# Record the DHCP leases here
dhcp-leasefile=/run/dnsmasq/dhcp-lease
# DHCPv4 Router
dhcp-option=3,192.168.1.254
So, that’s what I’m doing now! Hope it helps you!
Late edit (2019-01-22): In issue 129 of the “Awesome Self Hosted Newsletter“, I found a post called “My New Years Resolution: Learn IPv6“… which uses a pfSense box and a Hurricane Electric tunnel too. Fab!
Header image is “www.GetIPv6.info decal” by “Phil Wolff” on Flickr and is released under a CC-BY-SA license. Used with thanks!