This Mini-HOWTO is a very brief discussion of what I had to do to get ipv6 working on my internal lan so that everybody could access outside ipv6 addresses, yet prevent people from outside being able to connect back in to our internal network. It works by having one Linux box act as the ipv6 gateway and tunnel ipv6 traffic to a tunnel broker (several free ones are available), and it can tunnel with either a direct internet connection, a firewalled internet connection, or a NAT'ed internet connection, and it will handle all of these automatically. This Mini-HOWTO discusses using CentOS, Mandriva, and Gentoo as both the gateway and as clients.
  1. Register an account at go6.net. (There are several ipv6 tunnel brokers out there that will give you a free ip or netblock, but I chose to use go6.net and this Mini-HOWTO is based on that assumption.) There was no rocket science in my choice for go6.net over, for example, sixxs.net. It was simply the first one I stumbled upon when I Googled for ipv6 broker. They all seem to be equal in terms of what they offer, differing only slightly in how they go about offering it to you.
  2. Decide which machine is going to be the gateway machine. There are some very specific requirements. First, it must have a fairly recent kernel and iptables. At one location I'm using a Gentoo box with kernel 2.6.23 and iptables 1.4.0. At another location I'm using a Mandriva box with kernel 2.6.22 and iptables 1.3.7. It should also work with the latest Fedora Core release, as well as the latest CentOS 5 or RedHat EL 5 release. This machine will need to have ipv6 support enabled and ipv6 autoconfiguration enabled. In the case of my Ubuntu box, this results in an eth0 interface that looks like this:
    # ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:90:27:E0:0A:00 inet addr: Bcast: Mask: inet6 addr: fe80::290:27ff:fee0:a00/64 Scope:Link
    The "Scope:Link" address is an automatically generated ipv6 address that is designed to work ONLY on the local LAN. (network fe80::/16) Step 14 shows what the ethernet IPs will look like once this procedure is finished.
  3. Install the radvd package. For Gentoo, 'emerge radvd'. For CentOS, configure and enable the DAG repo and 'yum install radvd'. For Mandriva, it takes a few extra steps.
    useradd radvd mkdir /var/run/radvd chown radvd:radvd /var/run/radvd
  4. Download the source for gw6c from go6.net (aka freenet6.net). At the time of this writing (Jan 2008), the current version of gw6c is 5.1. gw6c is an abbreviation for Gateway 6 Client, the name of the software we'll be using. Gentoo users can 'emerge freenet6' if you choose, but you'll have to know where your config files are because they'll be different than what I describe here.
  5. When you extract gw6c tarball, it will extract into the current directory, so force it to extract into a subdirectory to keep the current directory clean:
    mkdir gw6c tar -zxvf gw6c*tar.gz -C gw6c/
  6. Compile and install the source:
    cd gw6c/tspc-advanced make target=linux make target=linux install installdir=/usr/local/gw6c
  7. Get the configuration in a place suitable for configs:
    cd /usr/local/gw6c mkdir logs mkdir etc mv bin/gw6c.conf* etc/
  8. Edit the configuration. Leave the defaults unchanged except for:
    userid -> the user you registered at go6.net passwd -> and the password for that user server=broker.freenet6.net auth_method=any host_type=router if_prefix -> the ethernet interface facing your local LAN log_file=2 log_filename=/usr/local/gw6c/logs/gw6c.log
  9. Create an init script for the gw6c service in /etc/init.d/gw6c or use one of the following init scripts (current as of Jan 2008). These init scripts take into account that the radvd service will be started by gw6c, and shuts it down. You do *NOT* want to start the radvd service from the init script nor at boot time automatically. The gw6c will handle starting radvd if you have gw6c configured to get a network (instead of a single IP) from go6.net.
    RedHat/CentOS and Mandriva: RH/Cent/Mdv Init Script
    Gentoo: Gentoo Init Script
  10. Enable the service to start at boot.
    RedHat/CentOS and Mandriva:
    chkconfig gw6c --add chkconfig gw6c on # should be on by default, but just in case chkconfig radvd off # again, just in case
    # Assuming "default" is your default boot category rc-update add gw6c default
  11. Configure the machine to forward packets across interfaces:
    echo "net.ipv6.ip_forward = 1" >> /etc/sysctl.conf sysctl -p
  12. At this point, you can start the gw6c service and test to see if it works. If it doesn't start properly, the next step discusses a couple of things to check. But how do you know if it works?
    a. Starting says OK:
    /etc/init.d/gw6c start
    If it doesn't say OK, then go look in /usr/local/gw6c/logs/gw6c.log and read the next step.
    b. There is a process running named gw6c.
    c. There is a process running named radvd (if host_type=router).
    d. There is a new ivp6 address on your ethernet interfaces, such as:
    ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:90:27:E0:0A:00 inet addr: Bcast: Mask: inet6 addr: 2001:9999:8888::1/64 Scope:Global inet6 addr: fe80::290:27ff:fee0:a00/64 Scope:Link
    Note the new address with the 2001::/16 prefix. That is the new ipv6 address that has been automatically created on the interface using the 2001:9999:8888::/64 network which was assigned to us by the gw6c client. Per convention, 2001:9999:8888::/64 is shorthand for 2001:9999:8888:0000::/64. Additionally, much like an ipv4 network where people typically put as the default gateway for the network, the gw6c client automatically assigns 2001:9999:8888::1/128 to the gateway interface (if_prefix=eth0). I have not seen this convention in any RFC, but this is the way gw6c does it.
  13. If you configured your machine as 'host_type=router', then gw6c did a second step for you as it started. It created a temporary config file for radvd at /usr/local/gw6c/radvd-gw6c.cfg. If for some reason it cannot start radvd, then the gw6c startup will fail. So if gw6c fails to start, one of the things to check is if radvd has some kind of error condition that causes it to fail its startup. In my tests where radvd failed to start, gw6c logged a message saying that it started up ok and assigned an ip, but then radvd logged an error (at that point both daemons died with no further logging). What's misleading is the init script said that it started ok. You must pay attention to the previous step for the sequence to verify that everything started up properly.
  14. Test the connection by pinging some known good ipv6 site.
    ping6 www.mrball.net PING www.mrball.net(2001:5c0:8fff:fffe::7a55) 56 data bytes 64 bytes from 2001:5c0:8fff:fffe::7a55: icmp_seq=1 ttl=62 time=192 ms 64 bytes from 2001:5c0:8fff:fffe::7a55: icmp_seq=2 ttl=62 time=218 ms
  15. Turn off the service because currently it's not firewalled and anybody can ping/ssh to your machine, even if you're behind an ipv6 NAT gateway. Why? Because you're tunnelling to go6.net and getting globally reachable IP addresses. The next step will take care of that.
    /etc/init.d/gw6c stop
  16. Make sure you have ipv6 iptables support, called ip6tables.
    yum install iptables-ipv6
    urpmi iptables-ipv6
    vi /etc/make.conf # make sure that you have ipv6 in USE flags emerge iptables # will build ipv6 support in # Make sure you have required kernel modules enabled. You can # either compile as a loadable module or into the kernel, your # choice. The following are required: # CONFIG_TUN # CONFIG_INET_TUNNEL # CONFIG_IPV6 # CONFIG_IPV6_PRIVACY # CONFIG_IPV6_SIT (used if you're not behind a NAT) # CONFIG_NETFILTER # CONFIG_NETFILTER_XTABLES # CONFIG_NETFILTER_XT_MATCH_STATE # CONFIG_NF_CONNTRACK_IPV6 # CONFIG_IP6_NF_IPTABLES # CONFIG_IP6_NF_MATCH_OPTS # CONFIG_IP6_NF_FILTER # CONFIG_IP6_NF_TARGET_REJECT # CONFIG_IP6_NF_TARGET_LOG # I hope I didn't miss any. # On my Gentoo box, I made everything ipv6 related a module, and # ended up loading these for proper operation: lsmod Module Size Used by tun 8096 1 ip6t_REJECT 4064 1 nf_conntrack_ipv6 14780 2 xt_state 1888 2 nf_conntrack 50376 2 nf_conntrack_ipv6,xt_state ip6table_filter 2016 1 ip6_tables 11148 1 ip6table_filter x_tables 11332 3 ip6t_REJECT,xt_state,ip6_tables ipv6 242724 16 ip6t_REJECT,nf_conntrack_ipv6
  17. Set up a simple firewall for ipv6. For CentOS/RedHat and Mandriva the following will be in /etc/sysconfig/iptables. For Gentoo, the following will be in /var/lib/ip6tables/rules-save:
    *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :IPV6-INPUT - [0:0] [0:0] -A INPUT -j IPV6-INPUT [0:0] -A FORWARD -j IPV6-INPUT [0:0] -A IPV6-INPUT -i lo -j ACCEPT # [0:0] -A IPV6-INPUT -p ipv6-icmp -j ACCEPT [0:0] -A IPV6-INPUT -p esp -j ACCEPT [0:0] -A IPV6-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # The following line uses my internal LAN facing interface [0:0] -A IPV6-INPUT -i eth0 -m state --state NEW -j ACCEPT [0:0] -A IPV6-INPUT -j REJECT --reject-with icmp6-adm-prohibited COMMIT
    You can uncomment the line with ipv6-icmp if you choose. This line allows all ping6 and tracepath6/traceroute6 tests to work both inbound and outbound. If commented, ping6 and tracepath6/traceroute6 only work from the inside. PAY ATTENTION: People can ping your internal hosts from the outside with that line enabled. They can't ssh or browse to it, but they'll be able to ping it, so they will know things like when employees are at work (when not to try to break in to some machine or when they're not at home) and other social engineering type things like that.
    WARNING: IPv6 stateful filtering was broken until kernel 2.6.20. CentOS 5 uses 2.6.18, so the --state rules above won't work.
  18. Load the firewall with:
    /etc/init.d/ip6tables start
  19. Look at the firewall rules to make sure it loaded properly:
    # ip6tables --list -n Chain INPUT (policy ACCEPT) target prot opt source destination IPV6-INPUT all ::/0 ::/0 Chain FORWARD (policy ACCEPT) target prot opt source destination IPV6-INPUT all ::/0 ::/0 Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain IPV6-INPUT (2 references) target prot opt source destination ACCEPT all ::/0 ::/0 ACCEPT icmpv6 ::/0 ::/0 ACCEPT esp ::/0 ::/0 ACCEPT all ::/0 ::/0 state RELATED,ESTABLISHED ACCEPT all ::/0 ::/0 state NEW REJECT all ::/0 ::/0 reject-with icmp6-adm-prohibited
  20. Now start the gw6c process back up:
    /etc/init.d/gw6c start
  21. Stateless autoconfiguration is the end goal of this whole procedure. The gist of stateless autoconfiguration is that the radvd process advertises a /64 network (the first 64 bits). The ipv6 enabled host will see this advertisement and the host generates the last 64 bits of the host address. Here's how to make sure that your host is ipv6 enabled.
    CentOS: If you didn't specifically disable ipv6 during the installation or at any time during the gui/ncurses configuration step, ipv6 should be enabled. Here's how to check:
    # in /etc/sysconfig/network NETWORKING_IPV6=yes # in /etc/sysconfig/network-scripts/ifcfg-eth0 (or whichever device needs to be ipv6 enabled) IPV6INIT=yes IPV6_AUTOCONF=yes # IPV6_PRIVACY="rfc3041"
    * For me, privacy extensions didn't work properly, but that may be because the machine I was testing it on was a wifi card so init scripts didn't quite work.
    Mandriva: If you didn't specifically disable ipv6 during any part of the gui/ncurses configuration step, ipv6 should be enabled.
  22. Go look at any host that has ipv6 and ipv6 autoconfiguration enabled and look to see if it has created the new address:
    ~$ /sbin/ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:1D:09:76:F5:58 inet addr: Bcast: Mask: inet6 addr: 2001:9999:8888:0:21d:9ff:fe76:f558/64 Scope:Global inet6 addr: fe80::21d:9ff:fe76:f558/64 Scope:Link
    Again, this is stateless autoconfiguration at work. Your server is advertising 2001:9999:8888::/64 as a valid network, but where did the second 64 bits of address come from? (the 21d:9ff:fe76:f558 portion). It is automatically generated using what's called EUI-64. It's based upon your 48 bit MAC address. Look at the MAC above and compare to the last 64 bits of the ipv6 address you'll see that it is very similar. The exact generation formula is described in Appendix A of RFC 4291.
  23. Test to see if you can ping6 www.kame.net or some other known ipv6 site. It should all be working now.
    ping6 www.mrball.net PING www.mrball.net(2001:5c0:8fff:fffe::7a55) 56 data bytes 64 bytes from 2001:5c0:8fff:fffe::7a55: icmp_seq=1 ttl=62 time=192 ms 64 bytes from 2001:5c0:8fff:fffe::7a55: icmp_seq=2 ttl=62 time=218 ms
  24. Add a little bit of resiliency by making a quick cronjob that will test if the daemon is still running and restart it if it is not. Like any service which is tunnelled, occassional disconnects happen and this is a simple way of correcting it. I achieve this using this:
    ~$ crontab -l -u root | grep gw6c 0 * * * * /sbin/pidof gw6c >/dev/null || /etc/init.d/gw6c restart
  25. Test from somewhere outside and make sure that your hosts are not reachable from the outside (several webbased ipv6 testers are available if you google for it). Note that if you allowed icmpv6 in the firewall by uncommenting that icmpv6 line, you'll be able to ping the host, but you won't be able to connect to anything via tcp or udp. If you specifically blocked icmpv6 by leaving that line commented, then you won't be able to ping the host either. In this example, I allowed ping:
    ping6 2001:9999:8888:0:21d:9ff:fe76:f558 PING 2001:9999:8888:0:21d:9ff:fe76:f558(2001:9999:8888:0:21d:9ff:fe76:f558) 56 data bytes 64 bytes from 2001:9999:8888:0:21d:9ff:fe76:f558: icmp_seq=1 ttl=62 time=188 ms 64 bytes from 2001:9999:8888:0:21d:9ff:fe76:f558: icmp_seq=2 ttl=62 time=186 ms --- 2001:9999:8888:0:21d:9ff:fe76:f558 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 186.161/187.506/188.852/1.413 ms telnet 2001:9999:8888:0:21d:9ff:fe76:f558 80 Trying 2001:9999:8888:0:21d:9ff:fe76:f558... telnet: Unable to connect to remote host: Permission denied
  26. RFC's are technical documents that pertain to implementing things on computers. The following page lists ipv6 specific RFC's: http://wiki.go6.net/index.php?title=IPv6_Requests_for_Comment. The ones of particular interest are: Also interesting is 4193 if you choose to implement a local subnet that you manually create, do dns for, and maintain (it can still generate automatically the second 64 bits of space, same as is done here.) There is a webbased form that will do the autogeneration of your own unique local subnet that is supposed to be globally unique, but since it's not a routable prefix, it is relatively safe (think 192.168.*.* or 10.*.*.* in the ipv4 world but without NAT capability, you'd use your globally unique public routable IP instead and rely on the firewall to keep anything you don't want from penetrating to your box).
  27. I try to keep up with everything that's happening in the ipv6 world. See what things I have been reading when it comes to ipv6 on my Del.icio.us bookmark page.

Todd A. Lyons
Rev 2 - 2/26/2009
Rev 1 - 6/03/2008
Rev 0 - 1/24/2008