Overview
Adding IPv6 support to a FreeBSD-based home router is relatively simple. First, you have to obtain an initial IPv6 address for the router by using autoconfiguration. In Time Warner's case, this is a /128 address. Then, you have to install and configure a dhcp6 client to obtain an IPv6 prefix to number the internal network with. Finally, you have to adjust ipfw so that IPv6 traffic is forwarded correctly.
My home network
My home router running FreeBSD 10.1 is relatively simple. First, I have an interface em1 that is plugged into my cable modem. That interface receives an IPv4 dhcp lease, and accepts IPv6 router advertisements to obtain an initial IPv6 address with. Second, I have an interface wlan0 which is an atheros wireless interface in hostapd mode (i.e. my home wireless network). I run ISC's dhcp server on that interface so that devices can obtain an RFC1918 address on the network, and FreeBSD's built-in IPv6 router advertisement daemon rtadvd so that devices can auto-configure an IPv6 address. Finally, I have an interface vr0 which is an internal PCI ethernet switch which my TV, blu-ray player, and Xbox 360 are plugged into. I also run ISC's dhcp server on that interface, but do not run rtadvd on that interface because none of the devices on that network support IPv6.
/etc/rc.conf
The following is what I added to my /etc/rc.conf to support IPv6.
ipv6_gateway_enable="YES" ipv6_cpe_wanif="em1" ifconfig_em1_ipv6="inet6 -ifdisabled accept_rtadv" ifconfig_wlan0_ipv6="inet6 -ifdisabled auto_linklocal" dhcp6c_enable="YES" dhcp6c_interfaces="em1" rtadvd_enable="YES" rtadvd_interfaces="wlan0"The first line configures the host as an IPv6 gateway (router). Because routers do not accept IPv6 router advertisements by default, the second line configures the router to accept router advertisements on em1, which is the interface plugged into the cable modem. The third line tells FreeBSD to enable IPv6 on the em1 interface, even though we have not configured an address on it. The fourth line also tells FreeBSD to enable IPv6 on the wlan0 interface, and to configure a link-local address on it. The fifth and sixth lines enable a DHCPv6 client, which solicits a prefix on em1; the client has to be installed from ports, and can be found in /usr/ports/net/dhcp6. Finally, the seventh and eighth lines enable FreeBSD's built-in IPv6 router advertisement daemon, and causes advertisements to be made on wlan0.
Installing and configuring dhcp6
To begin with, install /usr/ports/net/dhcp6 from ports. Then, create a /usr/local/etc/dhcp6c.conf file that is tailored to your needs.
interface em1 { send ia-pd 1; send ia-na 1; }; id-assoc na 1 { }; id-assoc pd 1 { prefix ::/56 infinity; prefix-interface wlan0 { sla-id 1; sla-len 8; }; };The important blocks are the first and the last. The first block tells the DHCPv6 client to solicit a prefix using em1. By default, Time Warner returns a /56 prefix. The last block asks for a permanent lease of a /56 prefix, and configures a /64 prefix on wlan0 (56 + 8 = 64). If I wanted to add a second /64 prefix to vr0, I'd add:
prefix-interface vr0 { sla-id 2; sla-len 8; };The important line is sla-id 2: it allocates the second /64 block from whatever /56 prefix was delegated to vr0.
Configuring IPFW
My firewall rules script is as follows.
############ # Set quiet mode if requested # case ${firewall_quiet} in [Yy][Ee][Ss]) fwcmd="/sbin/ipfw -q" ;; *) fwcmd="/sbin/ipfw" ;; esac fw="${fwcmd} add" wi_if="wlan0" natd_if="em1" sw_if="vr0" netbios="137,138,139" #clear the ruleset ${fwcmd} -f flush # Allow all traffic on the local network. ${fw} 501 pass ip from any to any via lo0 ${fw} 503 pass ip from any to any via ${wi_if} ${fw} 504 pass ip from any to any via ${sw_if} ${fw} 510 pass ip from me to not me out via ${natd_if} # NAT ${fw} 550 divert natd ip4 from any to any via ${natd_if} # TCP ${fw} 601 pass tcp from any to any out xmit ${natd_if} setup ${fw} 602 pass tcp from any to any via ${natd_if} established # UDP ${fw} 700 deny udp from any to any ${netbios} out xmit ${natd_if} ${fw} 701 deny udp from any ${netbios} to any in recv ${natd_if} ${fw} 702 pass udp from any to any out xmit ${natd_if} ${fw} 703 pass udp from any domain to any in recv ${natd_if} ${fw} 704 pass udp from any ntp to any in recv ${natd_if} ${fw} 706 pass udp from any to not me in recv ${natd_if} ${fw} 707 pass udp from not me 547 to me 546 in recv ${natd_if} # Pass fragments ${fw} 750 pass ip from any to any frag # ICMP ${fw} 801 pass icmp from any to any ${fw} 802 pass icmp6 from any to any ${fw} 1000 unreach filter-prohib log ip from any to anyThe firewall script is a fairly vanilla firewall configuration that denys most types of packets directed to the router, but there are four very important considerations. First, you must only divert IPv4 packets to the natd process by specifying ip4. If you divert all IP packets (with ip as seen in rules 501, 503, 504, and 510) to the natd process, it will drop IPv6 packets on the floor and you will have no IPv6. Second, rule 707 allows DHCPv6 responses back in. If you do not have that rule, you will not obtain a prefix delegation. Third, rule 750 passes fragments. This is important because DNSSEC can cause DNS responses to be large and fragmented. If you do not pass fragments then those responses will be discarded. Fourth, rule 802 passes ICMPv6 packets. This is important to obtain the initial router advertisement packets to configure an IPv6 address on em1.
Summary
With any luck, when you reboot the router IPv6 will just work and devices on your network will obtain IPv6 addresses. You can check this is happening by inspecting the neighbor discovery cache on the router with "ndp -an".