zx23 blog

Setting Up HE IPv6 Tunnel on FreeBSD

While this varies per country, most residential ISPs in the UK are far from offering an IPv6 service. Instead they seem to be dedicating a substantial amount of time to making promises of ‘delivering it in the future’. The latest from BT, one of the largest residential ISPs here, is ‘BT is thinking to offer IPv6 to their customers by the end of year 2015’. So they’re still thinking about it. And implementing Carrier Grade NAT. Good for them.

Meanwhile, lets setup an IPv6 tunnel with Hurricane Electric, using their Tunnel Broker service. Yes, its free and its awesome. Tunnel Broker service utilises the 6in4 mechanism to encapsulate IPv6 packets in IPv4 packets.

Once you’re signed up and logged in, navigate to Create Regular Tunnel page, enter your IPv4 address and choose a tunnel server. Understand that the closer the tunnel server is to you, the faster (in terms of latency) IPv6 connectivity you’ll get, so choose carefully and run ping / traceroute to candidate servers to determine the one that has the lowest latency.

When done, click Create Tunnel and wait a few seconds while some tests are run. For example, your public IP will need to be pingable, if it isn’t, you’ll be asked to allow it.

On the next page, Tunnel Details, give this tunnel a sensible description. Now we just need to setup our FreeBSD firewall. Lets use the following IPs in the example (you are the client and HE tunnel server is the server):

  • Server IPv4: 203.0.113.42
  • Server IPv6: 2001:db8:dead:beef::1
  • Client IPv4: 198.51.100.15
  • Client IPv6: 2001:db8:dead:beef::2

Here we creata gif(4) interface, assign IPv4 and v6 addresses and configure the default IPv6 gateway:

1
2
3
4
5
# ifconfig gif0 create
# ifconfig gif0 tunnel 198.51.100.15 203.0.113.42
# ifconfig gif0 inet6 2001:db8:dead:beef::2 2001:db8:dead:beef::1 prefixlen 128
# ifconfig gif0 inet6 -ifdisabled
# route -n add -inet6 default 2001:db8:dead:beef::1

If you are running w/o a firewall (wild wild west!) you should have full IPv6 connectivity, give it a go:

1
2
3
4
5
6
7
8
% traceroute6 google.com
traceroute6 to google.com (2a00:1450:4009:801::200e) from 2001:db8:dead:beef::2, 64 hops max, 12 byte packets
1  2001:db8:dead:beef::1  6.809 ms  6.793 ms  6.970 ms
2  v116.core1.lon2.he.net  10.978 ms  7.017 ms  17.997 ms
3  2001:7f8:4::3b41:1  7.484 ms  7.108 ms  7.487 ms
4  2001:4860::1:0:3067  7.466 ms  12.622 ms  7.474 ms
5  2001:4860:0:1::23  7.485 ms  7.364 ms  7.473 ms
6  2a00:1450:4009:801::200e  7.258 ms  7.373 ms  7.203 ms

Otherwise, lets add the following rules to our pf.conf so that traffic can pass through:

/etc/pf.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# create some useful macros
ext_if6="gif0"
v6_gw="203.0.113.42"

# enable logging on tunnel interface; we like to see what goes on
set loginterface $ext_if6

# allow icmp6 on the tunnel interface - this is required for the Neighbor
# Discovery Protocol to work
pass quick on $ext_if6 proto icmp6 all keep state label "icmp6"

# default block all incoming traffic on the tunnel interface, log and
# label for counters
block in log on $ext_if6 all label "block-all-external6"

# pass all outgoing traffic on the tunnel, label for counters
# note the use of 'keep state' rather than 'modulate state' - this is to
# work around a bug in PF IPv6 handling
pass out quick on $ext_if6 all keep state label "pass-all-external6"

# allow incoming and outgoing connections to the tunnel server IPv4
# address for protocol 41 (6in4)
pass in on $ext_if inet proto 41 from $v6_gw to $ext_if modulate state
pass out on $ext_if inet proto 41 from $ext_if to $v6_gw modulate state

Ok, now you’re good to test and make sure it all works as expected:

1
2
3
4
5
6
7
8
9
% ping6 -c 3 eff.org
PING6(56=40+8+8 bytes) 2001:db8:dead:beef::2 --> 2607:f258:102:3::2
16 bytes from 2607:f258:102:3::2, icmp_seq=0 hlim=58 time=150.981 ms
16 bytes from 2607:f258:102:3::2, icmp_seq=1 hlim=58 time=154.884 ms
16 bytes from 2607:f258:102:3::2, icmp_seq=2 hlim=58 time=164.709 ms

--- eff.org ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 150.981/156.858/164.709/5.776 ms

You can use tcpdump(1) on the external, non-tunnel, interface to see the 6in4 mechanism in action:

1
2
3
4
5
6
7
# tcpdump -ni em0 host 203.0.113.42
15:47:10.057887 IP 198.51.100.15 > 203.0.113.42: IP6 2001:db8:dead:beef::2 > 2607:f258:102:3::2: ICMP6, echo request, seq 0, length 16
15:47:10.222577 IP 203.0.113.42 > 198.51.100.15: IP6 2607:f258:102:3::2 > 2001:db8:dead:beef::2: ICMP6, echo reply, seq 0, length 16
15:47:11.063681 IP 198.51.100.15 > 203.0.113.42: IP6 2001:db8:dead:beef::2 > 2607:f258:102:3::2: ICMP6, echo request, seq 1, length 16
15:47:11.233365 IP 203.0.113.42 > 198.51.100.15: IP6 2607:f258:102:3::2 > 2001:db8:dead:beef::2: ICMP6, echo reply, seq 1, length 16
15:47:12.063405 IP 198.51.100.15 > 203.0.113.42: IP6 2001:db8:dead:beef::2 > 2607:f258:102:3::2: ICMP6, echo request, seq 2, length 16
15:47:12.220879 IP 203.0.113.42 > 198.51.100.15: IP6 2607:f258:102:3::2 > 2001:db8:dead:beef::2: ICMP6, echo reply, seq 2, length 16

And finally, lets not forget to add the required lines to /etc/rc.conf so that changes will work after a reboot - you are going to reboot this server to test your changes, right?

/etc/rc.conf
1
2
3
4
gif_interfaces="gif0"
gifconfig_gif0="198.51.100.15 203.0.113.42"
ifconfig_gif0_ipv6="inet6 2001:db8:dead:beef::2 2001:db8:dead:beef::1 prefixlen 128"
ipv6_defaultrouter="-iface gif0"

Comments