modules: move all per-module state/config out of server.rs/config.rs into own files
This commit is contained in:
parent
0d4c9297b5
commit
131471e245
18 changed files with 525 additions and 425 deletions
60
src/modules/connflood.rs
Normal file
60
src/modules/connflood.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//! connflood — InspIRCd `m_connflood`. Refuse connections from an IP opening too
|
||||
//! many too fast. Config: `connflood = <max> <secs>`. Per-IP recent-connect times
|
||||
//! live in `Server.ext`, pruned on the tick — nothing lives on `Server`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use crate::module::Module;
|
||||
use crate::server::{now, Server};
|
||||
|
||||
/// per-IP recent connection timestamps. Stored in `Server.ext`.
|
||||
#[derive(Default)]
|
||||
pub struct ConnHistory(pub HashMap<IpAddr, Vec<u64>>);
|
||||
|
||||
/// `(max, secs)` from `connflood = <max> <secs>`, or `None` when disabled.
|
||||
fn cfg(s: &Server) -> Option<(u32, u64)> {
|
||||
let v = s.conf("connflood")?;
|
||||
let mut it = v.split_whitespace();
|
||||
let mx: u32 = it.next()?.parse().ok()?;
|
||||
let sc: u64 = it.next()?.parse().ok()?;
|
||||
(mx > 0 && sc > 0).then_some((mx, sc))
|
||||
}
|
||||
|
||||
/// Record a connection from `ip`; returns true when it exceeds the limit (the
|
||||
/// caller should refuse it). No-op → false when connflood is unconfigured.
|
||||
pub fn over_limit(s: &mut Server, ip: IpAddr) -> bool {
|
||||
let Some((max, secs)) = cfg(s) else {
|
||||
return false;
|
||||
};
|
||||
let n = now();
|
||||
let hist = s
|
||||
.ext
|
||||
.get_or_insert_with::<ConnHistory>(ConnHistory::default)
|
||||
.0
|
||||
.entry(ip)
|
||||
.or_default();
|
||||
hist.retain(|&t| n.saturating_sub(t) < secs);
|
||||
hist.push(n);
|
||||
hist.len() as u32 > max
|
||||
}
|
||||
|
||||
/// Prunes stale per-IP bookkeeping on the tick.
|
||||
pub struct ConnFlood;
|
||||
impl Module for ConnFlood {
|
||||
fn name(&self) -> &'static str {
|
||||
"connflood"
|
||||
}
|
||||
fn on_tick(&mut self, s: &mut Server) {
|
||||
let Some((_, secs)) = cfg(s) else {
|
||||
return;
|
||||
};
|
||||
let n = now();
|
||||
if let Some(h) = s.ext.get_mut::<ConnHistory>() {
|
||||
h.0.retain(|_, times| {
|
||||
times.retain(|&t| n.saturating_sub(t) < secs);
|
||||
!times.is_empty()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue