Creating a 6in4 router using Mac OS X 10.7

Hurricane Electric have a 6in4 tunnel service at Mac OS X 10.7 has built-in router advertisement and IPv6 routing support, but it needs some work to configure things to start on each boot.
This example uses the following (slightly made-up) details:

Tunnel info from HE:
  Server IPv4 Address:
  Server IPv6 Address: 2001:470:1f08:f23a::1/64
  Client IPv6 Address: 2001:470:1f08:f23a::2/64

Local IPv4 router address:
Local IPv6 /48 network assigned by HE: 2001:470:f23f::/48

First, enable IP6 forwarding:

mini:/Users/chrisl/ 1$ echo "net.inet6.ip6.forwarding=1" >> /etc/sysctl.conf

Next, create a script (/usr/bin/ipv6_tunnel) to configure the tunnel when the machine boots. Here is the general template:

route -n add -inet6 default TUNNELSERVERIPV6ADDRESS
ifconfig en0 inet6 LOCALIPV6ADDRESS prefixlen 64

So, example (where LOCALIPV6ADDRESS is the autoconfiguration address, given the prefix 2001:470:f23f::/48):

ifconfig gif0 tunnel
ifconfig gif0 inet6 2001:470:1f08:f23a::2 2001:470:1f08:f23a::1 prefixlen 128
route -n add -inet6 default 2001:470:1f08:f23a::1
ifconfig en0 inet6 2001:470:f23f::3e07:54ff:fe10:b870 prefixlen 64

Next, create two LaunchDaemons to start “rtadvd” for router advertisements and the above script to configure interfaces:

mini:/Users/chrisl/ 1$ cat /Library/LaunchDaemons/com.example.ipv6.rtadvd.plist 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
mini:/Users/chrisl/ 2$ cat /Library/LaunchDaemons/com.example.ipv6.tunnel.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

Finally, enable the LaunchDaemons to start on boot:

