Bidirectionnal UDP tunnel (in TCP) as a temporary work-around
Why IPv6
I started conferencing about
IPv6 in 1995 (at that time it used to be called IPng, for IP Next Generation, like in Star Trek). I set up my first IPv6 link in 1999 or so. Then I lost interest for the subject, the progresses made were, in my opinion, too slow. Things have changed lately for various reasons (emerging countries and eastern countries not getting their share of IPv4 space, thus switching to IPv6; 6Bone getting a reality, for example).
How to connect to the IPv6 world
Basically two ways
The IPv6 on IPv4 tunnel way
To be able to make a
SIXXS IPv6-on-IPv4 tunnel, we need to be able to establish a IPv6 in IPv4 UDP datagram exchange:
However, in our case, we have a few more problems to care about, because the client will be in an
OpenVZ virtual machine, with private IP address 192.168.99.105, NATed. No
problem, because the above tunnelling protocol
does support NAT/PAT traversal (aka it doesn't hide tunnel end-point IP addresses or port numbers in the payload!):
Note that we did not specify the IPv6 addresses that the Client and the Server must possess above. From the Internet (IPv4) point of view, the IPv6 over IPv4 tunnel traffic is simply a set of UDP IPv4
datagrams. Only the Client and Server interpret the payload.
Additional problem: POP unreachable
Unfortunately, 194.1.163.40 is
not reachable from either of my providers (Cablecom (net2000) CATV, Sunrise ADSL). As a temporary measure, I can create another tunnel
from 80.83.54.2 to a
green host where I have shell access, so that the actual data exchange is done from there: but the datagram payload is exchanged through
a TCP tunnel (a TCP tunnel is easier for firewall reasons; however of course it violates the UDP quality of service: we don't care in this application)
This will only work if 194.1.163.40 does NOT verify the from UDP address is the same as the AYIYA login, and/or this address is not specified in the packet payload.
It seems to be the case, so it works.
Of course, without changing the software on the client, you need to have a few DNAT/SNAT tricks on the NAT system, so to make think the client that the real server is talking directly, where in reality it is the entry point into
the TCP tunnel.
Oh, and what I did hide in the above is that Relay has a private address: it connects the server through another NAT.
Existing tunnelling software
Unfortunately, the
udptunnel software available in Debian lenny doesn't support bidirectionnal phantom/fix tunnelling, because its main use is tunnelling RTP (e.g. audio
telephony) conversations, which happens generally between two well-known ports. Thus, the easiest is probably to either reuse my C virtual_client (TCP) I wrote in 1996 or so, or, to be a bit more modern and
actually learn something new, so do it in Perl. I chose the latter option.
My new implementation
- A quick and dirty Perl program
- protocol is quite simple: two bytes indicates the UDP payload in bytes, network order (big endian), then comes the UDP payload raw.
- we count on TCP to not desynchronize
- we have special care for partial data
- we didn't disable NAGLE
The real picture of what is happening
In short, this is what happens:
- we start the aiccu client on the client, it starts sending IPv6 as payload of UDPv4 frames, from its private IP 192.168.99.105 and a phantom port (dynamically allocated), to 194.1.163.40 port 5072 (this comes from a negociation that aiccu does at start, with tic.sixxs.net)
- our DNAT makes so the destination (194.1.163.40:5072) gets rewritten to the private side of the NAT, port 5073 -- there are reasons for this special port that I won't detail here
- we start the TCP relay server on NAT, listening to 80.83.54.2:9999 (TCP), and relaying private-NAT:5073 to the tunnel and back
- we start the TCP relay client on Relay: it TCP connects to 80.83.54.2:9999 (happens through another NAT, but that has no impact), it relays any datagram received on the TCP tunnel to 194.1.163.40:5072 and the other way round too. It uses the same port number as the client for the UDP side, even if we don't think it matters.
- for datagrams coming from the POP, a special SNAT rule on the NAT system makes sure the client isn't confused by the return direction having another address.
We could have done it simpler
If the whole virtual system where the client runs was IPv6-compatible, all this address rewriting could have been avoided: the IPv6-over-IPv4 tunnel would have simply be run from the real machine.
However, my goal was to run the whole IPv6 subsystem
in a virtual machine, not to migrate the whole virtual system to IPv6, yet!
It works!
This gives more than 100 ms ping6 to the other end of the tunnel, but it works:
vz6:~# ping6 -c 3 2001:41e0:ff00:30::1
PING 2001:41e0:ff00:30::1(2001:41e0:ff00:30::1) 56 data bytes
64 bytes from 2001:41e0:ff00:30::1: icmp_seq=1 ttl=64 time=136 ms
64 bytes from 2001:41e0:ff00:30::1: icmp_seq=2 ttl=64 time=129 ms
64 bytes from 2001:41e0:ff00:30::1: icmp_seq=3 ttl=64 time=127 ms
--- 2001:41e0:ff00:30::1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2011ms
rtt min/avg/max/mdev = 127.894/131.089/136.159/3.625 ms
vz6:~# traceroute6 www.switch.ch
traceroute to www.switch.ch (2001:620:0:1b::b), 30 hops max, 40 byte packets
1 gw-49.zrh-01.ch.sixxs.net (2001:41e0:ff00:30::1) 97.959 ms 97.716 ms 97.622 ms
2 xen-gw.zrh.sixxs.net (2001:41e0:ff00::1) 97.528 ms 97.441 ms 97.361 ms
3 ipman.zrh.sixxs.net (2001:41e0:fe00:1::1) 97.274 ms 107.240 ms 107.643 ms
4 ge0-3.br01.zrh254.ipv6.ip-man.net (2001:41e0:100::1) 107.983 ms 109.035 ms 109.416 ms
5 2001:41e0:4::39 (2001:41e0:4::39) 150.873 ms 151.315 ms 151.998 ms
6 2001:41e0::1122 (2001:41e0::1122) 152.356 ms 84.435 ms 84.791 ms
7 switch.ipv6.cixp.ch (2001:7f8:1c:24a::22f:1) 117.851 ms 118.271 ms 118.956 ms
8 swiLS2-10GE-1-3.switch.ch (2001:620:0:c006::2) 119.312 ms 119.675 ms 112.880 ms
9 swiAM1-10GE-1-4.switch.ch (2001:620:0:c048::1) 112.866 ms 112.291 ms 111.807 ms
10 oreius.switch.ch (2001:620:0:1b::b) 143.820 ms 101.705 ms 101.427 ms
--
MarcSCHAEFER - 05 Jan 2010