Surprising applications to sandboxing and network namespaces: the case of Command & Conquer 3: Tiberium Wars

Original version: 2022-03-02.
Last update: 2022-03-23T15:39:41-04:00.
2 minutes of reading time

Command & Conquer 3 : Tiberium Wars

This is a RTS1 game that I play a lot as I know it well, so, sometimes I wound up re-running the game.

Nowadays, I do not run anymore Windows except for Call of Duty, Black Desert Online and other annoying games.

Plus, Proton / Wine got a lot better, with an awesome compatibility layer with Vulkan and Intel Graphics cards.

So here is the thing, I more than often wants to play with my friends, but CNC3 has a very bad netcode2 : it do not handle multiple Linux interfaces at all and it uses layer 2 networking features, e.g. broadcasting over UDP, to find out LAN games.

Most of the time, I want to play with friends across Internet, meaning I need some virtual private networking supporting layer 2 networking and the ability to force a specific interface for the game.

Solution 1 : bruteforce your way

Multiple VPN providers supports L2 networking, even WireGuard could do with some help3, pick one, mine was ZeroTier.

Now, how can I make it so CNC3 knows only about the ZeroTier interface? Well, enter network namespaces.

Interlude: Network namespaces

Network namespace is a Linux kernel feature akin to the family of “xxx namespaces”4, it provides an hermetic world for the network subsystem of the Linux kernel for your children processes.

It fits the bill here as we do want to make believe our CNC3 program that we only have one interface and this is the ZeroTier one.

Using GDF Ion Canon to play a game quickly

Well, building network namespaces requires reading documentation, I can actually do it, but it takes time and I really want to play.

Thanksfully for me, firejail packages a lot of sandboxing features, including network namespaces in a way I am interested in: providing a list of “allowed” interfaces in the target namespace.

So here we go, firejail --net=ztxxx wine CNC3.exe ; thanks firejail!

Does it work? Absolutely. Did I expect for it to work? At first, no. Now, thinking to what happened, it is obvious as wine is only translating Windows syscalls and they will fall in the kernel under the network namespace feature, there is no magic involved here, wine has no special right and this is the actual magic at work here.

This trick works too on LAN when your computer has too much interfaces and multiple paths but at the end, you just want to play on a very specific physical LAN.

Solution 2 : use actually proper network namespaces

Well, yes, use proper tools for the problem ahem ; anyway, unshare would do the job in theory, this is left as an exercise to the reader.

  1. Real-time strategy↩︎

  2. So bad, I should look into patching it myself, I guess, that would be faster than what I am going to describe here.↩︎

  3. I guess, some UDP relays stuff which would do unicast to everyone through some list of “connected” hosts.↩︎

  4. User namespaces, process namespaces, PID namespaces, etc.↩︎