Skip to content

Instantly share code, notes, and snippets.

@paceline
Last active December 21, 2015 00:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paceline/6220970 to your computer and use it in GitHub Desktop.
Save paceline/6220970 to your computer and use it in GitHub Desktop.
Get your (multiple) web hosts to support IPv6 even though your hosting company still exclusively uses IPv4 (including intra data center traffic)

Prerequisites

General requirements

One or more virtual or dedicated servers with root access, possibly located in the same data center. I'm running two Debian virtual machines (Lenny and Squeeze) but I assume you can adopt the recipe to work on any Linux box An account with tunnelbroker.net or similar service

All network configuration doesn't do any good if your web server software doesn't support IPv6 requests. For nginx this means compiling with the --with-ipv6 option. See my Human script for passenger w/ nginx for my favorite nginx compilation options.

My setup

1st virtual server

| Hostname | IP --- | --- | --- Public IPv4 | fluffy.cloud.com | 69.150.210.40 Private IPv4 | fluffy.cloud.local | 192.168.170.200/17

2nd virtual server

| Hostname | IP --- | --- | --- Public IPv4 | cirrus.cloud.com | 69.150.210.41 Private IPv4 | cirrus.cloud.local | 192.168.170.201/17

IPv6 tunnel

| Client (my end of the tunnel) | Server (the other end of the tunnel) --- | --- | --- IPv4 Endpoint | 69.150.210.40 | 209.51.161.14 IPv6 Endpoint | 2001:470:1f04:f53::2/64 | 2001:470:1f04:f53::1/64 IPv6 Network | 2001:470:1f05:f53::/64 | -

"Solution"

I wanted both my servers to be on the same IPv6 network so I set up fluffy to handle my shiny new IPv6 network and do all the routing.

Internal networking (IPv4)

I requested two private IPs from my data center provider and set them up as virtual interfaces. Among other things this allows the two machines to communicate with each other without it counting towards my monthly bandwidth quota. Configuration is pretty straight forward. The snippets from /etc/network/interfaces look something like this:

Fluffy

auto eth0 eth0:0

[...]

iface eth0:0 inet static
 address 192.168.170.200
 netmask 255.255.128.0

Cirrus

auto eth0 eth0:0

[...]

iface eth0:0 inet static
 address 192.168.170.201
 netmask 255.255.128.0

Tunnel to your tunnelbroker (6in4)

Next I hooked up fluffy to Hurricane Electric's IPv6 tunnel. Also fairly easy to setup in /etc/network/interfaces, especially since they provide the necessary instructions:

iface he-ipv6 inet6 v4tunnel
 address 2001:470:1f04:f53::2
 netmask 64
 endpoint 209.51.161.14
 local 69.150.210.40
 gateway 2001:470:1f04:f53::1
 ttl 64

Now you should be able to reach any other public IPv6 host from fluffy.

Configure IPv4 and IPv6 paket filters

Since you probably want to restrict access to a few services (HTTP, HTTPS, SSH etc.) its a good idea to get your paketfiler rules straight now. I read somewhere that the iptables people started integrating the IPv4 and IPv6 versions of their paket filter, which would allow you work with just one ruleset. For now however you have to live with administering the two separately.

iptables

Lets start with the IPv4 since this will be the first ruleset your tunnel traffic will run through since the IPv6 packets are encapsulated in IPv4 packets. You probably already knew that. Since iptables is pretty well covered in various tutorials an how-tos I'm just going to show you the one line that matters for our purposes:

I inserted this at the very to of my ruleset. It basically allow all IPv6 in from our tunnel:

-A INPUT -p ipv6 -s 209.51.161.14 -j ACCEPT

You probably also want unrestricted (private network) communication between your servers:

-A INPUT -s 192.168.170.201/17 -j ACCEPT

For an introduction and good standard web server ruleset I'd like to refer you to the Slicehost knowledge base (see further reading below for direct links).

ip6tables

Since now we're basically letting all IPv6 traffic you probably want to copy most of your IPv4 rules to your IPv6 config file. This time I'll post my full config:

*filter

#  Allows all loopback (lo0) traffic
-A INPUT -i lo -j ACCEPT

**# Accepts all traffic from other nodes on YOUR IPv6 network (in my case just one)
-A INPUT -s 2001:470:1f05:f53::/64 -j ACCEPT**

