mode: cap mode changes per MODE command (modes=, default 20) and advertise it as the MODES= ISUPPORT token — an uncapped modestring like MODE #c +bbbb… dispatched a handler per letter, each fanning out to the whole channel and every S2S link (amplification DoS); matches InspIRCd's MODES limit
This commit is contained in:
parent
11cec9fc36
commit
c72b966e0a
2 changed files with 11 additions and 1 deletions
|
|
@ -119,11 +119,20 @@ pub fn apply_mode(s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||||
let mut echoed: Vec<String> = Vec::new();
|
let mut echoed: Vec<String> = Vec::new();
|
||||||
// (sign, letter, displayed-param) per applied change — for hidemode filtering
|
// (sign, letter, displayed-param) per applied change — for hidemode filtering
|
||||||
let mut changes: Vec<(char, char, Option<String>)> = Vec::new();
|
let mut changes: Vec<(char, char, Option<String>)> = Vec::new();
|
||||||
|
// Cap mode changes per command (advertised as MODES=, default 20 like InspIRCd):
|
||||||
|
// otherwise `MODE #c +bbbb…` in one line dispatches hundreds of handlers, each
|
||||||
|
// fanning out to the whole channel and every link — a cheap amplification flood.
|
||||||
|
let max_modes = s.conf_num("modes", 20usize).max(1);
|
||||||
|
let mut processed = 0usize;
|
||||||
for c in modestring.chars() {
|
for c in modestring.chars() {
|
||||||
if c == '+' || c == '-' {
|
if c == '+' || c == '-' {
|
||||||
sign = c;
|
sign = c;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if processed >= max_modes {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
processed += 1;
|
||||||
let adding = sign == '+';
|
let adding = sign == '+';
|
||||||
let Some(handler) = chan_mode(c) else {
|
let Some(handler) = chan_mode(c) else {
|
||||||
s.numeric(
|
s.numeric(
|
||||||
|
|
|
||||||
|
|
@ -771,12 +771,13 @@ impl Server {
|
||||||
let chathist = crate::modules::chathistory::limit(self);
|
let chathist = crate::modules::chathistory::limit(self);
|
||||||
let maxnick = self.conf_num("maxnick", 30usize);
|
let maxnick = self.conf_num("maxnick", 30usize);
|
||||||
let maxchan = self.conf_num("maxchannel", 50usize);
|
let maxchan = self.conf_num("maxchannel", 50usize);
|
||||||
|
let maxmodes = self.conf_num("modes", 20usize).max(1);
|
||||||
// operprefix/ojoin add the server oper prefix `y` above owner; sigils are
|
// operprefix/ojoin add the server oper prefix `y` above owner; sigils are
|
||||||
// config-overridable (see modules::customprefix)
|
// config-overridable (see modules::customprefix)
|
||||||
let include_oper = self.conf_bool("operprefix", false) || self.conf_bool("ojoin", false);
|
let include_oper = self.conf_bool("operprefix", false) || self.conf_bool("ojoin", false);
|
||||||
let prefix = crate::modules::customprefix::isupport(include_oper);
|
let prefix = crate::modules::customprefix::isupport(include_oper);
|
||||||
let mut tokens: Vec<String> = format!(
|
let mut tokens: Vec<String> = format!(
|
||||||
"CHANTYPES=# PREFIX={prefix} CHANMODES=beIgXw,k,lfjFLHBJdK,ACDGMNOPQRSTUcimnprstuz EXTBAN=,aGbcgjmnrsy ACCOUNTEXTBAN=a BOT=B WATCH={maxwatch} MONITOR={maxmon} SILENCE={maxsil} CALLERID=g WHOX CHATHISTORY={chathist} MSGREFTYPES=timestamp,msgid UTF8ONLY CASEMAPPING=ascii NICKLEN={maxnick} CHANNELLEN={maxchan} NETWORK={}",
|
"CHANTYPES=# PREFIX={prefix} CHANMODES=beIgXw,k,lfjFLHBJdK,ACDGMNOPQRSTUcimnprstuz EXTBAN=,aGbcgjmnrsy ACCOUNTEXTBAN=a BOT=B WATCH={maxwatch} MONITOR={maxmon} SILENCE={maxsil} CALLERID=g WHOX CHATHISTORY={chathist} MSGREFTYPES=timestamp,msgid UTF8ONLY CASEMAPPING=ascii NICKLEN={maxnick} CHANNELLEN={maxchan} MODES={maxmodes} NETWORK={}",
|
||||||
self.network
|
self.network
|
||||||
)
|
)
|
||||||
.split(' ')
|
.split(' ')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue