HughesNet offers native IPv6 support (including routed prefixes) on their HT1000/HT1100 GEN4 systems. If you don’t know what IPv6 is, then fix yourself some tea, settle in, and skim through these primers on IPv6. It’s very nice to see that HughesNet is embracing the future of the Internet by allowing its customers to use IPv6 without having to configure a tunnel–most other ISPs don’t yet offer native IPv6.
Here’s an overview of HughesNet’s IPv6 infrastructure:
- The HT1000 modem (and, I imagine, the HT1100 modem) advertise themselves as IPv6 routers via ICMPv6.
- The modem also acts as a DHCPv6 server.
- The modem is given a /61 prefix that is carved up into multiple /64s, which are given out via prefix delegation. Why a /61 and not, say, a /60? I have no idea. Still, it means we have multiple subnets to play with. Thank you, HughesNet!
- The prefixes can and do change.
- The addresses on these prefixes are globally reachable public IPv6 addresses!
I want IPv6 on my network. Unfortunately, most older routers don’t support IPv6. (And believe me, all of my equipment is old.) Fortunately, my router is actually an aging Linux box, so I can configure it to support IPv6.
Here’s my current network setup:
- Router: 900MHz Celeron, 512MB RAM, CentOS 6.4 with 4 NICs.
- WAN: eth3, DHCP(v4) enabled
- LAN: eth0-eth2, static (private) IPv4 addresses
- DHCP/DNS server: dnsmasq
- Firewall: good ol’ iptables
And here’s an overview of what has to be done to IPv6ify the router:
- Use wide-dhcp6 to fetch prefixes from the upstream router (the HT1000 modem) via prefix delegation, and assign a prefix to at least one LAN interface
- Use a newer version of DNSMasq to advertise the router via ICMPv6 and supply DHCPv6 configuration information
- Firewall the pants off the router
- Enable IPv6 forwarding
- Test it all
- Automate it all
Each one of these steps has some lovely caveats.
1. wide-dhcp6 and prefix delegation
Here’s the deal. The HughesNet HT1000 will hand out /64 subnets for your LANs via DHCPv6. Your router can then advertise to clients via ICMPv6 or DHCPv6 (or both).
So far, the only DHCPv6 client I’ve found that can take a prefix advertised on a WAN interface and assign it to a LAN interface is wide-dhcpv6, which hasn’t been updated since 2008 (that’s about 17 eons in computer years). It’s hard to find packages for RPM based distributions like CentOS, so I compiled it from source. It has to be patched, otherwise you’ll face lots of lovely glibc-related errors. I fetched the source and patches used by Ubuntu. You can find the sources and patches here.
Note that you’ll need flex, bison, byacc, make, and gcc.
# wget https://launchpad.net/ubuntu/saucy/+source/wide-dhcpv6/20080615-11.1/+files/wide-dhcpv6_20080615.orig.tar.gz # wget https://launchpad.net/ubuntu/saucy/+source/wide-dhcpv6/20080615-11.1/+files/wide-dhcpv6_20080615-11.1.debian.tar.gz # tar xf wide-dhcpv6_20080615.orig.tar.gz # tar xf wide-dhcpv6_20080615-11.1.debian.tar.gz # cd wide-dhcpv6-20080615/ # for file in ../debian/patches/*.patch; do patch -p1 < "$file"; done # ./configure # make # make install
Now, to configure the DHCPv6 client. Here’s the configuration file I used. Plop something similar in /usr/local/etc/dhcp6c.conf
interface eth3 { send ia-pd 0; send ia-na 1; }; id-assoc na 1 {}; id-assoc pd { prefix-interface eth0 { sla-id 0; sla-len 3; ifid 1; }; prefix-interface eth1 { sla-id 1; sla-len 3; ifid 1; }; };
The key lines:
interface eth3 { send ia-na 1; send ia-pd 0; };
This sends a DHCPv6 request out on eth3 asking for prefixes, and also asks for a DHCPv6 address for the WAN interface.
prefix-interface eth0 { sla-id 0; sla-len 3; ifid 1; };
This assigns one of the /64 subnets on the delegated prefix to eth0. (sla-id 0 is the first /64, sla-id 1 is the second, and so on.) sla-len is the difference between the prefix size (/61) and /64. ifid instructs dhcp6c to assign the interface an address of <subnet>::1. Otherwise, it will use SLAAC to create a nasty-looking address from the interface’s MAC address.
The eth1 section is the same, but sla-id has been incremented by 1.
But wait, you can’t just fire up dhcp6c just yet. CentOS 6’s default firewall blocks returning DHCPv6 queries. So we need an IP6Tables rule:
# ip6tables -I INPUT -i eth3 -m state --state NEW -m udp -p udp --dport 546 --sport 547 -s fe80::/10 -d fe80::/10 -j ACCEPT # ip6tables-save > /etc/sysconfig/ip6tables
Now you can run dhcp6c and see if things are jiving:
# dhcp6c eth3 # ifconfig eth0 eth0 Link encap:Ethernet HWaddr <MAC addr> inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: 2001:beef:beef:beef::1/64 Scope:Global inet6 addr: <link local address>/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:207029767 errors:1828 dropped:0 overruns:0 frame:1828 TX packets:119122609 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1523876758 (1.4 GiB) TX bytes:3933130082 (3.6 GiB)
Beautiful. Our LAN interface now has an IPv6 address!
2. DNSMasq
DNSMasq is a small application that combines a DNS cache/forwarder, a DHCPv4 server, a DHCPv6 server, a TFTP server, and a router advertisement service. It works well for small networks but adapting it for more complicated situations can be difficult. If you don’t like such kitchen-sink applications, you can use more traditional tools: ISC BIND for DNS forwarding, dhcpd/dhcpd6 for DHCPv4 and DHCPv6, and radvd for ICMPv6. This blog has a good guide to setting everything up with the help of some BASH scripts for automation: Native IPv6 on Comcast.
Since I use DNSMasq already for my network, I want to continue to use it, but I’ll need to compile the latest version, 2.66, which adds the ability to construct DHCPv6 ranges from the prefix present on an interface. This seems to gracefully handle prefix changes without having to generate configuration files or restart the daemon.
# wget http://www.thekelleys.org.uk/dnsmasq/dnsmasq-2.66.tar.gz # tar xf dnsmasq-2.66.tar.gz # cd dnsmasq-2.66 # make # make install
Only do this if you aren’t using DNSMasq already:
# cp dnsmasq.conf.example /etc/dnsmasq.conf
Edit the configuration file. There are a plethora of comments to guide you. Here’s my bare-bones config:
domain-needed bogus-priv no-resolv # don't consult /etc/resolv.conf, use server= only server=192.168.0.1 # replace this with a custom DNS server if you want server=8.8.8.8 # multiple servers are OK local=/home.lan/ # only consult DHCP hosts database and /etc/hosts interface=eth0 interface=eth1 expand-hosts domain=home.lan # DHCPv4 hosts will get <hostname>.home.lan automatically dhcp-range=192.168.1.32,192.168.1.254,12h dhcp-range=10.0.1.32,10.0.1.254,12h dhcp-range=::1,::500,constructor:eth0, ra-names, 12h # add the following three lines dhcp-range=::1,::500,constructor:eth1, ra-names, 12h # to existing config, if any enable-ra # this line too dhcp-authoritative cache-size=1000 no-negcache
If you want the router to use itself as a nameserver, add the following lines to /etc/sysconfig/network-scripts/ifcfg-eth3 (where eth3 is your WAN interface).
PEERDNS="yes" DNS1="127.0.0.1"
But be sure to specify the router’s fully-qualified domain name in /etc/hosts. For example:
192.168.1.1 router.home.lan router
3. Firewall
You really do not want to skip this section.
With IPv6, your clients are no longer “protected” by NAT like you assumed they were with IPv4. In fact, there is no NAT for IPv6. (Yeah, yeah, I know, it’s possible, but I’m just going to pretend it doesn’t exist.) This is a good thing. NAT is an ugly hack that was designed to stave off IPv4 address exhaustion. It breaks end-to-end connectivity and introduces a metric truckload of boondoggles, not the least of which is the common assumption that the machines on the private network behind the NAT router are safe. With IPv6, every client is directly routeable from the Internet, so it’s your job to configure your firewalls so that each machine is not reachable.
Here’s the stripped-down config I used for the router. Bear in mind: eth0 and eth1 are LAN, eth3 is WAN. You’ll probably want a much more robust set of firewall rules…
/etc/sysconfig/ip6tables
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p ipv6-icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -i eth0 -m state --state NEW -m udp -p udp --dport 53 -j ACCEPT -A INPUT -i eth1 -m state --state NEW -m udp -p udp --dport 53 -j ACCEPT -A INPUT -i eth0 -m state --state NEW -m udp -p udp --dport 547 -j ACCEPT -A INPUT -i eth1 -m state --state NEW -m udp -p udp --dport 547 -j ACCEPT -A INPUT -i eth0 -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPUT -s fe80::/10 -d fe80::/10 -i eth3 -p udp -m state --state NEW -m udp --sport 547 --dport 546 -j ACCEPT -A INPUT -j REJECT --reject-with icmp6-adm-prohibited -A FORWARD -i eth3 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT -A FORWARD -i eth3 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT -A FORWARD -i eth0 -o eth3 -j ACCEPT -A FORWARD -i eth1 -o eth3 -j ACCEPT -A FORWARD -j REJECT --reject-with icmp6-adm-prohibited COMMIT
DO NOT block ipv6-icmp. Blocking icmp in IPv4 was unwise, but you could get away with it. Blocking icmp in IPv6 will break things and you will be very upset.
Open up other services as you expect them. Here I have SSH open on the LAN.
4. IPv6 Forwarding
Here’s the fun part. On kernel versions < 2.6.37, enabling IPv6 forwarding is a binary thing, and enabling it disables receiving router announcements. Since CentOS 6’s kernel is a stable version 2.6.32, enabling IPv6 means our pretty SLAAC address on the WAN interface is about to go to IPv6 address heaven. But there is a little-documented workaround: enable IPv6 forwarding for all interfaces but then explicitly disable it on the WAN interface. It will still work. Why? I don’t know.
Enable forwarding:
# echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
Then, for kernel < 2.6.37
# echo 0 > /proc/sys/net/ipv6/conf/eth3/forwarding
For kernel >= 2.6.37:
# echo 2 > /proc/sys/net/ipv6/conf/eth3/accept_ra
You can set these in /etc/sysctl.conf to keep the settings across reboots:
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.eth3.forwarding=0
or for kernel >= 2.6.37:
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.eth3.accept_ra=2
(Thanks to these two blog posts for information on these pesky sysctl variables. Go read them, they go far deeper in depth on wide-dhcpv6 and IPv6 in general.)
5. Test it
Make sure your firewall config is in place. Enable IPv6 forwarding. Start dhcp6c manually:
# dhcp6c eth3
Start DNSMasq manually in debug mode.
# dnsmasq -d
Now connect a computer to your LAN interface. Enable IPv6 (most modern Linux distros will have IPv6 enabled already). Use ifconfig on the client to see if you have a public IPv6 address.
# ifconfig eth0 eth0 Link encap:Ethernet HWaddr <mac addr> inet addr:192.168.1.115 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: 2001:<snip>/64 Scope:Global inet6 addr: 2001:<snip>/64 Scope:Global
In this case, the client has two–one generated via SLAAC, the other via DHCPv6. Nice!
Try pinging something.
# ping6 google.com PING google.com(dfw06s33-in-x03.1e100.net) 56 data bytes 64 bytes from dfw06s33-in-x03.1e100.net: icmp_seq=1 ttl=55 time=683 ms 64 bytes from dfw06s33-in-x03.1e100.net: icmp_seq=2 ttl=55 time=823 ms 64 bytes from dfw06s33-in-x03.1e100.net: icmp_seq=3 ttl=55 time=743 ms 64 bytes from dfw06s33-in-x03.1e100.net: icmp_seq=4 ttl=55 time=813 ms
If all goes well by this point, you now have IPv6 on your home network!
6. Automate it
If you haven’t already, test the IPv6 forwarding settings and add them to /etc/sysctl.conf. Reboot
You’ll want dhcp6c to start when the interface is brought up and for it to be killed when the interface goes down. For CentOS, you can accomplish this by creating two files in /sbin, ifup-local and ifdown-local. These are called by the ifup/ifdown scripts if they exist, but they are not present on a stock CentOS system. Create them and mark them executable.
/sbin/ifup-local
#!/bin/bash if [[ "$1" == "eth3" ]] then echo "Starting wide-dhcpv6 client..." /usr/local/sbin/dhcp6c -p /var/run/dhcp6c.pid "$1" fi
/sbin/ifdown-local
#!/bin/bash if [[ "$1" == "eth3" ]] then test -e /var/run/dhcp6c.pid && kill `cat /var/run/dhcp6c.pid` fi
(The ifdown script could be improved and made to ensure that the process being killed is, in fact, dhcp6c…)
Mark them both executable:
# chmod +x /sbin/ifup-local /sbin/ifdown-local
To start DNSMasq on boot, plop this into /etc/init.d/dnsmasq (assuming you’re not already using dnsmasq from a proper RPM package). If you are, adjust the dnsmasq= line to point to the new dnsmasq executable in /usr/local/sbin/:
#!/bin/sh # # Startup script for the DNS caching server # # chkconfig: - 49 50 # description: This script starts your DNS caching server # processname: dnsmasq # pidfile: /var/run/dnsmasq.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ ${NETWORKING} = "no" ] && exit 0 dnsmasq=/usr/local/sbin/dnsmasq [ -f $dnsmasq ] || exit 0 DOMAIN_SUFFIX=`dnsdomainname` if [ ! -z "${DOMAIN_SUFFIX}" ]; then OPTIONS="-s $DOMAIN_SUFFIX" fi RETVAL=0 # See how we were called. case "$1" in start) if [ $UID -ne 0 ] ; then echo "User has insufficient privilege." exit 4 fi echo -n "Starting dnsmasq: " daemon $dnsmasq $OPTIONS RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/dnsmasq ;; stop) if test "x`pidfileofproc dnsmasq`" != x; then echo -n "Shutting down dnsmasq: " killproc dnsmasq fi RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/dnsmasq /var/run/dnsmasq.pid ;; status) status dnsmasq RETVAL=$? ;; reload) if test "x`pidfileofproc dnsmasq`" != x; then echo -n "Reloading dnsmasq: " killproc dnsmasq -HUP fi RETVAL=$? echo ;; force-reload) # new configuration takes effect only after restart $0 stop $0 start RETVAL=$? ;; restart) $0 stop $0 start RETVAL=$? ;; condrestart) if test "x`pidfileofproc dnsmasq`" != x; then $0 stop $0 start RETVAL=$? fi ;; *) echo "Usage: $0 {start|stop|restart|reload|condrestart|status}" exit 2 esac exit $RETVAL
Then, once the script is in place:
# chmod +x /etc/init.d/dnsmasq # chkconfig --add dnsmasq # chkconfig dnsmasq on
What’s next?
I don’t think dnsmasq’s nameserver is being advertised (either via ICMPv6 RDNSS or DHCPv6), so my local DNS cache is only available via IPv4 for now. I also want to enable RFC4941 privacy extensions so my MAC-derived SLAAC-configured addresses aren’t easily traced across every IPv6-enabled website I visit.
If you’ve gotten this far without encountering errors: congratulations! You have native HughesNet IPv6 on your network!
I used to work at RedHat, during the Bob Young era. But with the advent of Fedora, I switched to Debian for servers and Ubuntu for desktops. Thanks to your scripting, I should be able to use them for enabling IPv6 on my servers. hat might save me from having to dink with AT&T supplied routers and their want to make everything DHCP, even though we have 6 static IP addresses that we pay for. I miss the old days of just setting /etc/hosts the way you want it and things just worked out of the box!
Do you think we’ll ever get to the point that Hughes tech support doesn’t cringe when you mention Linux? I haven’t used Windows since 3.1.1. and that I ran on Wabi with Caldera in the mid 90’s. It was SO slick! Ric