StarCraft and NAT issues
- Documentation
- • LAG
- • NAT
- • Networking
- • StarCraft
Recently I set up PvPGN server to host StarCraft games and had to solve some lag problems when people behind NAT tried to play the game. In this post I try to summarize my experience and hope it can be useful for others, as there’s not that much info available on this topic, it seems.
Disclaimer
This post was written for people who are familiar with iptables, NAT concepts and networking concepts “in general”, and who already read, understood and tried applying the network setup listed in PvPGN documentation. There’s absolutely no point in asking questions here like “I do not know (and do not care) what it is all about, JUST TELL ME WHAT SHOULD I DO, STEP BY STEP,TO GET THIS DAMN THING WORKING!!!”
I also do not cover here server installation/configuration and firewall configuration for server, as it’s explained in PvPGN documentation, particularly on their NAT / Firewall or TCP/IP Addressing page.
StarCraft LAG problem
If you’re reading this there’s a chance you already know what I’m talking about Anyway, by the “lag problem” here I mean constant and extreme delays during the game when these delays are not the result of network latency or its low speed, but rather network configuration problem.
There are the following pre-conditions for the problem to occur:
- More than one player behind the NAT on the same local network, I will call them the “local” ones.
- At least one player that is not on the same local network as other players, I will call him the “external” one.
PvPGN NAT / Firewall or TCP/IP Addressing page discusses this issue in “StarCraft and LAG” section and proposes solution, but unfortunately it didn’t work for me straight out of the box.
Some other pages about this problem: StarCraft NAT, StarCraft and NAT - they, however, do not get enough into details of why the thing is happening in the first place, and thus offer only partial solution to the problem.
Therefore I had to perform some brief analysis with WireShark and, combining that with PvPGN documentation plus some extra info found on the Net, I’ve got the following picture on how things are working. While I might be wrong at some details and results can depend also on other factors, such as game/server versions or things like that, it shouldn’t be really important for general understanding of the problem. Note that by the “address” here I mean the “IP:port” pair.
- PvPGN server is used only for game setup, all actual communication during the game happens directly between players - this means that each player should be able to contact directly all other players.
- When new game is created, the player that becomes game server registers itself on the PvPGN server as game server.
- When players want to connect to the game they ask PvPGN server for the address of the game server. PvPGN server performs address translations of the game server address as specified in PvPGN address_translation.conf file.
- Having game server address, players connect to game server and ask game server for addresses of other players connected to this game.
- Once all players have each other addresses they exchange info with each other directly using these addresses.
Once more, the actual schema is most likely different, but this description should be enough to understand where the problem is: PvPGN address translation seems to be applied only to game server IP translation, not to other players addresses!
This description allows explaining easily what happens when different players become game server and PvPGN address translation is specified in the way suggested in their documentation:
“External” player hosts the game: “local” players receive its address from PvPGN server unchanged and are able to communicate with it correctly. However, once first “local” player asks for the address of the second one, game server returns the address that it “sees” when receiving messages from the second player, which in the case of NAT is external address. Then first “local” player tries to use received address to communicate with the second “local” player and the outcome of that attempt completely depends on network configuration: if the router is configured in the way that permits communication between local clients through the external address (by setting SNAT/DNAT appropriately) - things will work OK, if not - LAG problem will occur. Firewall rules suggested in PvPGN documentation in fact enable communication between local clients through the external address, though they do not explicitly mention this effect in their documentation.
One of “local” players hosts the game: “external” player receives translated game server address from PvPGN, so he is able to connect to game server correctly. For the second “local” player things are different, however: if we assume that PvPGN server is inside local network, then game server address is returned to second “local” player unchanged and thus it communicates with it directly over local network. Therefore, when “external” player asks game server for second “local” player address, the internal address is returned - as it’s the address game server sees the messages from second “local” player coming from. Therefore “external” player is not able then to communicate with second “local” player, as it does not have its correct, external address.
Therefore, if there’s a need in “complete” solution, which works reliably not depending on where the game is hosted, the following steps should be done:
- Follow PvPGN documentation to ensure there are communication paths between all players.
- Especially, make sure “local” players can communicate between each other using their external addresses! This should be the case by default if you use firewall rules from PvPGN documentation, but also make sure you do not have other rules that might block the appropriate packets. It might be a good idea to try playing the game with “local” players only, run WireShark and check that packets are in fact coming through the external addresses.
- Do not use exclusion ranges when specifying translation rules in address_translation.conf: i.e. instead of
192.168.10.199:16199 245.012.10.1:16199 192.168.10.0/24 ANY
lines use192.168.10.199:16199 245.012.10.1:16199 NONE ANY
.
With this kind of setup all players will communicate with each other using external addresses. This can place slightly higher load on your router, though it shouldn’t be a problem as traffic is very low. However, this pays off by the fact that all players are “equal” and contact each other in uniform & consistent way not depending on the game server location.
Moreover, I believe that the same configuration should be applicable to playing on Battle.Net official servers also, though I haven’t tested it myself.
- NDL's blog
- • Login to post comments
Hmm. I am not trying to use
Hmm. I am not trying to use PvPGN server; just trying to get BNET with two local comps that can host a 2v2 game online.
I have gotten it to the degree of the "StarCraft and NAT", where both players can join without lag but cannot host without lag.
What is truly odd is that despite my iptables, it still says in WireShark that all traffic is occuring on 6112.
These are my iptable entries
iptables -t nat -I PREROUTING -p udp -d $(nvram get wan_ipaddr) --dport 63002 -j DNAT --to 192.168.1.100:6112
iptables -t nat -I POSTROUTING -p udp -s 192.168.1.100 --sport 6112 -j SNAT --to $(nvram get wan_ipaddr):63002
iptables -t nat -I PREROUTING -p udp -d $(nvram get wan_ipaddr) --dport 63003 -j DNAT --to 192.168.1.102:6112
iptables -t nat -I POSTROUTING -p udp -s 192.168.1.102 --sport 6112 -j SNAT --to $(nvram get wan_ipaddr):63003
Ports mapping
In fact I would recommend to avoid changing ports during SNAT/DNAT mapping, so instead of mapping 6112 to/from 63002 and to/from 63003 respectively it’s better to use direct mapping: external 63002 to internal 63002 and external 63003 ro internal 63003. You will need to change “Game data port” for clients in registry, of course. While in theory your approach should also work, on practice sometimes it doesn’t - see, for example, this thread, I had similar problems during my setup (on openwrt router), but I think I also saw somewhere similar reports for systems other than openwrt-based ones.
You may also want to check iptables statistics on router to verify packets are indeed coming to DNAT’ed rules, I mean smth like
iptables -t nat -L -v
. If you have such possibility, taking packets dump with tcpdump on router may be also a good option for further analysis.I have WireShark running to
I have WireShark running to see my UDP connections made in StarCraft even after my iptables. It repeatedly still says that traffic is on 6112. Is this normal? Also, on BNET the computers seem to get traffic on internal clients from the LAN IP instead of external IP. How do you force it to route out to use external IP?
StarCraft "external" routing issues
For clients - no, it isn’t. The only traffic going from/to 6112 after things are set up correctly should be the traffic from/to PvPGN server, if you have one. Have you set up
Game Data Port
in registry for every client, as suggested in NAT / Firewall or TCP/IP Addressing guide?Hm, I’m not 100% sure I understood you correctly, but if you capture the traffic inside your local network coming from external players or server - destination addresses are of course local, as they’re processed by NAT.
In the case of correct setup traffic from the first local client (LIP1:LPORT1) to the second one (LIP2:LPORT2) captured at first client should look like:
From LIP1:LPORT1 to EIP:LPORT2
, and on the second client:From EIP:LPORT1 to LIP2:LPORT2
.$IPT -t nat -A PREROUTING -p udp -d $EXT_IP --dport $PORT_II -j DNAT --to-destination $HOST:$PORT_II
and$IPT -t nat -A POSTROUTING -p udp -s $HOST --sport $PORT_II -j SNAT --to-source $EXT_IP:$PORT_II
To check your setup without using StarCraft you may want to set up SNAT/DNAT mappings first not for UDP, but for TCP and then use telnet (or anything that generates TCP packets at specified ports) + WireShark at both local clients to verify packets are routed correctly through the external IP. Alternatively you can use nmap for sending UDP packets, then you can use the ‘real’ SNAT/DNAT setup directly for testing.