Openra: IPv6 support

Created on 14 Apr 2017  路  16Comments  路  Source: OpenRA/OpenRA

Let's collect ideas how to implement this here.

Feature Meta Networking

Most helpful comment

Working implementation (tested locally):

MasterServer still lacks "Client"-Table. Will add this later.

All 16 comments

This can be combined with the support for multiple master servers as it is a similar problem.

Here is my idea based on separate master servers for IPv4 and IPv6:

  • Servers try to ping all master servers and ignore any connection errors unless all master servers failed.
  • Clients get the list from all master servers and ignore any connection errors unless all master servers failed.
  • Optional: Clients merge the server lists based on some sort of id.

It should be impossible to spoof server id so it has to be a shared secret between the server and all master servers or some sort of public key cryptography. I prefer public key cryptography because it doesn't require shared storage which is less scalable and can fail.

The id could be implemented by generating a new RSA keypair on each server start and then use that to sign all ping requests. The public key is used as the id for merging the server lists on the client. If the original content of ping requests is also sent to the client, it could even detect compromised master servers by verifying the signature of all server list entries.

My main concern is that confusing/mixing IPv6 support with master server redundancy will be a great way to make sure that we don't support either feature for the forseeable future. IPv4 vs IPv6 requires matching up and deduplicating game records, while redundancy requires having completely independent servers. Trying to match and deduplicate records across completely independent servers will require a lot of unwanted and unneeded complexity that I expect would sink any attempted implementations.

