IPv6-in-IPv4 Tunnel for CentOS/Redhat 5 or 6

June 24, 2011 Cody IPv6

Today I want to show everyone how to properly handle IPv6, virtual interfaces, and routes in CentOS/Redhat without resorting to custom scripts or a hacked together mess that may work for you but will confuse the next person that needs to maintain the server. It is crucial to perform tasks via a standardized method so if your documentation (You do document configurations don’t you!) sounds like the rants of a madman the next person can use their standard knowledge or search RedHat documentation on how to make a safe change to the OS.

Before you can setup a IPv6-in-IPv4 tunnel you will need to acquire a tunnel provider. I suggest using Hurricane Electric as a tunnel broker service so wander over there and sign up for FREE. They will give you a reliable IPv6-in-IPv4 tunnel along with a default /64 and even a /48 by request. Now you will have plenty of public address space and be able to give dedicated IPv6 addresses to your Apache virtual hosts, email MTA, or whatever else you could possibly need an IP address for.

So lets start this process off by ensuring we have IPv6 active on our system.

Activating the IPv6 TCP/IP stack in CentOS/Redhat 5 or 6

First you will need to check the following file

nano /etc/sysconfig/network

and look for the following line called “NETWORKING_IPv6=yes”.


This will tell the network scripts to load the kernel module “net-pf-10” so that we can use the TCP/IP v6 kernel stack. You can confirm this using the following method.

modprobe -c | grep net-pf-10

alias net-pf-10 ipv6
alias net-pf-10-proto-0-type-6 dccp_ipv6
alias net-pf-10-proto-33-type-6 dccp_ipv6
alias net-pf-10-proto-132 sctp

Configuring the Network Device File

Our first goal in a IPv6-in-IPv4 tunnel is to create a ‘sit'(simple internet transition) virtual network device that we can then bring the virtual interface up on. A ‘sit’ device is nothing more the a point-to-point tunnel. We will tell the device our tunnel providers IPv4 address we wish to connect our tunnel to and we will specify what local IPv4 address to use for the tunnel locally. This is important as it allows the tunnel provider to identify our connection; you will be required to provide your IPv4 address to the tunnel provider during registration so that they can properly configure their side. The ‘sit’ interface will also hold our point-to-point IPv6 address that we are assigned by our tunnel provider. A point-to-point IPv6 address will create an IPv6 tunnel inside the IPv4 tunnel and allow our IPv6 /64 subnet to be routed over this IPv6 tunnel.

Lets start this by creating the virtual network device file and adding the required parameters.

nano /etc/sysconfig/network-scripts/ifcfg-sit1

NAME=”HE IPv6-in-IPv4 Tunnel”
#This will activate IPv6 on the interface
#Tunnel Providers remote IPv4 address
#Device name you want ‘ifconfig’ to display
#Your local IPv4 address that you provided to your tunnel provider
#IPv6 address for your side of the tunnel
#Ensures the virtual interface is activated on boot

That is it, easy huh? There really is not much to a ‘sit’ interface. Now we can edit our physical interface and assign our Global IPv6 addresses that have been assigned to us by our tunnel provider.

Setting a static IPv6 Address in CentOS/Redhat 5 or 6

nano /etc/sysconfig/network-scripts/ifcfg-eth0

Just add the following lines to your normal ifcfg-eth0 file to add IPv6 connectivity to the eth0 interface. We will turn off IPv6 auto-configuration and set a static IPv6 address from our /64 subnet that was provided by the tunnel broker.


I feel adding the statement ‘IPV6_AUTOCONF=no’ is important on a server network interface due to security. I do not want the network interface to ever acknowledge or process a RA (Router Advertisement) packet. This protects you from a rogue RA daemon whether it is malicious or not. On a server I *ONLY* want a static ip address and that means to disable any auto-configuration. I do not want an unknown global address to compromise security or stability of the system.

*TIP of the Day*