#  Accepts all established inbound connections
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

#  Allows all outbound traffic
#  You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

# Allow SSH since dyndns does not yet support IPv6
-A INPUT -p tcp --dport 22 -j ACCEPT

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allow ICMP traffic
-A INPUT -p icmpv6 -j ACCEPT

**# Route any traffic to and from any node on my IPv6 network
-A FORWARD -s 2001:470:1f05:f53::/64 -j ACCEPT
-A FORWARD -d 2001:470:1f05:f53::/64 -j ACCEPT**

# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j DROP
-A FORWARD -j DROP

COMMIT

You can see that for the most this looks just your regular iptables ruleset, which really makes you wonder why on earth they made two separate engines for IPv4 and IPv6.

I'd like to point two rules (the ones in bold face):

  • I allow unrestricted traffic on my IPv6 network (couldn't see why not)
  • I also IPv6 packet forwarding to an from any node on my network. They all have their own packet filter with different rulesets so I'd say thats ok, too. This or a similar setting is required fluffy here is supposed the serve as the IPv6 router for my web hosts.

I don't think I need to show the iptables settings for cirrus here. In principle they look just the same only without the FORWARD ACCEPT and tunnel inlet rules.

Internal routing (ISATAP)

Now for the somewhat tricky part. I need fluffy to assign an IPv6 address from my address space to cirrus and then do all the routing. Fluffy and cirrus can only talk IPv4 with one another since the data center internal traffic is IPv4 only. This calls for another tunnel only this time I didn't want to use static endpoints but rather have have fluffy use IPv6's RAD (router advertisement daemon) mechanism. The ISATAP protocol seemed perfect for the job.

Router settings

Lets start with yet another virtual interface to allow IPv6 communication between the two hosts. Modify to whatever IPs you use but be sure to include the "5efe" part in that last line. You have to put it in between your IPv6 network and IPv4 address blocks. Otherwise ISATAP won't work.

ip tunnel add is0 mode isatap local 192.168.170.200 ttl 64
ip link set is0 up
ip addr add 2001:470:1f05:f53::5efe:192.168.170.200/64 dev is0

I put three lines into a little script and placed it in the /etc/network/if-up.d folder for convenience reasons.

Next install the advertisement daemon, which should be available on any mainstream Linux distribution (aptitude install radvd on Debian). Create the config file, start your daemon and the router should be good to go:

interface is0 {
        AdvSendAdvert on;
        UnicastOnly on;
        prefix 2001:470:1f05:f53::/64 {
                AdvOnLink on;
                AdvRouterAddr on;
        };
};

Just replace the IPv6 network whatever your tunnelbroker provided you with. If you choose to fumble with the different configuration options just remember to keep the UnicastOnly option. It is required for ISATAP to work.

Client settings

Hope I remember this correctly but I think I just had to install the isatapd daemon (aptitude install isatapd on Debian). I'm using all the default settings so I didn't set up a separate config file. If you're using more custom options (e.g. for an interface name other than is0) you'd have to create a config file at /etc/isatapd.conf?

I however had to go into the init.d file (/etc/init.d/isatapd) and change line 29 to ISATAP_ROUTERS="fluffy" and you most certainly will have to, too. Use the hostname corresponding with the router's private IP.

DNS

As for forward DNS you should be able to simply create AAAA records using your nameserver provider's administration console just like you would do with A records for IPv4 addresses. For each host name I have one IPv4 and one IPv6 address assigned.

DNS isn't really all that different. For reverse DNS I just use Hurricane Electric's free service. With a little bit of extra effort you can however ns3 or whatever daemon you prefer to do the job as well. There's actually a pretty good how-to on that.

I also set up bind as a DNS cache for Hurricane Electric's IPv6 server on my router instead of just adding their server to /etc/resolv.conf. My configuration file (/etc/bind/named.conf.options) looks like this:

acl cloud.local {
  localhost;
  192.168.128.0/17;       // your LAN via IPv4
  2001:470:1f05:f53::/64; // your tunnel IPv6 /64
  2001:470:1f04:f53::/64; // your routed IPv6 /64
};

options {
  directory "/var/cache/bind";
  allow-query { cloud.local; };
  forwarders {
    2001:470:20::2;
    [...]
  };
  auth-nxdomain no;    # conform to RFC1035
  listen-on-v6 { any; };
};

Further reading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment