drop sshd support

This commit is contained in:
Pierre Dubouilh
2026-08-28 00:34:23 +02:00
committed by Pierre Dubouilh
parent ac17c11158
commit e63e926ccf
5 changed files with 19 additions and 144 deletions
+1 -8
View File
@@ -8,12 +8,11 @@ build::
cargo fmt --all cargo fmt --all
run:: run::
touch /tmp/sshdtest
touch /tmp/clftest touch /tmp/clftest
touch /tmp/jsontest touch /tmp/jsontest
touch /tmp/generictest touch /tmp/generictest
cargo build 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 ci:: test
cargo fmt --all -- --check cargo fmt --all -- --check
@@ -44,12 +43,6 @@ test::
release:: release::
cargo build --target x86_64-unknown-linux-musl --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:: 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 echo "Sep 26 06:25:19 livecompute sshd[23246]: Failed password for root from 179.124.36.195 port 41883 ssh2" >> /tmp/generictest
+13 -17
View File
@@ -3,7 +3,6 @@
Block internets scanners fast 🍶 Block internets scanners fast 🍶
Features: Features:
- SSH log parser
- Common Log Format parser (apache logs, etc...) - Common Log Format parser (apache logs, etc...)
- JSON log parser (caddy logs) - JSON log parser (caddy logs)
- Generic log parser - Generic log parser
@@ -14,16 +13,15 @@ Features:
## example ## example
```txt ```txt
$ ./blockfast -s=/var/log/auth.log -j=/caddy/logs $ ./blockfast -j=/caddy/logs
1737927469 - starting with sshd parsing at "/tmp/sshdtest"
1737927469 - starting with json parsing at "/tmp/jsontest" 1737927469 - starting with json parsing at "/tmp/jsontest"
1737927469 - jail setup, allowance 5, time 21600s 1737927469 - jail setup, allowance 5, time 21600s
1737927477 - sshd logged offence for 9.124.36.195 1737927477 - json logged offence for 9.124.36.195
1737927478 - sshd logged offence for 9.124.36.195 1737927478 - json logged offence for 9.124.36.195
1737927479 - sshd logged offence for 9.124.36.195 1737927479 - json logged offence for 9.124.36.195
1737927479 - sshd logged offence for 9.124.36.195 1737927479 - json logged offence for 9.124.36.195
1737927480 - sshd logged offence for 9.124.36.195 1737927480 - json logged offence for 9.124.36.195
1737927480 - sshd jailtime for 9.124.36.195 1737927480 - json jailtime for 9.124.36.195
``` ```
## build ## build
@@ -36,11 +34,11 @@ Blockfast - block internets scanners fast 🍶
Author: pierre dubouilh <pldubouilh@gmail.com> Author: pierre dubouilh <pldubouilh@gmail.com>
Blockfast reads logs from various sources and blocks the offending IPs using iptables and ipset. 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: Example:
# block invalid sshd attempts & invalid http statuses from caddy # block invalid http statuses from caddy
./blockfast -s=/var/log/auth.log -j=/caddy/logs ./blockfast -j=/caddy/logs
# generic log parser example with a log text to flag, and a regex to parse the offending IP. # 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' ./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] how many offences allowed (max 255) [default: 5]
-v, --verbose -v, --verbose
log all offences log all offences
-s, --sshd-logpath <SSHD_LOGPATH>
path of sshd logfile
-c, --clf-logpath <CLF_LOGPATH> -c, --clf-logpath <CLF_LOGPATH>
path of Common-Log-Format logfile (Apache, etc..) path of Common-Log-Format logfile (Apache, etc..), can be repeated
-j, --json-logpath <JSON_LOGPATH> -j, --json-logpath <JSON_LOGPATH>
path of JSON logfile (works with Caddy) path of JSON logfile (works with Caddy), can be repeated
--generic-logpath <GENERIC_LOGPATH> --generic-logpath <GENERIC_LOGPATH>
generic parser log file path generic parser log file path, can be repeated
--generic-ip <GENERIC_IP> --generic-ip <GENERIC_IP>
generic parser ip regex generic parser ip regex
--generic-positive <GENERIC_POSITIVE> --generic-positive <GENERIC_POSITIVE>
+2 -16
View File
@@ -7,7 +7,6 @@ use linemux::{Line, MuxedLines};
mod clf; mod clf;
mod generic; mod generic;
mod json; mod json;
mod sshd;
mod utils; mod utils;
mod jail; mod jail;
@@ -33,13 +32,6 @@ async fn run() -> Result<()> {
log!("starting with generic parsing at {:?}", &p); 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 // common log format
let clf_logpaths = &args.clf_logpath; let clf_logpaths = &args.clf_logpath;
for p in clf_logpaths { for p in clf_logpaths {
@@ -54,11 +46,7 @@ async fn run() -> Result<()> {
log!("starting with json parsing at {:?}", &p); log!("starting with json parsing at {:?}", &p);
} }
if json_logpaths.is_empty() if json_logpaths.is_empty() && clf_logpaths.is_empty() && generic_paths.is_empty() {
&& clf_logpaths.is_empty()
&& sshd_logpaths.is_empty()
&& generic_paths.is_empty()
{
bail!("no log files to parse, see --help"); 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_buf = Some(line.source().to_path_buf());
let path = path_buf.as_ref(); let path = path_buf.as_ref();
let (target, ret) = if path.is_some_and(|p| sshd_logpaths.contains(p)) { let (target, ret) = if path.is_some_and(|p| clf_logpaths.contains(p)) {
("sshd", sshd::parse(payload)?)
} else if path.is_some_and(|p| clf_logpaths.contains(p)) {
("clf", clf::parse(payload, invalid_statuses_ref)?) ("clf", clf::parse(payload, invalid_statuses_ref)?)
} else if path.is_some_and(|p| json_logpaths.contains(p)) { } else if path.is_some_and(|p| json_logpaths.contains(p)) {
("json", json::parse(payload, invalid_statuses_ref)?) ("json", json::parse(payload, invalid_statuses_ref)?)
-96
View File
@@ -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<ParsingStatus> {
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("");
})
}
}
+3 -7
View File
@@ -86,11 +86,11 @@ Blockfast - block internets scanners fast 🍶
Author: pierre dubouilh <pldubouilh@gmail.com> Author: pierre dubouilh <pldubouilh@gmail.com>
Blockfast reads logs from various sources and blocks the offending IPs using iptables and ipset. 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: Example:
# block invalid sshd attempts & invalid http statuses from caddy # block invalid http statuses from caddy
./blockfast -s=/var/log/auth.log -j=/caddy/logs ./blockfast -j=/caddy/logs
# generic log parser example with a log text to flag, and a regex to parse the offending IP. # 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'", ./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)] #[clap(short, long)]
pub verbose: bool, pub verbose: bool,
/// path of sshd logfile, can be repeated
#[clap(short, long, value_parser = resolve_path)]
pub sshd_logpath: Vec<PathBuf>,
/// path of Common-Log-Format logfile (Apache, etc..), can be repeated /// path of Common-Log-Format logfile (Apache, etc..), can be repeated
#[clap(short, long, value_parser = resolve_path)] #[clap(short, long, value_parser = resolve_path)]
pub clf_logpath: Vec<PathBuf>, pub clf_logpath: Vec<PathBuf>,