mirror of
https://github.com/timvisee/lazymc.git
synced 2025-05-19 12:50:23 -07:00
Use more efficient structure to manage banned IPs
This commit is contained in:
parent
168cbceb4c
commit
e816d4ff6c
@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
@ -8,6 +9,23 @@ use serde::Deserialize;
|
|||||||
/// File name.
|
/// File name.
|
||||||
pub const FILE: &str = "banned-ips.json";
|
pub const FILE: &str = "banned-ips.json";
|
||||||
|
|
||||||
|
/// List of banned IPs.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct BannedIps {
|
||||||
|
/// List of banned IPs.
|
||||||
|
ips: HashMap<IpAddr, BannedIp>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BannedIps {
|
||||||
|
/// Check whether the given IP is banned.
|
||||||
|
///
|
||||||
|
/// This uses the latest known `banned-ips.json` contents if known.
|
||||||
|
/// If this feature is disabled, this will always return false.
|
||||||
|
pub fn is_banned(&self, ip: &IpAddr) -> bool {
|
||||||
|
self.ips.get(ip).map(|ip| ip.is_banned()).unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A banned IP entry.
|
/// A banned IP entry.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct BannedIp {
|
pub struct BannedIp {
|
||||||
@ -27,11 +45,22 @@ pub struct BannedIp {
|
|||||||
pub reason: String,
|
pub reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BannedIp {
|
||||||
|
/// Check if this entry is currently banned.
|
||||||
|
pub fn is_banned(&self) -> bool {
|
||||||
|
// TODO: check expiry date here!
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Load banned IPs from file.
|
/// Load banned IPs from file.
|
||||||
pub fn load(path: &Path) -> Result<Vec<BannedIp>, Box<dyn Error>> {
|
pub fn load(path: &Path) -> Result<BannedIps, Box<dyn Error>> {
|
||||||
// Load file contents
|
// Load file contents
|
||||||
let contents = fs::read_to_string(path)?;
|
let contents = fs::read_to_string(path)?;
|
||||||
|
|
||||||
// Parse contents
|
// Parse contents, transform into map
|
||||||
Ok(serde_json::from_str(&contents)?)
|
let ips: Vec<BannedIp> = serde_json::from_str(&contents)?;
|
||||||
|
let ips = ips.into_iter().map(|ip| (ip.ip, ip)).collect();
|
||||||
|
|
||||||
|
Ok(BannedIps { ips })
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use tokio::sync::{Mutex, RwLock, RwLockReadGuard};
|
|||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::mc::ban::BannedIp;
|
use crate::mc::ban::BannedIps;
|
||||||
use crate::os;
|
use crate::os;
|
||||||
|
|
||||||
/// Server cooldown after the process quit.
|
/// Server cooldown after the process quit.
|
||||||
@ -66,7 +66,7 @@ pub struct Server {
|
|||||||
kill_at: RwLock<Option<Instant>>,
|
kill_at: RwLock<Option<Instant>>,
|
||||||
|
|
||||||
/// List of banned IPs.
|
/// List of banned IPs.
|
||||||
banned_ips: RwLock<Vec<BannedIp>>,
|
banned_ips: RwLock<BannedIps>,
|
||||||
|
|
||||||
/// Lock for exclusive RCON operations.
|
/// Lock for exclusive RCON operations.
|
||||||
#[cfg(feature = "rcon")]
|
#[cfg(feature = "rcon")]
|
||||||
@ -317,7 +317,7 @@ impl Server {
|
|||||||
/// This uses the latest known `banned-ips.json` contents if known.
|
/// This uses the latest known `banned-ips.json` contents if known.
|
||||||
/// If this feature is disabled, this will always return false.
|
/// If this feature is disabled, this will always return false.
|
||||||
pub async fn is_banned_ip(&self, ip: &IpAddr) -> bool {
|
pub async fn is_banned_ip(&self, ip: &IpAddr) -> bool {
|
||||||
self.banned_ips.read().await.iter().any(|i| &i.ip == ip)
|
self.banned_ips.read().await.is_banned(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the given IP is banned.
|
/// Check whether the given IP is banned.
|
||||||
@ -329,7 +329,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the list of banned IPs.
|
/// Update the list of banned IPs.
|
||||||
pub async fn set_banned_ips(&self, ips: Vec<BannedIp>) {
|
pub async fn set_banned_ips(&self, ips: BannedIps) {
|
||||||
*self.banned_ips.write().await = ips;
|
*self.banned_ips.write().await = ips;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use futures::FutureExt;
|
|||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::mc::ban::{self, BannedIp};
|
use crate::mc::ban::{self, BannedIps};
|
||||||
use crate::proto::client::Client;
|
use crate::proto::client::Client;
|
||||||
use crate::proxy;
|
use crate::proxy;
|
||||||
use crate::server::{self, Server};
|
use crate::server::{self, Server};
|
||||||
@ -160,10 +160,10 @@ pub fn route_proxy_address_queue(inbound: TcpStream, addr: SocketAddr, queue: By
|
|||||||
/// Load banned IPs if IP banning is enabled.
|
/// Load banned IPs if IP banning is enabled.
|
||||||
///
|
///
|
||||||
/// If disabled or on error, an empty list is returned.
|
/// If disabled or on error, an empty list is returned.
|
||||||
fn load_banned_ips(config: &Config) -> Vec<BannedIp> {
|
fn load_banned_ips(config: &Config) -> BannedIps {
|
||||||
// Blocking banned IPs must be enabled
|
// Blocking banned IPs must be enabled
|
||||||
if !config.server.block_banned_ips {
|
if !config.server.block_banned_ips {
|
||||||
return vec![];
|
return BannedIps::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure server directory is set, it must exist
|
// Ensure server directory is set, it must exist
|
||||||
@ -171,7 +171,7 @@ fn load_banned_ips(config: &Config) -> Vec<BannedIp> {
|
|||||||
Some(dir) => dir,
|
Some(dir) => dir,
|
||||||
None => {
|
None => {
|
||||||
warn!(target: "lazymc", "Not blocking banned IPs, server directory not configured, unable to find {} file", ban::FILE);
|
warn!(target: "lazymc", "Not blocking banned IPs, server directory not configured, unable to find {} file", ban::FILE);
|
||||||
return vec![];
|
return BannedIps::default();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ fn load_banned_ips(config: &Config) -> Vec<BannedIp> {
|
|||||||
let path = dir.join(crate::mc::ban::FILE);
|
let path = dir.join(crate::mc::ban::FILE);
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
warn!(target: "lazymc", "Not blocking banned IPs, {} file does not exist", ban::FILE);
|
warn!(target: "lazymc", "Not blocking banned IPs, {} file does not exist", ban::FILE);
|
||||||
return vec![];
|
return BannedIps::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load banned IPs
|
// Load banned IPs
|
||||||
@ -188,7 +188,7 @@ fn load_banned_ips(config: &Config) -> Vec<BannedIp> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
// TODO: quit here, require user to disable feature as security feature?
|
// TODO: quit here, require user to disable feature as security feature?
|
||||||
error!(target: "lazymc", "Failed to load banned IPs from {}: {}", ban::FILE, err);
|
error!(target: "lazymc", "Failed to load banned IPs from {}: {}", ban::FILE, err);
|
||||||
return vec![];
|
return BannedIps::default();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user