connflood: bound the per-IP connection-history map (prune stale buckets past 65536 tracked IPs) — it only shrank on the tick GC, so a wide source-IP spread could grow it unbounded between ticks (memory DoS)
This commit is contained in:
parent
a218d65371
commit
83cdce17c5
1 changed files with 13 additions and 6 deletions
|
|
@ -32,17 +32,24 @@ pub fn over_limit(s: &mut Server, ip: IpAddr) -> bool {
|
|||
return false;
|
||||
};
|
||||
let n = now();
|
||||
let hist = s
|
||||
.ext
|
||||
.get_or_insert_with::<ConnHistory>(ConnHistory::default)
|
||||
.0
|
||||
.entry(ip)
|
||||
.or_default();
|
||||
let store = s.ext.get_or_insert_with::<ConnHistory>(ConnHistory::default);
|
||||
// Bound memory: a wide source-IP spread (e.g. an IPv6 /64) could otherwise grow
|
||||
// this map unbounded between tick GCs — once it's large, drop stale buckets now.
|
||||
if store.0.len() > MAX_TRACKED_IPS {
|
||||
store.0.retain(|_, times| {
|
||||
times.retain(|&t| n.saturating_sub(t) < secs);
|
||||
!times.is_empty()
|
||||
});
|
||||
}
|
||||
let hist = store.0.entry(ip).or_default();
|
||||
hist.retain(|&t| n.saturating_sub(t) < secs);
|
||||
hist.push(n);
|
||||
hist.len() as u32 > max
|
||||
}
|
||||
|
||||
/// Ceiling on distinct source IPs tracked between GC ticks (memory bound).
|
||||
const MAX_TRACKED_IPS: usize = 65_536;
|
||||
|
||||
/// Prunes stale per-IP bookkeeping on the tick.
|
||||
pub struct ConnFlood;
|
||||
impl Module for ConnFlood {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue