diff --git a/master/config/main.toml b/master/config/main.toml index 899ce96..8d244b9 100644 --- a/master/config/main.toml +++ b/master/config/main.toml @@ -7,13 +7,15 @@ level = "info" [server] ip = "0.0.0.0" port = 27010 +# How many servers with the same ip can be registred +max-servers-per-ip = 14 [server.timeout] # Time in seconds while challenge is valid challenge = 10 # Time in seconds while server is valid server = 300 -# TIme in seconds before next admin request is allowed after wrong password +# Time in seconds before next admin request is allowed after wrong password admin = 10 [client] diff --git a/master/src/config.rs b/master/src/config.rs index 79821eb..3d74ba7 100644 --- a/master/src/config.rs +++ b/master/src/config.rs @@ -20,6 +20,8 @@ pub const DEFAULT_CHALLENGE_TIMEOUT: u32 = 10; pub const DEFAULT_SERVER_TIMEOUT: u32 = 300; pub const DEFAULT_ADMIN_TIMEOUT: u32 = 10; +pub const DEFAULT_MAX_SERVERS_PER_IP: u16 = 14; + pub const DEFAULT_HASH_LEN: usize = admin::HASH_LEN; macro_rules! impl_helpers { @@ -76,11 +78,14 @@ impl Default for LogConfig { #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] +#[serde(rename_all = "kebab-case")] pub struct ServerConfig { #[serde(default = "default_server_ip")] pub ip: IpAddr, #[serde(default = "default_u16::")] pub port: u16, + #[serde(default = "default_u16::")] + pub max_servers_per_ip: u16, #[serde(default)] pub timeout: TimeoutConfig, } @@ -90,6 +95,7 @@ impl Default for ServerConfig { Self { ip: default_server_ip(), port: DEFAULT_MASTER_SERVER_PORT, + max_servers_per_ip: DEFAULT_MAX_SERVERS_PER_IP, timeout: Default::default(), } } diff --git a/master/src/master_server.rs b/master/src/master_server.rs index 67a9c36..dc01791 100644 --- a/master/src/master_server.rs +++ b/master/src/master_server.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only // SPDX-FileCopyrightText: 2023 Denis Drakhnia +use std::collections::hash_map; use std::io; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket}; use std::ops::Deref; @@ -108,6 +109,7 @@ pub struct MasterServer { challenges_counter: Counter, servers: HashMap>, servers_counter: Counter, + max_servers_per_ip: u16, rng: Rng, start_time: Instant, @@ -180,6 +182,7 @@ impl MasterServer { challenges_counter: Counter::new(CHALLENGE_CLEANUP_MAX), servers: Default::default(), servers_counter: Counter::new(SERVER_CLEANUP_MAX), + max_servers_per_ip: cfg.server.max_servers_per_ip, rng: Rng::new(), timeout: cfg.server.timeout, clver: cfg.client.version, @@ -492,11 +495,25 @@ impl MasterServer { } } + fn count_servers(&self, addr: &Ipv4Addr) -> u16 { + self.servers.keys().filter(|i| i.ip() == addr).count() as u16 + } + fn add_server(&mut self, addr: SocketAddrV4, server: ServerInfo) { - let entry = Entry::new(self.now(), server); - match self.servers.insert(addr, entry) { - Some(_) => trace!("{}: Updated GameServer", addr), - None => trace!("{}: New GameServer", addr), + let now = self.now(); + match self.servers.entry(addr) { + hash_map::Entry::Occupied(mut e) => { + trace!("{}: Updated GameServer", addr); + e.insert(Entry::new(now, server)); + } + hash_map::Entry::Vacant(_) => { + if self.count_servers(addr.ip()) >= self.max_servers_per_ip { + trace!("{}: max servers per ip", addr); + return; + } + trace!("{}: New GameServer", addr); + self.servers.insert(addr, Entry::new(now, server)); + } } }