rline: native regex engine (thompson nfa, no backtracking) + RLINE regex bans (registration/enforce/stats R/matchonnickchange)
This commit is contained in:
parent
b76fbfdb79
commit
56d3774647
8 changed files with 786 additions and 1 deletions
|
|
@ -243,7 +243,7 @@ impl Command for Stats {
|
|||
s.numeric(uid, RPL_STATSOLINE, &format!("O * * {n} :oper"));
|
||||
}
|
||||
}
|
||||
'k' | 'g' | 'z' | 'e' | 'q' | 's' | 'S' => {
|
||||
'k' | 'g' | 'z' | 'e' | 'q' | 's' | 'S' | 'R' => {
|
||||
let kind = match letter {
|
||||
'k' => XKind::Kline,
|
||||
'g' => XKind::Gline,
|
||||
|
|
@ -251,6 +251,7 @@ impl Command for Stats {
|
|||
'e' => XKind::Eline,
|
||||
'q' => XKind::Qline,
|
||||
'S' => XKind::Svshold,
|
||||
'R' => XKind::Rline,
|
||||
_ => XKind::Shun,
|
||||
};
|
||||
let rows: Vec<String> = s
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ pub fn commands() -> Vec<Box<dyn Command>> {
|
|||
Box::new(Shun),
|
||||
Box::new(Qline),
|
||||
Box::new(Cban),
|
||||
Box::new(Rline),
|
||||
Box::new(Connect),
|
||||
Box::new(ChgHost),
|
||||
Box::new(ChgIdent),
|
||||
|
|
@ -743,6 +744,56 @@ impl Command for Cban {
|
|||
}
|
||||
}
|
||||
|
||||
/// RLINE — ban users whose `nick!user@host realname` matches a regular expression.
|
||||
/// `RLINE <regex> [<duration>] :<reason>` adds; `RLINE <regex>` removes.
|
||||
struct Rline;
|
||||
impl Command for Rline {
|
||||
fn name(&self) -> &'static str {
|
||||
"RLINE"
|
||||
}
|
||||
fn min_params(&self) -> usize {
|
||||
1
|
||||
}
|
||||
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||
if !require_oper(s, uid) {
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
let pattern = params[0].clone();
|
||||
let nick = s
|
||||
.users
|
||||
.get(&uid)
|
||||
.map(|u| u.nick.clone())
|
||||
.unwrap_or_default();
|
||||
if params.len() < 2 {
|
||||
let word = if s.remove_xline(XKind::Rline, &pattern) {
|
||||
"removed"
|
||||
} else {
|
||||
"not found"
|
||||
};
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :R-line {word}: {pattern}", s.name),
|
||||
);
|
||||
return CmdResult::Ok;
|
||||
}
|
||||
if let Err(e) = crate::regex::Regex::new(&pattern) {
|
||||
s.send(
|
||||
uid,
|
||||
format!(":{} NOTICE {nick} :Invalid RLINE regex: {e}", s.name),
|
||||
);
|
||||
return CmdResult::Fail;
|
||||
}
|
||||
let dur = parse_duration(¶ms[1]).unwrap_or(0);
|
||||
let reason = params
|
||||
.get(2)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| "No reason given".to_string());
|
||||
s.add_xline(XKind::Rline, &pattern, dur, &nick, &reason);
|
||||
s.enforce_rline(&pattern, &reason);
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
||||
/// NICKLOCK — force a user's nick and lock it so they can't change it.
|
||||
/// `NICKLOCK <nick> <newnick>`; opers/services still can.
|
||||
struct NickLock;
|
||||
|
|
|
|||
|
|
@ -501,6 +501,24 @@ impl Command for Nick {
|
|||
}
|
||||
}
|
||||
s.set_nick(uid, newnick);
|
||||
// RLINE matchonnickchange: re-test the R-lines against the new identity
|
||||
if s.conf_bool("rline_matchonnickchange", false) {
|
||||
let info = s.users.get(&uid).map(|u| {
|
||||
(
|
||||
u.nick.clone(),
|
||||
u.ident.clone(),
|
||||
u.host.clone(),
|
||||
u.addr.ip().to_string(),
|
||||
u.realname.clone(),
|
||||
)
|
||||
});
|
||||
if let Some((nk, id, ho, ip, rn)) = info {
|
||||
if let Some(reason) = s.matched_rline(&nk, &id, &ho, &ip, &rn) {
|
||||
s.send(uid, format!("ERROR :Closing link: ({reason})"));
|
||||
s.remove_user(uid, &reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
CmdResult::Ok
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue