Skip to content

Resolve shard IP hostnames before sending them to the client - #324

Open
MettleSphee wants to merge 2 commits into
OpenFusionProject:masterfrom
MettleSphee:master
Open

Resolve shard IP hostnames before sending them to the client#324
MettleSphee wants to merge 2 commits into
OpenFusionProject:masterfrom
MettleSphee:master

Conversation

@MettleSphee

Copy link
Copy Markdown

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.

[INFO] OpenFusion v
[INFO] Protocol version: 1013
[INFO] Resolved shard IP "fusiontest.test" to 127.0.0.1
[INFO] Built with libsqlite 3.53.4
[INFO] Patching tdata/patch/1013/paths.json

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.

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.
@MettleSphee

MettleSphee commented Aug 5, 2026

Copy link
Copy Markdown
Author

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:
Client is always OpenFusionLauncher 2.2.4 (Latest Release, Windows), game version selected is beta-20100104;
Servers:

  • On Ubuntu 22.04, all protocol versions (104, 728, 1013) send the client towards the correct IP of the SHARD server, despite in two cases not working past the tutorial due to different game versions being selected by the client (unknown packet). Domain is registered via /etc/hosts file, pointing to LAN address;
  • On Docker (via ghcr.io), with the correctly specified game version, the entire process works flawlessly. Domain is registered via DNS, accessible via the internet. Protocol v104;
  • On Windows, v1013 works flawlessly when paired with beta-20111013, v104 works with its corresponding game version, same with v728, minus desynced character name wheel between client and server. Domain was registered via C:\Windows\System32\drivers\etc\hosts, pointing to 127.0.0.1;

@yungcomputerchair

yungcomputerchair commented Aug 5, 2026

Copy link
Copy Markdown
Member

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 127.0.0.1. That would cause the client to connect to localhost instead of the machine that's actually running the shard.

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:

  • Waiting to initialize the sandbox is clever, but goes against the principle of the sandbox itself. Every networked operation the process does is supposed to be locked down from start to finish. All the functionality we need is configured via the allowlist (and all of it was enabled because the server cannot function otherwise)
  • The overflow protection is largely redundant-- config cannot be controlled by an attacker, and it's unlikely that the server owner would put in a malformed IP address-- but it might be worth keeping to avoid smashing the stack if the server owner made a mistake after all.
  • I would advise opening a separate PR for the GCR workflow; I anticipate there will be some discussion on that and it'd be better for it to have its own scope.

@yungcomputerchair

Copy link
Copy Markdown
Member

(It's also worth nothing that this will not respect any of the host entries on the client's machine)

@MettleSphee

Copy link
Copy Markdown
Author

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.

@yungcomputerchair

Copy link
Copy Markdown
Member

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.

@yungcomputerchair

Copy link
Copy Markdown
Member

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?

@MettleSphee

MettleSphee commented Aug 6, 2026

Copy link
Copy Markdown
Author

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.
Now that I think about it, the shard/login servers are bundled in one singular executable, so why do we need to have a problem like this in the first place? Why doesn't the client use the same IP (or domain, given it's possible) for both game and login, to help ease the setup of a server?
If it would be such a huge DNS provider difference, why couldn't it just use the IP found by the client?

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants