xline: tell a banned user when the ban expires, not just why
This commit is contained in:
parent
745ddd540e
commit
7cb9256ff5
2 changed files with 34 additions and 4 deletions
|
|
@ -1655,6 +1655,21 @@ mod tests {
|
||||||
assert!(joined.contains("XLINE: Z-line on 192.0.2.5 expired"), "expire: {joined}");
|
assert!(joined.contains("XLINE: Z-line on 192.0.2.5 expired"), "expire: {joined}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn banned_user_message_shows_expiry() {
|
||||||
|
let mut s = srv();
|
||||||
|
s.conf_path = std::env::temp_dir().join("echo-ban-expiry-test").display().to_string();
|
||||||
|
// permanent K-line: reason only, no expiry tail
|
||||||
|
s.add_xline(crate::xline::XKind::Kline, "*@perm.example", 0, "op", "spam");
|
||||||
|
let perm = s.matched_xline("bob", "perm.example", "1.2.3.4").unwrap();
|
||||||
|
assert_eq!(perm, "K-lined: spam", "permanent ban shows no expiry: {perm}");
|
||||||
|
// timed Z-line: reason + when it lifts
|
||||||
|
s.add_xline(crate::xline::XKind::Zline, "5.6.7.8", 604800, "op", "botnet");
|
||||||
|
let timed = s.matched_xline("bob", "any.host", "5.6.7.8").unwrap();
|
||||||
|
assert!(timed.starts_with("Z-lined: botnet (expires in "), "timed ban shows expiry: {timed}");
|
||||||
|
assert!(timed.contains(" on ") && timed.ends_with(')'), "with an absolute date: {timed}");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dnsbl_hit_emits_expected_snotices() {
|
fn dnsbl_hit_emits_expected_snotices() {
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
|
||||||
23
src/xline.rs
23
src/xline.rs
|
|
@ -100,6 +100,21 @@ pub fn human_duration(mut secs: u64) -> String {
|
||||||
parts.join(" ")
|
parts.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The " (expires in …)" tail appended to the reason a banned user is shown, or
|
||||||
|
/// empty for a permanent ban (`expires` is the absolute unix expiry, 0 = permanent).
|
||||||
|
/// Lets someone who hits a K/G/Z/R-line see when it lifts, not just why.
|
||||||
|
fn ban_expiry_suffix(expires: u64, now: u64) -> String {
|
||||||
|
if expires > now {
|
||||||
|
format!(
|
||||||
|
" (expires in {} on {})",
|
||||||
|
human_duration(expires - now),
|
||||||
|
crate::server::long_date(expires)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
/// Whether an active x-line of `kind` matches this `user@host` / `ip`.
|
/// Whether an active x-line of `kind` matches this `user@host` / `ip`.
|
||||||
fn xmatch(&self, kind: XKind, uh: &str, ip: &str) -> bool {
|
fn xmatch(&self, kind: XKind, uh: &str, ip: &str) -> bool {
|
||||||
|
|
@ -192,7 +207,7 @@ impl Server {
|
||||||
for kind in [XKind::Kline, XKind::Gline, XKind::Zline] {
|
for kind in [XKind::Kline, XKind::Gline, XKind::Zline] {
|
||||||
if self.xmatch(kind, &uh, ip) {
|
if self.xmatch(kind, &uh, ip) {
|
||||||
let n = now();
|
let n = now();
|
||||||
let reason = self
|
let (reason, expires) = self
|
||||||
.xlines
|
.xlines
|
||||||
.iter()
|
.iter()
|
||||||
.find(|x| {
|
.find(|x| {
|
||||||
|
|
@ -203,9 +218,9 @@ impl Server {
|
||||||
_ => glob_match(&x.mask, &uh),
|
_ => glob_match(&x.mask, &uh),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|x| x.reason.clone())
|
.map(|x| (x.reason.clone(), x.expires))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
return Some(format!("{}-lined: {reason}", kind.tag()));
|
return Some(format!("{}-lined: {reason}{}", kind.tag(), ban_expiry_suffix(expires, n)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
@ -234,7 +249,7 @@ impl Server {
|
||||||
.map(|re| re.is_match(&hostform) || re.is_match(&ipform))
|
.map(|re| re.is_match(&hostform) || re.is_match(&ipform))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
.map(|x| format!("R-lined: {}", x.reason))
|
.map(|x| format!("R-lined: {}{}", x.reason, ban_expiry_suffix(x.expires, n)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kill every registered local user matched by R-line `pattern` (called after an
|
/// Kill every registered local user matched by R-line `pattern` (called after an
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue