mirror of
https://github.com/pldubouilh/blockfast.git
synced 2026-09-05 08:37:47 -04:00
drop sshd support
This commit is contained in:
committed by
Pierre Dubouilh
parent
ac17c11158
commit
e63e926ccf
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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>,
|
||||||
|
|||||||
Reference in New Issue
Block a user