Life is a lot simpler if we have IPv4 vs IPv6 on the same server, and then as a completely separate feature (to be discussed in #2568) let the game talk to parallel or fallback master servers.

Seprate ipv4 and ip6 will either the server to list twice if someone supports both, or split the users into two groups. Having the option to provide an ipv4 and ipv6 for one server will solve this problem. My Idea:

  1. The Gameserver should call the list handler for master.openra.net using ipv4.
  2. Either he gets an OK or ERROR (in case of he cannot host on ipv4)
  3. This handler will also return a special generated session-key. Noone else can see this key
  4. Then the server tries to call the master server with ipv6.

Now comes the special part: only if ipv4 was sucessfull, the ipv6 route gets added the session key.

MasterServer: If both requests were sucessfull, the ipv6 route will not list a new server, but instead add the ipv6 ip to the server in list.

This would allow ipv4 only users to play with ipv6 only users if the server is able to handle both.

Client: When listing servers, you actualy get the same list + the ipv4 and ipv6 adress, which is null or empty-string if not present. By checking wether ipv4 and ipv6 were available to the client at all before getting the server list, we can automatically filter servers which the client cannot connect to.

Also the result of this checks can be used to toggle the behavior which handlers to call upon hosting a game.

@IceReaper I prefer separate server lists for IPv4 and IPv6 because:

  • There is no need to show IPv4-only servers to an IPv6-only client and the other way around.
  • In case a new layer 3 protocol gets introduced, separate server lists are already compatible while your solution requires changes on the master server and probably all client versions too.
  • Separate server lists means that you can also have multiple servers for the same address family --> scalability and availability.

I implented IPv6 in other solutions. I would suggest:

  • Accept that IPv4 will be here still for at least 5 to 10 years: ( https://www.google.com/intl/nl/ipv6/statistics.html )
  • Almost all current implementations are dualstack or convert to an IPv4 (mainly mobile networks) before reaching the internet: Maybe on the exception of a few geeks, it will still be 5 to 10 years ahead before people will consider turning off IPv4.
  • Avoid splitting the community as much as possible.

I'm in favor of IceReaper's suggestion, but I would suggest to turn things around to make it future proof and IPv6 first, IPv4 second. But important, without damaging the full support of IPv4:

  • Detect if the server has IPv6 or only IPv4.

If it has IPv6, use IPv6 to connect to master.openra.net:

  • Register itself as a server with IPv6 AND IPv4 (if available).
  • To test IPv4, a seperate call could be made.
  • If a server registers with only Ipv6 and no ipv4, give a warning that majority of players can't join yet.

If it does not have IPv4, use IPv4 to connect to master.openra.net:

  • Register itself as a server with only IPv4.

A status added to the serverlist showing if it is dual, or only 4 or 6.

  • If the browsing client cannot handle IPv6, automatically hide all IPv6 servers in the list who do not have IPv4 (avoid frustration among users). This will be a minority of servers, as most can handle both.

In the master.openra.net database, there should be room for both types of IP Addresses.

  • In the game itself, if the client has an IPv6, it favors connecting using IPv6, only falls back to IPv4 if IPv6 is not available on the server.

Only the network code layer is different, the same code receives the commands and triggers the commands, the same internal game server is used for IPv6 and IPv4.

Working implementation (tested locally):

MasterServer still lacks "Client"-Table. Will add this later.

It looks fine to me except these things:

  • Announcing the IPv6 address will probably take a very long time if IPv4 connectivity is broken (blackholed or something similar).
  • The client requires IPv4 connectivity to get the server list AFAIK.
  • The dedicated server listens on IPv4 only AFAIK.
  • Hardcoding address families is not nice because that doesn't work if multiple layer 3 protocols are involved or new protocols are introduced.

It has to be tested on all possible combinations of no, broken (blackholed and / or ports closed) and full connectivity of both address families. I can provide a testing environment if someone needs it.

  • Announcing has to be done one after the other for the session to work out, except if there are some special networking problems. but even in that case, it will only take a little more time which is not that problematic in my eyes?
  • using my approach, default master... will listen on v4 and v6.
  • dedicated: doesnt it use the same game code to create the listen socket?

We are talking about a minute or more (depends on the os and os configuration). That's not "a little more time" for me.

So you mean that the dns name used by the client will have an A and an AAAA record while the server uses separate names for them? Which command line arguments can be used to override each of them?

The dedicated server uses it's own code to create the socked before passing it to the server logic.

My ISP out of the sudden just decided to update my modem (its a modem-router combination) remove my IPv4 connection and replace it with IPv6

needless to say that i cant port-forward any OpenRA-Server now , and i probably have to call and tell them to activate IPv4 again

I've managed to direct-connect to my server with @IceReaper 's https://github.com/IceReaper/OpenRA/tree/ipv6 ... so thats a success

Let me explain the procedure of my current idea.

Launch of the game server:

  • The game server generates a random RSA keypair for all following operations.
  • The game server asks all configured master servers for his current public addresses. Remove failed master servers from that list.

Ping to a master server:

  • The game server puts the current state into some yaml or json blob. This has to include the current timestamp and the public address which was returned by the master server when it was asked at launch (see below for the reason).
  • The game server signs the whole blob using his private key.
  • The game server sends the whole blob and its public key to the master server.
  • The master server validates the signature and the contained public address. If it passes, the blob and the public key are written into the unshared database.

Refresh of the client for a master server:

  • Get the current list from the master server.
  • Verify the signatures and remove all invalid entries.

After all responses are available or have timed out:

  • Merge the lists by public key. The entry with a higher timestamp overwrites the other except that the address lists are concatenated and duplicates removed.

Client wants to connect to a server list entry:

  • Clone the list of addresses into a new list.
  • (Optionally) shuffle the list.
  • Connect to the first address.

    • If successful --> break the loop and use the connection.

    • If not successful --> remove the first address and repeat.

    • If the list is empty --> show error message to the user.

This is the most reliable and future-proof method I could find so far. Because clients and servers always connect to all available master servers and have a timeout set, a broken connection does not prevent the announcement process. Also it doesn't show game servers to players if they can't connect anyway. Even though it has the side effect of providing the necessary changes for https://github.com/OpenRA/OpenRA/issues/2568, it isn't the only advantage over other approaches.

The list for load balancing already exists and can be done via SRV entries on DNS-servers. Microsoft is using it for Active Directory and Teamspeak 3 uses it to get the servers and its TDNS adresses using this method.

So the clients can search the SRV entry on open-ra.net and get the list of master servers. Also Game / Server hosting providers can make use of this advantage.

This also enables dynamic updates of hostnames for master servers, because they only needs to lookup the SRV entries and get the list of addresses, priority, weight and port.

In the old days of Westwood / EA, Game servers was anounced via ServerServ via IRC,
the syntax is here.
https://github.com/LipkeGu/pvpgn-server/blob/master/src/bnetd/handle_wserv.cpp#L162

SRV records are good for converting simple names into address+port pairs.

Because the master server(s) are running on the default port and their address hardcoded into the client anyway, it isn't that important for them. Priority and weight is useful for better control over the loadbalancing and failover process, but not that important as long as there is only a single master server anyway.

This is different for the direct connect dialog, where the name is entered by the user. For this situation, a service name registration with IANA would be a good idea if not basically required. But I think nearly all players connect through the master server announcements instead of the direct connect dialog.

The only way where it would really be useful imo requires a redesign of the announcement process to the master server. In the first step, the client would request the master server to create one or more SRV records for a random name under its domain. This would be skipped if the user configures a name explicitly. In the second step, it would then announce as usual, except that it uses the name instead of address+port.

I have previously today played with my hacked server, and I just noticed this issue now. I noticed that the tree linked above is gone, so here is the patch I use, if anybody needs a patch. The patch is simple, simply changes IPAddress.Any to IPAddress.IPv6Any:

[~/OpenRA-release-20200202] ack IPv6Any

OpenRA.Server/Program.cs
68:                             var server = new Server(new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), settings, modData, ServerType.Dedicated);


OpenRA.Game/Game.cs
900:                    server = new Server.Server(new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), settings, ModData, ServerType.Multiplayer);

@ysangkok That will break IPv4 connectivity if IPV6_V6ONLY is enabled (or not implemented at all like on BSDs). Take a look at https://github.com/OpenRA/OpenRA/pull/17571 for a better fix.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AliT1993 picture AliT1993  路  3Comments

Punsho picture Punsho  路  4Comments

MlemandPurrs picture MlemandPurrs  路  4Comments

TheMightyAltroll picture TheMightyAltroll  路  3Comments

ghost picture ghost  路  4Comments