fix(friends): restore LAN realm address after restart (#158)

This commit is contained in:
Дмитрий committed 2026-10-27 08:34:02 +05:00
1 parent 4a99dd3a6a
commit bf2fffcffa
3 files changed
+73 -7

No files matched your search

@@ -0,0 +1,7 @@
---
area: manager
type: fixed
audience: admins
title: Internet sharing restores the LAN address after server restarts
---
Friends on the local network receive the server's LAN address and network mask while internet players keep using its public address.
+65 -6
View File
@@ -163,10 +163,52 @@ pub fn set_open(root: &Path, meta: &Path, open: bool) -> Result<bool> {
/// Make the realm list advertise `host` to remote clients (the launcher resets it to 127.0.0.1 at every start, so this
/// runs after each start).
pub fn apply_realm_address(root: &Path, host: &str) -> Result<()> {
fn realm_address_sql(
host: &str,
local: Option<(std::net::Ipv4Addr, std::net::Ipv4Addr)>,
where_realms: &str,
) -> Result<String> {
if !host_ok(host) {
return Err(Error::Invalid("That address is not valid.".into()));
}
let local = local
.map(|(address, mask)| format!(",localAddress='{address}',localSubnetMask='{mask}'"))
.unwrap_or_default();
Ok(format!(
"UPDATE acore_auth.realmlist SET address='{host}'{local} WHERE {where_realms};"
))
}
pub fn apply_realm_address(root: &Path, settings: &Settings) -> Result<()> {
let host = settings.host.as_deref().unwrap_or("127.0.0.1");
let local = match settings.mode {
Mode::Direct | Mode::Lan => {
let address = if settings.mode == Mode::Lan {
host.to_owned()
} else {
crate::net::resolve_lan_host(
settings.lan_address_override.as_deref(),
crate::net::lan_ip(),
)?
};
let address = crate::net::validate_lan_address(&address)?;
let mask = if_addrs::get_if_addrs()?
.into_iter()
.find_map(|interface| match interface.addr {
if_addrs::IfAddr::V4(v4) if v4.ip == address => Some(v4.netmask),
_ => None,
})
.ok_or_else(|| {
Error::Invalid("The selected local network address is not connected.".into())
})?;
Some((address, mask))
}
Mode::Local => Some((
std::net::Ipv4Addr::LOCALHOST,
std::net::Ipv4Addr::new(255, 0, 0, 0),
)),
Mode::Private => None,
};
let db = Db::from_repack(root, Account::Admin)?;
let realm = crate::realms::state(root)?.active.realm_id();
let where_realms = if crate::realms::state(root)?.simultaneous {
@@ -174,9 +216,7 @@ pub fn apply_realm_address(root: &Path, host: &str) -> Result<()> {
} else {
format!("id={realm}")
};
db.query(&format!(
"UPDATE acore_auth.realmlist SET address='{host}' WHERE {where_realms};"
))?;
db.query(&realm_address_sql(host, local, &where_realms)?)?;
Ok(())
}
@@ -194,9 +234,9 @@ pub fn ensure_bind(root: &Path, meta: &Path) -> Result<bool> {
/// After every server start: put the chosen address back into the realm list (the launcher resets it to 127.0.0.1).
pub fn reapply(root: &Path, meta: &Path) -> Result<()> {
let s = load(meta);
match (s.mode, s.host) {
match (s.mode, &s.host) {
(Mode::Local, _) | (_, None) => Ok(()),
(_, Some(host)) => apply_realm_address(root, &host),
(_, Some(_)) => apply_realm_address(root, &s),
}
}
@@ -390,6 +430,25 @@ CoA.AllowRemoteClients = 0
);
}
#[test]
fn realm_addresses_restore_lan_without_replacing_public_host() {
let sql = realm_address_sql(
"203.0.113.9",
Some((
"192.168.50.7".parse().unwrap(),
"255.255.254.0".parse().unwrap(),
)),
"id IN (1,2)",
)
.unwrap();
assert_eq!(sql, "UPDATE acore_auth.realmlist SET address='203.0.113.9',localAddress='192.168.50.7',localSubnetMask='255.255.254.0' WHERE id IN (1,2);");
assert_eq!(
realm_address_sql("100.64.1.2", None, "id=1").unwrap(),
"UPDATE acore_auth.realmlist SET address='100.64.1.2' WHERE id=1;"
);
assert!(realm_address_sql("bad'host", None, "id=1").is_err());
}
#[test]
fn old_settings_load_without_migrating_effective_host_to_override() {
let s: Settings = serde_json::from_str(r#"{"mode":"lan","host":"192.168.1.50"}"#).unwrap();
+1 -1
View File
@@ -2571,7 +2571,7 @@ async fn friends_enable(
friends::save(&meta, &settings)?;
let running = coa_core::process::observe(&root, &ports).world.state == coa_core::process::ServiceState::Running;
if running {
friends::apply_realm_address(&root, &host)?;
friends::apply_realm_address(&root, &settings)?;
}
Ok(FriendsResult { host, restart_required: changed && running, note })
})