Resolve shard IP hostnames before sending them to the client - #324
Resolve shard IP hostnames before sending them to the client#324MettleSphee wants to merge 2 commits into
Conversation
The FusionFall client only understands literal IPv4 addresses in the shard select packet, so a hostname configured as the shard IP (e.g. a dynamic-DNS address) is now resolved to IPv4 by the server before it is sent to the client. The address is resolved once at startup, before the sandbox engages (the login server thread is not allowed to open new sockets afterwards), and re-resolved on every character select on builds where runtime DNS lookups are possible (Windows, and Linux builds without the seccomp sandbox), so dynamic-DNS changes are picked up without a restart. Also guards against overflowing the 16-byte g_FE_ServerIP field and documents hostname support in config.ini.
|
Although I have only lazily tested before, I have now done the test on each of the build artifacts provided by the GitHub Actions workflows. The OpenFusion game client gets the correct IP from the server in the following scenarios:
|
|
Thanks for the PR. There's some stuff to think about here, though, as this is a little tricker than it seems. We actually implemented DNS resolution of the shard host before, but ultimately opted not to check it in for one good reason: resolving hostnames from the perspective of the server can yield different results than resolving from the perspective of the client, especially on a local network. This is something that can trip up server owners very easily. For example, if I'm running the server on a LAN and I put the server's host name in as the shard IP, it'll resolve to This case is extremely common as most of our users who want private servers run the server on a LAN or VPN network. Saying "oh, you can just put the computer name in" would be wrong in these cases, and makes the feature a footgun instead of actually helpful. Public server owners might be able to benefit, but they're already tech-savvy enough to know the concrete IP of their shard and will almost always opt to use that to avoid introducing potential issues caused by DNS outages or other flakiness ("it's always DNS"). Other notes:
|
|
(It's also worth nothing that this will not respect any of the host entries on the client's machine) |
|
The main idea of mine with this change was to help out the few server owners who want to cheap out on having domains and, instead, use something like a dynamic DNS or a public proxy, in the case of having either CG-NAT or random IPs from the ISP instead of a static one, mainly because it's such a pain to keep manually changing the shard's IP if/when the ISP decides to change the IP (power outage of the connection, restarting the router etc). As such, I admit that I haven't though of the differences in client vs server DNS resolutions nor actually using the computer name as a domain. It would probably be a better change if this was an option only for the more experienced users (i.e. add a "domain" field in the config file with the warnings you mentioned earlier). One other solution would've been to create a script that externally updates the shard's IP from the config file, and then reboots the server to apply the changes. It would also be an okay solution, but wasteful because, when the IP change would occur, the server hardware would require a restart on its own, in most cases. I do agree that the GCR workflow deserves its own PR and discussions, although it might not be too big of a change other than a longer deployment on each build (if that is an issue). I'm looking forward to discussing this further, if anyone's willing. |
|
We could maybe add a Boolean setting that enables DNS resolution of the shard host (disabled by default). Looping in @dongresource to see if he has an opinion here. |
|
Another question came up to me as I've been thinking about this: with the way this is modeled, doesn't the DynamicDNS case die out since you'd have to restart the server whenever the IP changes? And that's not something you can know easily besides the client failing to connect. Is there a way we can safely allow the DNS resolution through the sandbox instead of doing the one-time resolution at startup? |
|
I don't really think so (for the first question), the cases I do know of the IP resetting are usually outages, whether the power fails (and servers get rebooted anyway), the ISP has an outage (and in this case, most servers only have one component, so an IP redirection is a problem only for the DNS/domain resolver). Another case would be manually rebooting the router, but in that case the server owner would know to update the Dynamic DNS manually, and therefore of the current limitation with the shard server, given we assume how experienced server owners have to be in this scenario. As for the sandbox part, I genuinely don't know. The only thing coming to my mind would be the one earlier, to remove the need for the server to deal with DNS resolution, because I haven't thoroughly looked into how the server works... |
Because that's not how the original server was architected. Almost all MMO servers host the login server on a separate box than the shard server, and FusionFall was one of the games to adopt that architecture. Thus the client was engineered to retrieve the shard address from the login server. Your point about the IP not really changing unless there's an outage kind of works against you here: if the IP only changes in rare circumstances, there's even less reason to use DynamicDNS. I'm still waiting for @dongresource to formalize a response, but I'm personally just not convinced the positives outweigh the negatives here. We don't really have a good way to warn server owners of all the caveats (hindering the sandbox, needing to restart the server to re-resolve the address, and the client/server resolution discrepancy). Feel free to keep the PR open so we can keep discussing. (And of course, in the spirit of FOSS, feel free to use this feature from your fork and inform the community about it.) |
Unfortunately, in this current day and age where more and more political conflicts can (and will) cause power outages. While my case alone may not be enough to prove a point, I can atleast confess that it's a huge pain in the backside to keep manually updating the configs whenever the IP changes, and after some point, someone will have enough and decide to auto-update it somehow. Furthermore, if an outage occurs and therefore the IP changes (in my case, I am not always near the physical servers, and operate remotely), losing access to my one (or few) entry point(s) because of the IP change would basically mean the servers are completely down until I go all the way to their physical location and start them all over. Due to other servers only having one component, that is a non-problem for most components, but that doesn't apply in our case. There's growing popularity with self-hosting nowadays, and I am very sure there's a good amount of people having run into the problem of dynamic IPs and/or CG-NAT, for the sake of ISP clients' security or them running out of IPs to give out to clients. Sure, there may not be such many cases that also partake in this game, hence why that might not be favorable... Now that I think about it, that doesn't matter at all. If the domain's IP is a different one for clients with different DNS resolutions, the resolved IP is still the one from the server... In the fortunate case the login server's domain doesn't resolve correctly (for public domains only), the IP is still the correct one. If a client's ISP somehow breaks the standard and uses the same IP for a different computer than the one on the internet, that becomes a whole different problem that will require another solution anyway (and then a solution will be a VPN). The intention of this was to not use any other software than the server/client pair, given that the server owner has enough knowledge and configuration to even hold this as a service. Even in the case of the official OpenFusion servers, it would be a pain to keep updating the IP manually when the domain provider, ISP or cloud hosting have an issue. |
I don't anticipate this to be a common occurrence. Again, the only issue that arises from the difference in perspective between client and server is the first example I pointed out, where the server is running on the same local network and resolves its own hostname as localhost and breaks the client. I think that is an acceptable tradeoff if it's the only issue with the PR, but it's not; the fact that the server needs to restart to pick up a new IP is a bigger issue. A stale IP being handed out for the entire lifetime of the server is a straight-up bug. For a feature to make it into the official repo, it needs to be useful without exception. My opinion is that there are too many "gotchas" here right now for that to be true. That being said, if you can correctly configure the sandbox so the resolution works under it, we might have a way forward here. |
|
Also:
We actually have never had to update the IP address for the public servers; most web hosting providers (ours included) give you a static IP for free. If it were to change, it would violate the SLA. |
For a simplified description: Adds domain support in the config.ini file for the IP field (resolves domains on server launch, and sends the resolved IP to become the SHARD server's new IP), and adds a workflow build for GitHub's container registry (ghcr.io). Works with domains defined in hosts file and those from a DNS provider.
The FusionFall client only understands literal IPv4 addresses in the shard select packet, so a hostname configured as the shard IP (e.g. a dynamic-DNS address) is now resolved to IPv4 by the server before it is sent to the client.
The address is resolved once at startup, before the sandbox engages (the login server thread is not allowed to open new sockets afterwards), and re-resolved on every character select on builds where runtime DNS lookups are possible (Windows, and Linux builds without the seccomp sandbox), so dynamic-DNS changes are picked up without a restart.
Also guards against overflowing the 16-byte g_FE_ServerIP field and documents hostname support in config.ini.