IPv6 in userspace

Introduction

This document describes, how a internet server with a static ipv4 address can be connected to ipv6. The common way to achieve this would be to use the ipv6 support of the operating system and use 6in4 tunneling techniques, if no native ipv6 from your ISP is available.

But the situation described here is more challenging: The server is a virtual server (vserver) and runs a linux kernel that doesn't have ipv6 support. And it's not possible to replace the kernel. As the kernel and the libc both don't support ipv6, the applications (like apache) don't know ipv6 either.

But is it still possible to connect this vserver to ipv6? Yes, it is. The solution is to do all ipv6 stuff in userspace. Ok, that's no solution for productive use, but that's not the point. It's theoretically possible, so let's do it.

IPv6

What is IPv6? It is the so called "next generation internet protocol" and replaces the old ipv4 internet protocol. With IPv4 there exists mainly one problem: the lack of free addresses. So there were many workarounds developed as NAT (network address translation), CIDR (classless inter-domain routing) and dynamic addresses. All of these "workarounds" make network applications much more complicated. IPv6 will provide a much bigger address space. Some numbers to compare: IPv4 addresses use 32 bits. That means that about 232 ~ 4.2 billions different addresses are possible (but not all of them are usable, some are reserved for private networks or for multicast). IPv6 addresses use 128 bits, which should provide enough addresses to connect everything to the internet. The bigger address space is not the only improvement of ipv6. Others are e.g. auto configuration, renumbering, fixed header size for routing optimization. See IPv6 article in wikipedia.

The main difference between ipv4 and ipv6 is the concept of subnets. With ipv4 it was possible to divide a subnet into several smaller subnets. IPv6 knows only one subnet size: 64 bit. This is the smallest subnet which means that one ipv6 subnet is actually bigger than the whole ipv4 address space. The 64 bit are necessary as with the stateless autoconfiguration of ipv6 every host calculates its ip address with the help of the MAC address of the network interface. This MAC address is 48 bit long and should be worldwide unique.

Generally you will get a 48 bit or 56 bit long prefix from you isp, e.g. 2001:0DB8:1234::/48 or 2001:0DB8:1235:AB::/56. This means that you could divide your network into 65536 subnets (for 48 prefixes) or 256 subnets (for 56 prefixes). And each subnet could contain as much hosts as possible (at least 264 hosts which should be enough).

How IPv4 and IPv6 are connected

IPv6 will not replace IPv4 immediately. It's not possible to switch ipv4 off and ipv6 on at once because not every router in the internet supports ipv6. So the transition to ipv6 will take a long time and in the meanwhile there exist two networks. But there are techniques to connect the networks so that a smooth transition to ipv6 is possible: dual stack and 6to4. Dual stack means that a server is reachable with both a ipv4 and a ipv6 address. And 6to4 is a technique to transmit ipv6 packages in the old ipv4 network.

This 6to4 technique is described in the RFCs 3056 and 3068 and works as follows:
Every ipv4 host gets a special ipv6 address (to be exact, it gets a whole ipv6 address space). If the ipv4 host wants to send data to an ipv6 host, it will encapsulate the ipv6 packet into a standard ipv4 packet and send it to a special relay router. This router is connected to ipv4 and ipv6 natively. It will extract the ipv6 packet and will forward it. That's one way. The other way, if the addressed ipv6 host wants to send an answer, it sends the packet simply back. The routers in the ipv6 network see that this is a special ipv6 packet (because of the special ipv6 destination address) and will forward it to a relay router. This router will then encapsulate the answer packet into a ipv4 packet and send it to the ipv4 host. The two mentioned relay routers are not neccessary the same. Every packet is sent independent from the others and may use different relay routers.

Addresses

To use this 6to4 stuff, the ipv4 host needs a public ipv4 address. This address will be mapped to 2002:V4ADDR::/48. For example, the address 192.1.2.3 will use the ipv6 prefix 2002:c001:0203::/48. As you see, the ipv4 address is included as a hexadecimal number in the ipv6 address.

The ipv4 host has to use a ipv6 address from this address space as source address in ipv6 packets. Any ipv6 packets in the ipv6 network with destination address out of this address space will be forwarded to the ipv4 host, encapsulated in ipv4 packets.

To make life easier, the relay servers, that will forward packets into the ipv6 network, have a anycast ipv4 address: 192.88.99.1. With this address, you will reach the nearest 6to4 relay router.

Header

To transmit the ipv6 packets through the ipv4 world, they are encapsulated. A standard ipv4 header with protocol type protocol 41 will be used. Protocol 41 is the protocol number for ipv6. So ipv6 will be transmitted just like TCP (protocol number 6) or UDP (protocol number 17). If you use tcp via ipv6 from the ipv4 host, the following protocol stack (layer 3 and above) will be used: ipv4(ipv6(tcp)).

Problem description and expectations

The new program, that will run in userspace without any support from the kernel, has to to the following: Receive all packets for protocol 41 (that is all ipv4 packets that carry ipv6 data), unwrap the ipv6 data and interpret it. ICMP echo request shall be answered, other packets, suchs as UDP and TCP, have to be forwarded to a server process. This forwarding means that the UDP/TCP data is encapsulated in ipv4 and transmitted. On the other side, the userspace program has to catch all answers from the server processes, build a ipv6 packet, put this in a ipv4 packet and send this to the 6to4-gateway.

In order to do no changes at all for the current server process, the forwarding has to be done via the loopback interface. But it's in principle not limited to loopback, the program could forward the packets to an other server with an own ip address.

Implementation

The program is written in Perl and in order to learn more about the headers of ipv4, ipv6, icmp, icmpv6, tcp, udp, only the core modules of perl are needed. So everything to interpret the packets is done manually.

Basic workflow

- main loop
- open a sniffing socket, listen for any packet
- open a second socket, to send custom packets
- wait for a received packet
- analyze it
- in case of icmp echo request, send a echo reply back
- in case of a tcp/udp packet, forward the packet, if a rule exists
- otherwise send a tpc rst or icmp

Alternative workflow for ping

- main loop
- send a ping (echo request) every second

Configuration

- of perl program
- of host: mtu of loopback interface, iptables: drop RST on loopback

Conclusion

- possible improvements: socket filter,
- NAT support (works it behind a NAT firewall?)
- limitations (high traffic??)
- nevertheless: it is possible
- How you would do it correctly: use linux support: sit, or a tunnel broker (e.g. sixxs.net)

printf "2002:%02x%02x:%02x%02x::/64\n" a b c d # if ipv4 address is a.b.c.d
ip tunnel add sit1 mode sit remote 192.88.99.1 ttl 64
ip link set dev sit1 up
ip -6 address add 2002:xxxx:xxxx::/64 dev sit1
ip -6 route add ::/0 dev sit1
© 2010 adabolo.de (2010/03/21)