You can use the site IPv6Verify.com to ensure that the address you chose from your /64 subnet is valid. This can help you quickly eliminate the chosen ipv6 address as an issue if your encounter problems.

Adding Tunnel Route to the IPv6 Kernel Routing Table

You can check your ipv6 routing tables via two different commands:

route -A inet6 -vn
ip -f inet6 route

Each command differs in how it formats the output of the route table.

Adding a route to direct ipv6 traffic to our tunnel interface is performed by a ‘route’ file which will be called by the network service when started. This will keep our route persistent across reboots and allow for an easy edit in the future. An administrator will not have to go dig thru rc.local or some customer bash script to update the route. He simply needs to inspect the default OS location for such a route file.

Adding an IPv6 route will require the use of a ‘route6’ file. If you fail to include the ‘6’ the file will not append the IPv6 route.

nano /etc/sysconfig/network-scripts/route6-sit1

In this example I will be routing all IPv6 traffic (::/0) to device ‘sit1’.

#IPv6 route to HE tunnel device
#routes all IPv6 traffic to network device ‘sit1’
::/0 dev sit1

Once the network is restarted you should be able to ping HE.net (2001:470:0:76::2)

Here we will use the ‘ping6’ command instead of the regular ‘ping’ command that most people are used to.

ping6 2001:470:0:76::2

PING 2001:470:0:76::2(2001:470:0:76::2) 56 data bytes
64 bytes from 2001:470:0:76::2: icmp_seq=0 ttl=59 time=80.4 ms
64 bytes from 2001:470:0:76::2: icmp_seq=1 ttl=59 time=80.2 ms
64 bytes from 2001:470:0:76::2: icmp_seq=2 ttl=59 time=80.3 ms
64 bytes from 2001:470:0:76::2: icmp_seq=3 ttl=59 time=80.2 ms
64 bytes from 2001:470:0:76::2: icmp_seq=4 ttl=59 time=80.3 ms
64 bytes from 2001:470:0:76::2: icmp_seq=5 ttl=59 time=80.3 ms

— 2001:470:0:76::2 ping statistics —
6 packets transmitted, 6 received, 0% packet loss, time 5002ms
rtt min/avg/max/mdev = 80.227/80.328/80.403/0.335 ms, pipe 2

Once you ensure that you have data connectivity across the tunnel we can test the systems default DNS servers. This test will see if the DNS server can return a proper AAAA dns record which will translate a hostname into an IPv6 address.

ping6 he.net

PING he.net(he.net) 56 data bytes
64 bytes from he.net: icmp_seq=0 ttl=59 time=80.4 ms
64 bytes from he.net: icmp_seq=1 ttl=59 time=80.2 ms
64 bytes from he.net: icmp_seq=2 ttl=59 time=80.2 ms
64 bytes from he.net: icmp_seq=3 ttl=59 time=85.2 ms
64 bytes from he.net: icmp_seq=4 ttl=59 time=80.2 ms

— he.net ping statistics —
5 packets transmitted, 5 received, 0% packet loss, time 4002ms
rtt min/avg/max/mdev = 80.258/81.299/85.282/2.008 ms, pipe 2

Declaring IPv6 Nameservers in /etc/resolv.conf

Next we will declare our ipv4 and ipv6 Nameservers in ‘/etc/resolv.conf’.

nano /etc/resolv.conf

search foo-domain.com
;Hurricane Electric IPv6+IPv4 public Anycast DNS
nameserver 2001:470:20::2
;GBLX public ipv6
nameserver 2001:450:2005::
;Google Public DNS ipv4 & AAAA records

Remember that “/etc/resolv.conf” will only use the first THREE nameservers listed no matter if they are ipv6 or ipv4. I suggest adding the Hurricane Electric ipv6 Anycast servers and then one of the Public Google DNS servers since they are reachable over ipv4 and will return ipv6 AAAA records. Then for the third nameserver you can use your default ISP or such that will always be available and in a worst case resolve the ipv4 address of a domain.

