Friday, September 24, 2021
Username: Password:
Added by unreal
In less than 230 days, no more new IPv4 blocks will be available. Despite the fact that many IP operators have already deployed IPv6 on their backbones, native IPv6 connectivity is taking a long time to reach end users. Limited native IPv6 availability does not encourage content providers to migrate their services to a dual IPv4/IPv6 stack. In this context, an IPv6 tunnel appears to be an ideal transition solution that is cheap and easy to deploy.

In this article, we are going to configure a FreeBSD machine to use a tunnel to provide safe IPv6 connectivity to local network computers.


We are going to use a FreeBSD 8.1 machine with a single NIC (em0), connected to our local area network. IPv4 connectivity is provided via a virtual interface (vlan1), whos parent interface is em0.

Basic tunnel configuration

There are several IPv6 tunnel providers. We are going to use the Hurricane Electric Tunnelbroker service because it offers several useful options such as RDNS delegation and multiple subnet allocation.

Start by creating an account on HE's website.

Choose "Create Regular Tunnel" and enter your (static) IPv4 address. You can now create a routed /64 prefix and generate the configuration file for many OS's, including FreeBSD. In this example we'll assume that your public IP is and that your alloted /64 is 2001:11:22:33::/64.

Enter the following commands (after changing the various IP addresses):

ifconfig gif0 create
ifconfig gif0 tunnel
ifconfig gif0 inet6 2001:11:22:33::2 2001:11:22:33::1 prefixlen 128
route -n add -inet6 default 2001:11:22:33::1
ifconfig gif0 up

Ifconfig can be used to verify the tunnel has been created:

# ifconfig gif0
gif0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1280
        tunnel inet -->
        inet6 fe80::219:d1ff:fe7a:7437%gif0 prefixlen 64 scopeid 0x6
        inet6 2001:11:22:33::2 prefixlen 64

Finally, use the ping6 command to check the tunnel is working:

# ping6 -c 1
PING6(56=40+8+8 bytes) 2001:11:22:33::2 --> 2a01:e0c:1:1599::1
16 bytes from 2a01:e0c:1:1599::1, icmp_seq=0 hlim=55 time=51.311 ms

--- ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 51.311/51.311/51.311/0.000 ms

If the ping command does not work and you are using a firewall on your gateway, you might need to configure it to allow tunneled IP traffic. Here's an example using PF to allow the tunnel (replace with the IP of your tunnel's endpoint):

# IPv6 Tunnel
pass out on $nc_if inet proto 41 from any to keep state
pass in on $nc_if inet proto 41 from to any keep state

Assuming this part works, let's move on to providing IPv6 connectivity to your local network.

Subnet routing

Open the Tunnelbroker interface again and allocate a routed /48; we'll use a smaller /64 subnet from this /48 to connect the local network. In this example we'll assume the alloted /48 subnet is 2001:44:55::/48 and that the /64 "LAN" subnet is 2001:44:55:1::/64.

Start by configuring an IP from the "LAN" subnet on the em0 interface::

ifconfig em0 inet6 2001:44:55:1::1 prefixlen 64

To activate kernel routing between the "LAN" subnet and the "WAN" subnet, you will need to enable IP forwarding:

sysctl -w net.inet6.ip6.forwarding=1

To check everything is working correctly, manually configure an IPv6 address (for example 2001:44:55:1::2) on a computer connected to the "LAN" network and use the traceroute command:

$ traceroute6 -n
traceroute6 to (2a01:e0c:1:1599::1) from 2001:44:55:1::2, 64 hops max, 12 byte packets
1 2001:44:55:1::1 0.366 ms 0.301 ms 0.285 ms
2 2001:11:22:33::1 33.619 ms 27.855 ms 29.953 ms
3 2001:470:0:7b::1 27.837 ms 29.885 ms 28.257 ms

We can see the IP of the router (2001:44:55:1::1), and after that, the IP on the endpoint (2001:11:22:33::1).

IPv6 filtering with PF

By now you should have a operational routed IPv6 network. However, it cannot be considered 'safe' as all IP addresses are public and no IP filtering is occuring. To rectify this, we shall use PF to provide router-level filtering. To make this example as clear as possible, only rules associated with the IPv6 tunnel are listed in the example below:

ipv6_if = "gif0"
macmini_v6 = "2001:44:55:1::2"
macmini_web_ports = "{ 80, 443 }"
ext_server = "2a02:1:2:3::4"

# <IPv6>
# Block all by default
block on $ipv6_if all

pass in on $ipv6_if proto icmp6 all keep state
pass out on $ipv6_if proto icmp6 all keep state

# Inward connections.
pass in on $ipv6_if proto tcp from any to $macmini_v6 \
                        port $macmini_web_ports flags S/SA keep state \
                        (max-src-conn-rate 100/5)
pass in on $ipv6_if inet6 proto tcp from $ext_server to any port 22 keep state

# Outward connections.
pass out on $ipv6_if inet6 proto tcp all keep state
pass out on $ipv6_if inet6 proto udp all keep state
# </IPv6>

This configuration denies all incoming traffic except ICMP, Web to "macmini_v6" and SSH to "ext_server". ICMP, TCP and UDP outgoing traffic is allowed.


One of the very useful features of IPv6 is auto-configuration that allows machines to receive static IPs without the use of DHCP, thanks to the MAC addresses of their network cards. FreeBSD provides this feature using the router advertisement daemon or rtadvd. To configure it, edit rc.conf and rtadvd.conf :


    :addrs#1:addr="2001:44:55:1::": prefixlen#64:tc=ether:

Start the rtadvd daemon to enable IPv6 autoconf.

Automatic starting of services

So that everything starts automatically with the system, we'll add some stuff to rc.conf :

# Network
ifconfig_em0="inet netmask"
cloned_interfaces="vlan0 vlan1"
ifconfig_vlan0="vlan 2 vlandev em0"
ifconfig_vlan1="DHCP vlan 4 vlandev em0"

# IPv6
ipv6_network_interfaces="lo0 em0 gif0"
ipv6_ifconfig_em0="2001:44:55:1::1 prefixlen 64"
ipv6_defaultrouter="-interface gif0"

# PF
pf_enable="YES"                 # Enable PF (load module if required)
pf_rules="/etc/pf.conf"         # rules definition file for pf
pf_flags=""                     # additional flags for pfctl startup
pflog_enable="YES"             # start pflogd(8)
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile
pflog_flags=""                 # additional flags for pflogd startup

Next time you reboot the machine, everything should start automatically.


Using a tunnelbroker service, it is fairly simple to deploy a transition IPv6 network, until more durable solutions come along (like native IPv6).


- 20th October 2010: first version

Posted on 20/10/10 at 15:46

IPv6 routing using FreeBSD
You could comment this news if you had an account!