mini:/Users/chrisl/ 1$ sudo launchctl load -w /Library/LaunchDaemons/com.example.ipv6.rtadvd.plist 
mini:/Users/chrisl/ 2$ sudo launchctl load -w /Library/LaunchDaemons/com.example.ipv6.tunnel.plist 


  • I have assigned an IP from my /48 block to my en0, why is it that when I conenct to IPv6 sites, they see the IPv6 of the tunnel instead of the assigned IPv6 from my /48 block?

  • That’s because your machine now effectively has two externally facing interfaces, en0 and gif0. gif0 is the one that points towards the ipv6 internet so that’s the one the routing table uses to originate packets from.

  • Is there a way to make applications make use of the assigned IPv6 on en0?

  • Not without some odd routing rules, possibly involving NAT. If you wanted to use a particular IPv6 address from your /48 for incoming traffic then you could alias that address on gif0, like:
    mini:/Users/chrisl/ 1$ sudo ifconfig gif0 inet6 2001:470:f23f::3e07:54ff:fe10:b111 alias up

    and then your gif0 would look like this:
    gif0: flags=8051 mtu 1280
    tunnel inet –>
    inet6 fe80::2a37:37ff:fe16:d97d%gif0 prefixlen 64 scopeid 0x2
    inet6 2001:470:1f08:f23a::2 –> 2001:470:1f08:f23a::1 prefixlen 128
    inet6 2001:470:f23f::3e07:54ff:fe10:b111 prefixlen 64

  • I had used a similar setup in Snow Leopard, and everything worked fine (aside from a bug in rtadvd that led to OS X losing the default v6 route), however since updating to Lion I haven’t been able to have rtadvd run properly. It starts and stays running, the route stays in place, but it just won’t pass v6 configuration to other machines. I also can’t get it to log anything (even when using -d or -D), neither to stdout/stderr when using -f, nor to /var/log/system.log. In SL, even the iPhone on both iOS 4 and iOS 5 easily got an IPv6 address using rtadvd.
    What do you have in /etc/rtadvd.conf?

  • I actually have nothing in rtadvd.conf, I’m letting it guess what to do based on the existing routes. Do you have net.inet6.ip6.forwarding=1 in /etc/sysctl.conf and is that set to 1 if you run ‘sysctl net.inet6.ip6.forwarding’ ?
    I don’t have anything in my log files either for rtadvd (apart from launchd information saying it started up).

  • I actually have sysctl setting net.inet6.ip6.forwarding to 1 directly in the script I use at launch, however after some fiddling yesterday I managed to make it work. I am not sure what I did exactly, though, aside from going to System Preferences and enabling IPv6 for en0, as it was mysteriously set to Off.

    In any event, something apparently changed in Lion because I am 100% confident that in Snow Leopard you could set ipv6 addresses on en0 manually and they would work out of the box. Now, after removing the line that set net.inet6.ip6.accept_rtadv to 0 (so I reckon the default is 1), this same machine gets two ipv6 addresses for en0 – one is autoconf, the other is autoconf temporary –, but there are some routing issues because I can’t reach them from outside, nor I can contact anything else using those as a source. The routing table for those entries show the interface being lo0, so it may actually be a bug. Using route to change it to en0 doesn’t seem to cause any significant effect, as it just keeps not working.
    Adding my own addresses to gif0 works as expected, the routing table being automatically updated.

    A little extra info that may be of interest to your readers: if your ISP assigns you a dynamic IPv4 (as it’s the norm at least here in Italy), you can use wget or curl to change your IPv4 endpoint for your HE tunnel by accessing Opening that page without extra parameters shows how to use the service.

  • A while ago, I turned IPv6 off on my MBP (including sysctl -w net.inet6.ip6.accept_rtadv=0), but today I’ve decided to turn it back on, and I’ve got issues.

    Perhaps you guys can help.

    When I boot the Mac, the en1 interface gets an global address prefix from my local gateway and it autogenerates a local IPv6 address. However, it refuses to send IPv6 packets (e.g. when I run ping6 -I en1 towards the local gateway).

    If I disable the interface, then re-enable it (e.g. turn wifi off, then on, or ifconfig en1 down/up), it won’t assign a global address IPv6 address (only link-local).

    Also, weirdness:

    $ ping6 -I en1 ff02::1
    PING6(56=40+8+8 bytes) fe80::9227:e4ff:fef9:6b6a%en1 –> ff02::1
    ping6: sendmsg: Operation not permitted
    ping6: wrote ff02::1 16 chars, ret=-1

    $ sudo rtsold -d -f en1
    checking if en1 is ready…
    en1 is ready
    send RS on en1, whose state is 2
    sendmsg on en1: Operation not permitted

    I’m running Lion, with firewalling turned off, so I’m at wits end here.


  • Might be worth checking firewalling really is off, with “sudo ip6fw show” to see if there’s anything other than ‘allow ipv6 from any to any’. “Operation not permitted” is going to be some sort of kernel/driver/firewall issue, so here’s all my sysctl parameters for net.inet6.ip6 too, in case there’s some corruption with your kernel settings that’s causing this:

    imac:/Users/chrisl/ 12$ sysctl -a net.inet6.ip6
    net.inet6.ip6.forwarding: 0
    net.inet6.ip6.redirect: 1
    net.inet6.ip6.hlim: 64
    net.inet6.ip6.maxfragpackets: 1536
    net.inet6.ip6.accept_rtadv: 0
    net.inet6.ip6.keepfaith: 0
    net.inet6.ip6.log_interval: 5
    net.inet6.ip6.hdrnestlimit: 15
    net.inet6.ip6.dad_count: 1
    net.inet6.ip6.auto_flowlabel: 1
    net.inet6.ip6.defmcasthlim: 1
    net.inet6.ip6.gifhlim: 0
    net.inet6.ip6.kame_version: 2009/apple-darwin
    net.inet6.ip6.use_deprecated: 1
    net.inet6.ip6.rr_prune: 5
    net.inet6.ip6.v6only: 0
    net.inet6.ip6.rtexpire: 315
    net.inet6.ip6.rtminexpire: 10
    net.inet6.ip6.rtmaxcache: 128
    net.inet6.ip6.use_tempaddr: 1
    net.inet6.ip6.temppltime: 86400
    net.inet6.ip6.tempvltime: 604800
    net.inet6.ip6.auto_linklocal: 1
    net.inet6.ip6.prefer_tempaddr: 1
    net.inet6.ip6.use_defaultzone: 0
    net.inet6.ip6.maxfrags: 12288
    net.inet6.ip6.mcast_pmtu: 0
    net.inet6.ip6.neighborgcthresh: 1024
    net.inet6.ip6.maxifprefixes: 16
    net.inet6.ip6.maxifdefrouters: 16
    net.inet6.ip6.maxdynroutes: 1024
    net.inet6.ip6.fw.enable: 1
    net.inet6.ip6.fw.debug: 0
    net.inet6.ip6.fw.verbose: 0
    net.inet6.ip6.fw.verbose_limit: 0
    net.inet6.ip6.scopedroute: 1
    net.inet6.ip6.select_srcif_debug: 0
    net.inet6.ip6.mcast.maxgrpsrc: 512
    net.inet6.ip6.mcast.maxsocksrc: 128
    net.inet6.ip6.mcast.loop: 1
    net.inet6.ip6.only_allow_rfc4193_prefixes: 0

  • Aye; the IPv6 firewall is off, or rather, it is enabled, but has

    $ sudo ip6fw show
    65535 53524 249326407 allow ipv6 from any to any

    in it. I’m not running LittleSnitch or similar.

    The only difference in the sysctl is net.inet6.ip6.rtexpire, which is set to 1 hour (3600).

    Since I wrote my previous entry, I’ve reinstalled MacOS (migrated everything but “Settings” from TimeMachine), but to no avail. It’ll get an IPv6 global address (from local gw), but cannot reach it. After a while (1 hour?) the IPv6 address is removed from the interface and only the link local is left.

    Weirder still, if I boot into recovery, I can ssh/ping6 the gw and the rest of the world just fine.


  • How about something that’s interfering with the network system, like Parallels or VirtualBox’s network drivers? Got anything like that installed?

  • Hm, no. But you got me thinking.

    $ sudo kextstat |grep -v
    Index Refs Address Size Wired Name (Version)
    100 0 0xffffff7f818fc000 0x2d000 0x2d000 com.checkpoint.cpfw (1.0)

    ^- “wtf is this,” I thought to myself, “I don’t run ..” — well, apparently I did, it’s bundled as part of the Checkpoint VPN client. Well, after a quick kill of the client and a kextunload — it works!

    Thanks for the help!


  • Leave a comment