Hurricane Electric will have a listing of DNS servers to use with your tunnel if your default DNS servers still don’t support AAAA records. But if you need ideas for an IPv6 DNS server or AAAA record capable ipv4 DNS server then check out the list @ http://www.chatz6.com/files/resolv.conf

Testing your IPv6 Connectivity

Lastly lets ping an ipv6 website and make sure we have connectivity. There are a few different options for this: ipv6.google.com and he.net are two. Both of these domains have AAAA records on ipv4 public DNS servers that should return the ipv6 address for you.

ping6 -n ipv6.google.com

PING ipv6.google.com(2001:4860:800b::68) 56 data bytes
64 bytes from 2001:4860:800b::68: icmp_seq=1 ttl=56 time=64.1 ms
64 bytes from 2001:4860:800b::68: icmp_seq=2 ttl=56 time=63.9 ms
64 bytes from 2001:4860:800b::68: icmp_seq=3 ttl=56 time=63.8 ms
64 bytes from 2001:4860:800b::68: icmp_seq=4 ttl=56 time=63.9 ms
— ipv6.google.com ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 63.805/63.956/64.128/0.115 ms

Lets resolve some AAAA DNS records over ipv4 and ipv6 before we say everything is working 100%.

We can use the command “dig” to query the DNS servers in ‘/etc/resolv.conf’ for A and AAAA DNS records over IPv4 and IPv6 with the switch -4 and -6 respectfully.

dig +short -6 aaaa he.net


dig +short -6 a he.net

dig +short -4 aaaa he.net


dig +short -4 a he.net

As you can see we can make DNS queries over IPv4 and IPv6 networks while requesting either A or AAAA records.

Securing IPv6 with IP6TABLES

Do not forget to allow traffic through iptables using the command “ip6tables”. Also if you have a Global ipv6 address then do not just set an ANY<>ANY traffic rule for ipv6 on eth0. This will allow anyone full access to any port listening for ipv6 connections.

You can modify the commands below to open and close ports using “ip6tables”.

#accept incoming connection if established outbound connection exists
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#important for ipv6 network health and testing
ip6tables -A INPUT -p ipv6-icmp -j ACCEPT
#Allow traffic for 'lo' device
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -i lo -j ACCEPT
#allow new ssh connections
ip6tables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
#allow new website connections on port 80
ip6tables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
#Allow new outbound connections to anywhere
ip6tables -A OUTPUT -m state --state NEW -p all -s ::0/0 -d ::0/0

# iptables-save

Anyone have any ideas on an article they would like to see written that covers Fedora/RedHat/CentOS ?

4 Responses to “IPv6-in-IPv4 Tunnel for CentOS/Redhat 5 or 6”

  • trm says:

    thank you for the article! It is very well-written.
    I am getting an error when I restart the network though:
    Bringing up interface sit1: ioctl: No such device
    Any idea why?
    Thanks a lot in advance.

  • jean says:

    Great article!

    Check the double-quote for NAME=”HE IPv6-in-IPv4 Tunnel” in ifcfg-sit1 that they are linux double-quote and not copy/paste double-quote.

    Hope this help you


  • Jean says:


    excellent blog. I wonder why you are still an enthusiast within HE certification. Can’t you finish this and reach Sage? You will receive a very nice ipv6 shirt! 🙂

    If you need help, I can help you.



  • Cody says:

    Hi Jean,

    The certification would be nice but I simply have not had time to upgrade my personal email server to support IPv6 just yet for the Administrator part of the HE cert.

    I have been too busy implementing IPv6 into all of the services for the company I work for and am honestly burnt out on IPv6 to the point that I don’t want to convert my personal stuff yet. The server that powers this website has native IPv6 connectivity but I have yet to implement it and update the DNS records. Sigh.

Leave a Reply

Your email address will not be published. Required fields are marked *

Powered by WordPress. Designed by elogi.