From e63e926ccf864ac3f275cd487da44968915ed2f7 Mon Sep 17 00:00:00 2001 From: Pierre Dubouilh Date: Fri, 28 Aug 2026 00:21:05 +0200 Subject: [PATCH] drop sshd support --- Makefile | 9 +---- README.md | 30 +++++++--------- src/main.rs | 18 ++-------- src/sshd.rs | 96 ---------------------------------------------------- src/utils.rs | 10 ++---- 5 files changed, 19 insertions(+), 144 deletions(-) delete mode 100644 src/sshd.rs diff --git a/Makefile b/Makefile index 2828c23..1686556 100644 --- a/Makefile +++ b/Makefile @@ -8,12 +8,11 @@ build:: cargo fmt --all run:: - touch /tmp/sshdtest touch /tmp/clftest touch /tmp/jsontest touch /tmp/generictest cargo build - sudo target/debug/blockfast -v -s=/tmp/sshdtest -c=/tmp/clftest -j=/tmp/jsontest --generic-logpath=/tmp/generictest --generic-ip='from ([0-9a-fA-F:.]+) port' --generic-positive='Failed password' + sudo target/debug/blockfast -v -c=/tmp/clftest -j=/tmp/jsontest --generic-logpath=/tmp/generictest --generic-ip='from ([0-9a-fA-F:.]+) port' --generic-positive='Failed password' ci:: test cargo fmt --all -- --check @@ -44,12 +43,6 @@ test:: release:: cargo build --target x86_64-unknown-linux-musl --release -hit-sshd:: - echo "Sep 26 06:25:32 livecompute sshd[23254]: Invalid user neal from 9.124.36.195" >> /tmp/sshdtest - -ok-sshd:: - echo "Sep 26 06:25:19 livecompute sshd[23246]: successful login 8.124.36.195 port 41883 ssh2" >> /tmp/sshdtest - hit-generic:: echo "Sep 26 06:25:19 livecompute sshd[23246]: Failed password for root from 179.124.36.195 port 41883 ssh2" >> /tmp/generictest diff --git a/README.md b/README.md index 0569c03..8e853ce 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ Block internets scanners fast 🍶 Features: - - SSH log parser - Common Log Format parser (apache logs, etc...) - JSON log parser (caddy logs) - Generic log parser @@ -14,16 +13,15 @@ Features: ## example ```txt -$ ./blockfast -s=/var/log/auth.log -j=/caddy/logs -1737927469 - starting with sshd parsing at "/tmp/sshdtest" +$ ./blockfast -j=/caddy/logs 1737927469 - starting with json parsing at "/tmp/jsontest" 1737927469 - jail setup, allowance 5, time 21600s -1737927477 - sshd logged offence for 9.124.36.195 -1737927478 - sshd logged offence for 9.124.36.195 -1737927479 - sshd logged offence for 9.124.36.195 -1737927479 - sshd logged offence for 9.124.36.195 -1737927480 - sshd logged offence for 9.124.36.195 -1737927480 - sshd jailtime for 9.124.36.195 +1737927477 - json logged offence for 9.124.36.195 +1737927478 - json logged offence for 9.124.36.195 +1737927479 - json logged offence for 9.124.36.195 +1737927479 - json logged offence for 9.124.36.195 +1737927480 - json logged offence for 9.124.36.195 +1737927480 - json jailtime for 9.124.36.195 ``` ## build @@ -36,11 +34,11 @@ Blockfast - block internets scanners fast 🍶 Author: pierre dubouilh Blockfast reads logs from various sources and blocks the offending IPs using iptables and ipset. -It supports logs from sshd, Common-Log-Format (Apache, etc..), JSON (Caddy) and a generic logs parser. +It supports logs in Common-Log-Format (Apache, etc..), JSON (Caddy) and a generic logs parser. Example: - # block invalid sshd attempts & invalid http statuses from caddy - ./blockfast -s=/var/log/auth.log -j=/caddy/logs + # block invalid http statuses from caddy + ./blockfast -j=/caddy/logs # generic log parser example with a log text to flag, and a regex to parse the offending IP. ./blockfast --generic-logpath=/tmp/generictest --generic-positive='Failed password' --generic-ip='from ([0-9a-fA-F:.]+) port' @@ -54,14 +52,12 @@ Options: how many offences allowed (max 255) [default: 5] -v, --verbose log all offences - -s, --sshd-logpath - path of sshd logfile -c, --clf-logpath - path of Common-Log-Format logfile (Apache, etc..) + path of Common-Log-Format logfile (Apache, etc..), can be repeated -j, --json-logpath - path of JSON logfile (works with Caddy) + path of JSON logfile (works with Caddy), can be repeated --generic-logpath - generic parser log file path + generic parser log file path, can be repeated --generic-ip generic parser ip regex --generic-positive diff --git a/src/main.rs b/src/main.rs index e70ca58..a2c5061 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use linemux::{Line, MuxedLines}; mod clf; mod generic; mod json; -mod sshd; mod utils; mod jail; @@ -33,13 +32,6 @@ async fn run() -> Result<()> { log!("starting with generic parsing at {:?}", &p); } - // sshd - let sshd_logpaths = &args.sshd_logpath; - for p in sshd_logpaths { - ml.add_file(&p).await?; - log!("starting with sshd parsing at {:?}", &p); - } - // common log format let clf_logpaths = &args.clf_logpath; for p in clf_logpaths { @@ -54,11 +46,7 @@ async fn run() -> Result<()> { log!("starting with json parsing at {:?}", &p); } - if json_logpaths.is_empty() - && clf_logpaths.is_empty() - && sshd_logpaths.is_empty() - && generic_paths.is_empty() - { + if json_logpaths.is_empty() && clf_logpaths.is_empty() && generic_paths.is_empty() { bail!("no log files to parse, see --help"); } @@ -70,9 +58,7 @@ async fn run() -> Result<()> { let path_buf = Some(line.source().to_path_buf()); let path = path_buf.as_ref(); - let (target, ret) = if path.is_some_and(|p| sshd_logpaths.contains(p)) { - ("sshd", sshd::parse(payload)?) - } else if path.is_some_and(|p| clf_logpaths.contains(p)) { + let (target, ret) = if path.is_some_and(|p| clf_logpaths.contains(p)) { ("clf", clf::parse(payload, invalid_statuses_ref)?) } else if path.is_some_and(|p| json_logpaths.contains(p)) { ("json", json::parse(payload, invalid_statuses_ref)?) diff --git a/src/sshd.rs b/src/sshd.rs deleted file mode 100644 index 44311ca..0000000 --- a/src/sshd.rs +++ /dev/null @@ -1,96 +0,0 @@ -use anyhow::*; -use lazy_static::lazy_static; -use regex::Regex; -use std::{net::IpAddr, str::FromStr}; - -use crate::utils::ParsingStatus; - -struct Rule { - matcher: String, - extractor: Regex, -} - -lazy_static! { - static ref SSHD_BAD: [Rule; 3] = [ - Rule { - matcher: "Failed password".to_string(), - extractor: Regex::new(r"(from.)(\S+)").unwrap(), - }, - Rule { - matcher: "Invalid user ".to_string(), - extractor: Regex::new(r"(from.)(\S+)").unwrap(), - }, - Rule { - matcher: "authentication failure".to_string(), - extractor: Regex::new(r"(rhost=)(\S+)").unwrap() - }, - ]; -} - -pub fn parse(line: &str) -> Result { - let hits = SSHD_BAD - .iter() - .find(|rule| line.contains(&rule.matcher)) - .and_then(|r| r.extractor.captures(line)); - - if hits.is_none() { - return Ok(ParsingStatus::OkEntry); - } - - let ip = hits - .and_then(|c| c.get(2)) - .and_then(|m| IpAddr::from_str(m.as_str()).ok()) - .ok_or_else(|| anyhow!("cant parse sshd line"))?; - - Ok(ParsingStatus::BadEntry(ip)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn positive() { - let vectors = [ - "Sep 26 06:25:19 livecompute sshd[23246]: Failed password for root from 179.124.36.195 port 41883 ssh2", - "Sep 26 06:26:14 livecompute sshd[23292]: pam_unix(sshd:auth): authentication failure; logname= u =0 tty=ssh ruser= rhost=5.101.107.190", - "Sep 26 06:25:32 livecompute sshd[23254]: Invalid user neal from 35.184.211.144" - ]; - - vectors.iter().for_each(|e| { - let ret = parse(*e).unwrap(); - match ret { - ParsingStatus::BadEntry(_) => {} - _ => panic!("bad parsing"), - } - }) - } - - #[test] - fn negative() { - let vectors = [ - "Sep 26 06:25:19 livecompute sshd[23246]: successful login 179.124.36.195 port 41883 ssh2", - "Sep 26 06:26:14 livecompute sshd[23292]: pam_unix(sshd:auth): authentication total success; logname= u =0 tty=ssh ruser= rhost=5.101.107.190", - "Sep 26 06:25:32 livecompute sshd[23254]: very good user neal from 35.184.211.144" - ]; - - vectors.iter().for_each(|e| { - let ret = parse(*e).unwrap(); - match ret { - ParsingStatus::OkEntry => {} - _ => panic!("bad parsing"), - } - }) - } - - #[test] - fn malformed() { - let vectors = [ - "Sep 26 06:25:19 livecompute sshd[23246]: Failed password for root from 179.124.36.195.232 port 41883 ssh2", - ]; - - vectors.iter().for_each(|e| { - parse(*e).expect_err(""); - }) - } -} diff --git a/src/utils.rs b/src/utils.rs index e8c4a05..7a90043 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -86,11 +86,11 @@ Blockfast - block internets scanners fast 🍶 Author: pierre dubouilh Blockfast reads logs from various sources and blocks the offending IPs using iptables and ipset. -It supports logs from sshd, Common-Log-Format (Apache, etc..), JSON (Caddy) and a generic logs parser. +It supports logs in Common-Log-Format (Apache, etc..), JSON (Caddy) and a generic logs parser. Example: - # block invalid sshd attempts & invalid http statuses from caddy - ./blockfast -s=/var/log/auth.log -j=/caddy/logs + # block invalid http statuses from caddy + ./blockfast -j=/caddy/logs # generic log parser example with a log text to flag, and a regex to parse the offending IP. ./blockfast --generic-logpath=/tmp/generictest --generic-positive='Failed password' --generic-ip='from ([0-9a-fA-F:.]+) port'", @@ -110,10 +110,6 @@ pub struct Args { #[clap(short, long)] pub verbose: bool, - /// path of sshd logfile, can be repeated - #[clap(short, long, value_parser = resolve_path)] - pub sshd_logpath: Vec, - /// path of Common-Log-Format logfile (Apache, etc..), can be repeated #[clap(short, long, value_parser = resolve_path)] pub clf_logpath: Vec,