NAT IPv4 holepunching nattraversal

8 oct 2009

today i wanted to play a game of spring [1] with a friend but it didn’t work. i was using windows xp (not linux but yes this is even more usual there) and i downloaded spring with the nice little lobby called ‘springlobby’. i even remembered my login for the lobby interface. after connecting we wanted to use skype which didn’t work for about 15minutes (yes i was using my linux laptop and the sound there usually suckz as it tends to block the soundcard for some unknown reason quite often). but the problem was also the new account on the other end which had to be created but which didn’t work. after a couple of skype restarts on both sides it was starting to work. (not mentioning the issue of adding a new contact…).

so the lobby was running and we could talk using skype, what else could go wrong?

right after wards i hosted a game (i didn’t expect it to work since i didn’t do any manual port forwarding for the kind of random ip i usually have). i didn’t see the ‘nat traversal’ option in springlobby first (because i tend to join other games instead of hosting exactly for this kind of issue). so the game failed but to detect it - especially if several ppl join your game - you have to launch the game. so the game starts in fullscreen (it’s an opengl application) and computes some routes (waypoints or whatever) which is important for the ai (also for the own units) for pathfinding. waiting about 40 seconds to see that the connection didn’t work.

so next i rehosted the game using ‘nat traversal’ clicked. but it didn’t work either. no error message and no diagnostics of the issue. just a silent fail - which is what i tend to hate most (except a silent fail after a timeout which i even hate more).

finally my friend tried to host a game (he is also behind NAT - but who is not nowadays?). of course the same problem - it didn’t work. but skype once the audio part worked keept working. skype managed to traverse the NAT (or at least was using a relay we didn’t know of - which is the usual fallback used by skype, see [2]).

this reminded me however of the solution for this problem i was thinking of quite some time ago when i wrote a lobbyclient myself [3] together with two friends.

the question is: “how to establish a connection before game launch?”

two answer this question we will have a look at how a game launch works right now.

  1. using springlobby to connect the the tasserver (that is the springlobby server which hosts the chat and the game preparation - a chatroom exchanging the gamedetails as map/teams and the ip of the server)
  2. in springlobby creating new game -> ‘host a game’
  3. other players see this game in a list and join it (the tasprotocol is quite ugly but this is not of interest now)
  4. now every player (not the hoster) has to click ‘ready’
  5. finally the game is launched by the hoster (the administrator of the game) and the hoster sends it’s IP along with a UDP Port to the other players.
  6. now a config file is created in every client, a special config is created for the hoster (hoster = server)
  7. the clients try to connect to the hoster (if the hoster isn’t already done with starting the game, which can take a while as seen above, the clients reconnect every few secons until a timeout of 40 seconds is reached). please note that while the player is waiting for that timeout he can’t read the chat log since he is already ingame which is usability wise a horrible thing to do. you can’t inform the player that the game won’t work (in case you know that already for some reason)
  8. now after the hoster managed to start the game the clients connect and the player label color changes from red (not connection yet) to green (player has successfully connected)
  9. in case every player is connected … the game can start

say the game connection didn’t work for at least one player and say an average game is joined by 4-8 ppl. please think of the time each player has to wait in average to detect a network issue. believe me ‘it is a lot of time’ and this made the ‘autohost’ function very popular.

the autohost is a game hosted by a nice person which has a computer running 24/7 with some game starter script. if a programmed bot in the gameroom parses the chat of the players and detects some string as “!start” from the ‘virtual hoster’ the game is launched and spring.exe starts (that is the game binary). since spring.exe can’t be run dedicated it is not only a waste of power/bandwidth but also a waste of workspace. i expect the game to be run in the background but still this has lots of performance loss for the user.

autohosting is a nice thing for players but it seems - at least for me - be more like a workaround for a technological problem not solved properly.

the fix i was talking of is this:

when the ‘hoster’ is hosting a game the ‘hoster’ starts a udp-server on a random port (which is known after starting the server of course). the ip and port are then automatically given to the other players. now every player tries to connect to that ip:port right away without launching spring.exe and without creating a configuration file. if the connection from player to the hoster is working a green LED in the springlobby will light up and everyone sees the status immediately. when the game launches every client then connects - not the the hoster ip:port - but instead to localhost:port.

so now we need a tiny relay udp server with hole punching capabilities and as some might like UPnP network capabilities.

client1 (192.168.1.22) –lan– fritz!box (192.168.1.1) —– inet —————–many routers —————— inet —– fritz!box (192.168.1.1) —-lan— client2 (192.168.1.33)

as you can see both clients reside in the same subnets but this is no issue since both subnets (192.168.1.x/24) are in an address space which isn’t routed in the ipv4 internet definition and since both clients are routed by a router (fritzbox in this case, can be any other vendor as well) both are behind NAT (network address translation) - which is our problem in the first place.

our small udpserver (i call it “udpPuncher”) would require:

  • relaying udp packets from one ip to another, no parsing of the udp packets at all
  • libNAT (to have UPnP capabilities)
  • holepunching (a udp nat traversal technique which is quite common)
  • and some interface (either a socket or a dbus like interface) to control and query the relay
  • some easy logic to report to the springlobby that the playerX has successfully connected to the hoster

so you might say that is no new technology.

  • maybe not but don’t forget that most games are hosted by expensive servers (battle.net from blizzard or others). some games have a dedicated client (very often a even a linux client) you can install and run on a internetserver which is not behind a NAT and which has lots of bandwidth (most important aspect here is the upload speed and latency).

i’ve never seen such a udpserver or library. all i know are a couple of projects trying to solve that issue. take sip as an example - they have the same problem there and they often give you a stun server (udp holepunching) to relay connection establishment.

there was a nice project i came along [4] which checked the NAT capabilities of your own network (there was a linux and a windows client). i’m not sure about the results but this could be used to qualify the network NAT type in an attempt to write the not yet written udpPuncher.

ipv6 would be a nice solution but i doubt this will be here soon as nobody seems to have interest in ipv6.

#links * [1] http://springrts.com * [2] http://en.wikipedia.org/wiki/Skype_protocol * [3] http://code.google.com/p/qtlobby/ * [4] http://nattest.net.in.tum.de/?mod=infos&lan=de

UPDATE:

I just found out that [4] is not new at all (maybe it is but not but at least for me it is), i’ve read [5] some long time ago but didn’t remember it. Now here is a very detailed documentation about NAT with illustrated (but not animated ;-P) examples of usage:

article source