Skip to main content
Engineering LibreTexts

8.14: IPv6 Connectivity via Tunneling

  • Page ID
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    \( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)

    ( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\id}{\mathrm{id}}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\kernel}{\mathrm{null}\,}\)

    \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\)

    \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\)

    \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    \( \newcommand{\vectorA}[1]{\vec{#1}}      % arrow\)

    \( \newcommand{\vectorAt}[1]{\vec{\text{#1}}}      % arrow\)

    \( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vectorC}[1]{\textbf{#1}} \)

    \( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)

    \( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)

    \( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)

    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    The best option for IPv6 connectivity is native support by one’s ISP. In such a situation one’s router should be sending out Router Advertisement messages, and from these all the hosts should discover how to reach the IPv6 Internet.

    If native IPv6 support is not forthcoming, however, a short-term option is to connect to the IPv6 world using packet tunneling (less often, some other VPN mechanism is used). RFC 4213 [] outlines the common 6in4 strategy of simply attaching an IPv4 header to the front of the IPv6 packet; it is very similar to the IPv4-in-IPv4 encapsulation of 7.13.1 IP-in-IP Encapsulation.

    There are several available providers for this service; they can be found by searching for “IPv6 tunnel broker”. Some tunnel brokers provide this service at no charge.

    The basic idea behind 6in4 tunneling is that the tunnel broker allocates you a /64 prefix out of its own address block, and agrees to create an IPv4 tunnel to you using 6in4 encapsulation. All your IPv6 traffic from the Internet is routed by the tunnel broker to you via this tunnel; similarly, IPv6 packets from your site reach the outside world using this same tunnel. The tunnel, in other words, is your link to an IPv6 router.

    Generally speaking, the MTU of the tunnel must be at least 20 bytes less than the MTU of the physical interface, to allow space for the header. At the near end this requires a local configuration change; tunnel brokers often provide a way for users to set the MTU at the far end. Practical MTU values vary from a mandatory IPv6 minimum of 1280 to the Ethernet maximum of 1500−20 = 1480.

    Setting up the tunnel does not involve creating a stateful connection. All that happens is that the tunnel client (ie your endpoint) and the broker record each other’s IPv4 addresses, and agree to accept encapsulated IPv6 packets from one another provided these two endpoint addresses are used as source and destination. The tunnel at the client end is represented by an appropriate “virtual network interface”, eg sit0 or gif0 or IP6Tunnel. Tunnel providers generally supply the basic commands necessary to get the tunnel interface configured and the MTU set.

    Once the tunnel is created, the tunnel interface at the client end must be assigned an IPv6 address and then a (default) route. We will assume that the /64 prefix for the broker-to-client link is 2001:470:0:10::/64, with the broker at 2001:470:0:10::1 and with the client to be assigned the address 2001:470:0:10::2. The address and route are set up on the client with the following commands (Linux/Mac/Windows respectively; interface names may vary, and some commands assume the interface represents a point-to-point link):

    ip addr add 2001:470:0:10::2/64 dev sit1
    ip route add ::/0 dev sit1
    ifconfig gif0 inet6 2001:470:0:10::2 2001:470:0:10::1 prefixlen 128
    route -n add -inet6 default 2001:470:0:10::1
    netsh interface ipv6 add address IP6Tunnel 2001:470:0:10::2
    netsh interface ipv6 add route ::/0 IP6Tunnel 2001:470:0:10::1

    At this point the tunnel client should have full IPv6 connectivity! To verify this, one can use ping6, or visit IPv6-only versions of websites (eg []), or visit IPv6-identifying sites such as []. Alternatively, one can often install a browser plugin to at least make visible whether IPv6 is used. Finally, one can use netcat with the -6 option to force IPv6 use, following the HTTP example in 12.6.2 netcat again.

    There is one more potential issue. If the tunnel client is behind an IPv4 NAT router, that router must deliver arriving encapsulated 6in4 packets correctly. This can sometimes be a problem; encapsulated 6in4 packets are at some remove from the TCP and UDP traffic that the usual consumer-grade NAT router is primarily designed to handle. Careful study of the router forwarding settings may help, but sometimes the only fix is a newer router. A problem is particularly likely if two different inside clients attempt to set up tunnels simultaneously; see 7.13.1 IP-in-IP Encapsulation.

  • 8.13.1 IPv6 firewalls

    It is strongly recommended that an IPv6 host block new inbound connections over its IPv6 interface (eg the tunnel interface), much as an IPv4 NAT router would do. Exceptions may be added as necessary for essential services (such as ICMPv6). Using the linux ip6tables firewall command, with IPv6-tunneled interface sit1, this might be done with the following:

    ip6tables --append INPUT --in-interface sit1 --protocol icmpv6 --jump ACCEPT
    ip6tables --append INPUT --in-interface sit1 --match conntrack --ctstate ESTABLISHED,RELATED --jump ACCEPT
    ip6tables --append INPUT --in-interface sit1 --jump DROP

    At this point the firewall should be tested by attempting to access inside hosts from the outside. At a minimum, ping6 from the outside to any global IPv6 address of any inside host should fail if the ICMPv6 exception above is removed (and should succeed if the ICMPv6 exception is restored). This can be checked by using any of several websites that send pings on request; such sites can be found by searching for “online ipv6 ping”. There are also a few sites that will run a remote IPv6 TCP port scan; try searching for “online ipv6 port scan”. See also exercise 7.0.

  • 8.13.2 Setting up a router

    The next step, if desired, is to set up the tunnel endpoint as a router, so other hosts at the client site can also enjoy IPv6 connectivity. For this we need a second /64 prefix; we will assume this is 2001:470:0:20::/64 (note this is not an “adjacent” /64; the two /64 prefixes cannot be merged into a /63). Let R be the tunnel endpoint, with eth0 its LAN interface, and let A be another host on the LAN.

    We will use the linux radvd package as our Router Advertisement agent (8.6.1 Router Discovery). In the radvd.conf file, we need to say that we want the LAN prefix 2001:470:0:20::/64 advertised as on-link over interface eth0:

    interface eth0 {
           prefix 2001:470:0:20::/64
                   AdvOnLink on;         # advertise this prefix as on-link
                   AdvAutonomous on;     # allows SLAAC with this prefix

    If radvd is now started, other LAN hosts (eg A) will automatically get the prefix (and thus a full SLAAC address). Radvd will automatically share R’s default route (::/0), taking it not from the configuration file but from R’s routing table. (It may still be necessary to manually configure the IPv6 address of R’s eth0 interface, eg as 2001:470:0:20::1.)

    On the author’s version of host A, the IPv6 route is now (with some irrelevant attributes not shown)

    default via fe80::2a0:ccff:fe24:b0e4 dev eth0

    That is, host A routes to R via the latter’s link-local address, always guaranteed on-link, rather than via the subnet address.

    If radvd or its equivalent is not available, the manual approach is to assign R and A each a /64 address:

    On host R: ip -6 address add 2001:470:0:20::1/64 dev eth0
    On host A: ip -6 address add 2001:470:0:20::2/64 dev eth0

    Because of the “/64” here (8.12.3 Manual address configuration), R and A understand that they can reach each other via the LAN, and do so. Host A also needs to be told of the default route via R:

    On host A: ip -6 route add ::/0 via 2001:470:0:10::1 dev eth0

    Here we use the subnet address of R, but we could have used R’s link-local address as well.

    It is likely that A’s eth0 will also need its MTU configured, so that it matches that of R’s virtual tunnel interface (which, recall, should be at least 20 bytes less than the MTU of R’s physical outbound interface).

  • A second router

    Now let us add a second router R2, as in the diagram below. The R──R2 link is via a separate Ethernet LAN, not a point-to-point link. The LAN with A is, as above, subnet 2001:470:0:20::/64.


    In this case, it is R2 that needs to run the Router Advertisement agent (eg radvd). If this were an IPv4 network, the interfaces eth0 and eth1 on the R──R2 link would need IPv4 addresses from some new subnet (though the use of private addresses is an option). We can’t use unnumbered interfaces (7.12 Unnumbered Interfaces), because the R──R2 connection is not a point-to-point link.

    But with IPv6, we can configure the R──R2 routing to use only link-local addresses. Let us assume for mnemonic convenience these are as follows:

    R’s eth0: fe80::ba5e:ba11
    R2’s eth1: fe80::dead:beef

    R2’s forwarding table will have a default route with next_hop fe80::ba5e:ba11 (R). Similarly, R’s forwarding table will have an entry for destination subnet 2001:470:0:20::/64 with next_hop fe80::dead:beef (R2). Neither eth0 nor eth1 needs any other IPv6 address.

    R2’s eth2 interface will likely need a global IPv6 address, eg 2001:470:0:20::1 again. Otherwise R2 may not be able to determine that its eth2 interface is in fact connected to the 2001:470:0:20::/64 subnet.

    One advantage of not giving eth0 or eth1 global addresses is that it is then impossible for an outside attacker to reach these interfaces directly. It also saves on subnets, although one hopes with IPv6 those are not in short supply. All routers at a site are likely to need, for management purposes, an IP address reachable throughout the site, but this does not have to be globally visible.

  • This page titled 8.14: IPv6 Connectivity via Tunneling is shared under a CC BY-NC-ND license and was authored, remixed, and/or curated by Peter Lars Dordal.

    • Was this article helpful?