diff --git a/echoircd.conf.example b/echoircd.conf.example index 53928b5..e4422ca 100644 --- a/echoircd.conf.example +++ b/echoircd.conf.example @@ -120,6 +120,11 @@ amu_target = both # --- chanlog (m_chanlog): mirror the oper server-notice stream into a channel so # staff can watch it in a normal window. Set the channel (create/keep it opped): # chanlog = #snotices +# --- globops (m_globops): no config — adds the oper command /GLOBOPS , +# broadcasting to all opers (like the server-notice stream). +# --- autodrop (m_autodrop): silently drop a not-yet-registered client that sends +# any of these commands (HTTP scanners blurt GET/POST before NICK/USER): +# autodrop_commands = GET POST HEAD CONNECT PUT DELETE OPTIONS TRACE PATCH # --- hidelist (m_hidelist): list modes (+b/+e/+I/…) are viewable by members by # default; this restricts a given list to a minimum rank. Repeatable, # `hidelist = ` (rank: owner|admin|op|halfop|voice). Opers see diff --git a/src/modules/autodrop.rs b/src/modules/autodrop.rs new file mode 100644 index 0000000..25bfa9d --- /dev/null +++ b/src/modules/autodrop.rs @@ -0,0 +1,45 @@ +//! autodrop — silently drop a not-yet-registered client that sends one of the +//! configured commands. HTTP scanners and other junk open a connection and blurt +//! `GET` / `POST` / `CONNECT` before ever sending NICK/USER; a real IRC client +//! never does. Config, space-separated (repeatable): +//! +//! ```text +//! autodrop_commands = GET POST HEAD CONNECT PUT DELETE OPTIONS TRACE PATCH +//! ``` +//! +//! Reference: InspIRCd's `m_autodrop`. Original native Rust. + +use crate::module::{ModResult, Module}; +use crate::server::Server; +use crate::Uid; + +pub struct AutoDrop; + +impl Module for AutoDrop { + fn name(&self) -> &'static str { + "autodrop" + } + + fn on_pre_command( + &mut self, + s: &mut Server, + uid: Uid, + cmd: &str, + _params: &[String], + ) -> ModResult { + // only before registration — a registered client's commands are its own + if s.users.get(&uid).map(|u| u.registered).unwrap_or(true) { + return ModResult::Passthru; + } + let hit = s + .conf_all("autodrop_commands") + .iter() + .any(|line| line.split_whitespace().any(|w| w.eq_ignore_ascii_case(cmd))); + if hit { + s.send(uid, "ERROR :Closing link (dropped)".to_string()); + s.remove_user(uid, "Autodropped"); + return ModResult::Deny; + } + ModResult::Passthru + } +} diff --git a/src/modules/globops.rs b/src/modules/globops.rs new file mode 100644 index 0000000..f03193c --- /dev/null +++ b/src/modules/globops.rs @@ -0,0 +1,35 @@ +//! globops — `GLOBOPS ` lets an oper send a message to all opers (the +//! server-notice stream, echoIRCd's equivalent of InspIRCd's `+g` snomask). +//! Reference: InspIRCd's `m_globops`. Original native Rust. + +use crate::command::{CmdResult, Command}; +use crate::numeric::ERR_NOPRIVILEGES; +use crate::server::Server; +use crate::Uid; + +pub fn commands() -> Vec> { + vec![Box::new(GlobopsCmd)] +} + +struct GlobopsCmd; +impl Command for GlobopsCmd { + fn name(&self) -> &'static str { + "GLOBOPS" + } + fn min_params(&self) -> usize { + 1 + } + fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult { + if !s.is_oper(uid) { + s.numeric( + uid, + ERR_NOPRIVILEGES, + ":Permission Denied- You're not an IRC operator", + ); + return CmdResult::Fail; + } + let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default(); + s.snotice(&format!("GLOBOPS from {nick}: {}", params.join(" "))); + CmdResult::Ok + } +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index b94eed4..f79a913 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -6,6 +6,7 @@ pub mod account_registration; pub mod antimixedutf8; pub mod antirandom; +pub mod autodrop; pub mod autoop; pub mod banredirect; pub mod blockamsg; @@ -29,6 +30,7 @@ pub mod filehost; pub mod filter; pub mod flood; pub mod geoip; +pub mod globops; pub mod hashident; pub mod hidelist; pub mod hidewhois; @@ -93,6 +95,7 @@ pub fn default_modules() -> Vec> { Box::new(dccallow::DccAllow), Box::new(solvemsg::SolveMsg), Box::new(autoop::AutoOp), + Box::new(autodrop::AutoDrop), ] } @@ -127,5 +130,6 @@ pub fn module_commands() -> Vec> { .chain(customtitle::commands()) .chain(dccallow::commands()) .chain(geoip::commands()) + .chain(globops::commands()) .collect() }