| CARVIEW |
Tiberian Sun IPv6 patch
This is the page of my IPv6 patch for Tiberian Sun, a game originally made by Westwood and recently rereleased as freeware by Electronic Arts (the current rights holder).
It is in all imaginable ways a horrible, detestable hack (see below for technical details), and should of course be considered proof-of-concept above anything else. It does, however, work pretty well for me, and allows Nod to take over the world even in the future dystopia of pervasive double-NATed IPv4. :-)
Download
Tiberian Sun IPv6 patch 0.1 (44 kB, includes source). See below for installation instructions.
Installation
NOTE: You will need Windows Vista or newer for this to work. (WINE 1.2 prereleases or newer also work fine—in fact WINE was my primary development platform—but I've had reports that WINE 1.0 doesn't work.) Specifically, Windows XP will not cut it, even if you've enabled IPv6 manually.
- Make sure you have IPv6 connectivity somehow. (I cannot help you with this part, but Teredo/6to4 connectivity will do fine for testing.)
- Download and install the multiplayer-only XWIS-patched version of Tiberian Sun from here (download by XWIS, 49.5 MB). Note that the official (single-player-enabled) release you'll get from EA seems to have lots of problems with Internet play on modern versions of Windows, so you want the XWIS version.
- Unzip the patch file into the Tiberian Sun program directory (usually something like C:\Program Files\Tiberian Sun), overwriting files as needed. (Note that what this essentially does is renaming language.dll to languageorig.dll, and then add a new language.dll.)
- Launch the game as usual. Note that the copyright notice (lower right on the main menu screen) should have changed to reflect that the IPv6 patch is enabled.
- Select Multiplayer → Internet, find a game, and have fun. :-) IPv6 will be used transparently for communicating with other IPv6-enabled players. (For playing against IPv4-only players, you still need working IPv4 port forwards.)
Rationale
The big question is, of course, why? There are many reasons, some perhaps more than others:
- To demonstrate that IPv6 not that hard—when one guy even without the source can add IPv6 support to a full, commercial game, the number of excuses are sort of growing thin. (Even as of 2010, I don't know a single commercial game that ships with IPv6 support, although support in free software is abundant.) The two-way translation technique discussed below may or may not be useful for IPv6-enabling legacy software, although full support would of course be better.
- To generate just a tiny bit more stir about IPv6, whose deployment is getting more urgent by the day.
- To keep multiplayer support for a true classic even as the world goes to a point where even a single layer of NAT with port forwards will stop being feasible.
- To learn more about reverse engineering and binary patching (it's fun!).
- And last but not least, because I got annoyed that I had to set up port forwards just to play a game. :-)
Bugs/limitations
- Currently (as of version 0.1) you're being sent to a special test server, due to lack of IPv6 support in the production server. You may find this a bit lonely.
- Uses dualstack sockets liberally. This means: No Windows XP support. On Linux systems, make sure bindv6only is set to 0 (echo 0 > /proc/sys/net/ipv6/bindv6only); especially recent versions of Debian have changed this from the default.
- Still contacts the server over IPv4 only, mostly by design (so it will know your true IPv4 address to give out to IPv4 participants). In other words, you cannot run this in an IPv6-only environment unless you do weird DNS trickery et al.
- No IPv6 ping support, so all IPv6 participants will appear as 1000ms+ away. Mostly because WINE doesn't support IPv6 ping, so I didn't have a proper way of testing. :-)
- Poor handling of IPv6 privacy addresses and other temporary addresses. (They should not really be announced to other players, but are nevertheless.) In particular, this means that if you're logged in for a very long time (24h+), you can start having problems communicating with other players. Just log out and in again.
Technical details
A small list of subproblems to tackle for a binary patch like this; mostly for the sufficiently perverse. Probably quite uninteresting if you're not into programming.
Injecting code
First, we need to somehow get our code into the Tiberian Sun process. There are many ways of doing this, but the simplest is to put it into a DLL (which gets its own address space, can have its own imports, etc.) and make the process somehow load that DLL. (On DLL load, DllMain() is called, from which we can do pretty much whatever we want to the process.)
Tiberian Sun is bilingual (English/German) and uses a file called language.dll to store its message resources. This DLL is the only one loaded before any networking code, so it's an obviou target for us. We simply move the original DLL out of the way (to languageorig.dll) and put our own code there instead. Any requests for the language resources are just proxied on to languageorig.dll, so the effect on the messages displayed is zero.
IPv6 packet support
In order to reduce complexity (changing data structure using binary patching is very cumbersome), all Tiberian Sun networking code still believes it's talking IPv4. To this extent, a technique that looks a bit like a weird inverse form of NAT-PT is used; whenever we need to talk to an IPv6 address, an IPv4 address from unused address space (224.0.0.0/3) is allocated, and that address is the one the game sees. (This works because although there's trillions and trillions of IPv6 addresses out there, a typical program doen't need to talk to more than a couple of hundred or thousand during its lifetime.)
We put a small layer between Tiberian Sun and the Winsock layer that deals with this patching (mostly by changing the entries in the import tables to point to our own functions). Whenever it sees attempts at IPv4 communication with one of these special addresses, it looks up that address in its translation table and sends that request over IPv6 instead. Similarly, inbound traffic from IPv6 hosts is rewritten to one of these shim addresses. Also, of course, all attempts to open IPv4 sockets are replaced by attempts to open dual-stack IPv4/IPv6 sockets instead.
IPv6 protocol support
Being able to talk IPv6 is not very useful without others knowing how to contact you. To this end, the Tiberian Sun lobby protocol has been extended using a few extra commands—and thanks to Olof van der Spek of XWIS (who currently runs the Tiberian Sun servers on a community basis), the server understands these extensions.
The protocol used actually looks a lot like IRC (although with a ton of weird extensions), so it's text-based and relatively easy to understand. The main extra change is that the places that usually hold an IPv4 address (for some reason specified in decimal form, so 1.2.3.4 becomes 0x04030201 = 67305985) can also hold an IPv6 address. Colon (:) has a special meaning in the IRC protocol, and the game's protocol parser is pretty rudimentary, so to avoid confusion addresses are sent back and forth with underscores instead (e.g. 2001_700_300_1880__2). Parsing of these addresses happen a few places, but they all happen to call atol(), so by redirecting that function into something that can handle IPv6 addresses (and add IPv4 translation entries as needed) the parsing problem is solved as well. :-)
Finally the client needs to give out an IPv6 address where it can be contacted (using a new command, IPV6ADDR), since the client typically connects over IPv4 (otherwise, we'd need to find and report the IPv4 address, which is a lot harder due to NAT). This is one of the few places where there's actual code patching going on, as opposed to just redirecting functions; some extra code is patched into the initial handshake to find a usable IPv6 address and report it.
Credits
- EA Software very graciously re-released Tiberian Sun as freeware, as part of the tenth C&C anniversary. Without this, this project would probably never have existed.
- Steinar H. Gunderson (that is me) made the binary patch itself, and this page.
- Olof van der Spek added IPv6 support on the central Tiberian Sun servers.
- Several other people helped with testing.
Last updated July 28th, 2010.