better err handling, and WIP iptables asve
This commit is contained in:
parent
f4a3062663
commit
bb9235b6ef
@ -6,6 +6,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
pull_policy: build
|
||||||
|
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
@ -13,3 +14,4 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- /var/log/auth.log:/host_ssh/auth.log
|
- /var/log/auth.log:/host_ssh/auth.log
|
||||||
|
- /etc/iptables/rules.v4:/host_iptables/rules.v4
|
||||||
|
8
src/iptables_save.rs
Normal file
8
src/iptables_save.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
pub fn save_iptables() {
|
||||||
|
let _ = Command::new("iptables-save")
|
||||||
|
.arg(">")
|
||||||
|
.arg("/host_iptables/rules.v4")
|
||||||
|
.output();
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
|
use regex::Regex;
|
||||||
|
|
||||||
pub struct LoginAttempt {
|
pub struct LoginAttempt {
|
||||||
pub ip: String,
|
pub ip: String,
|
||||||
user: String,
|
pub user: String,
|
||||||
port: String,
|
pub port: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginAttempt {
|
impl LoginAttempt {
|
||||||
@ -12,4 +14,14 @@ impl LoginAttempt {
|
|||||||
port: port.to_string(),
|
port: port.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn capture(line: &str) -> Option<Self> {
|
||||||
|
let regex = Regex::new(r#"Failed password for (?:invalid user )?(?P<user>\S+) from (?P<ip>\S+) port (?P<port>\d+)"#).unwrap();
|
||||||
|
let captured = regex.captures(line)?;
|
||||||
|
Some(Self::new(
|
||||||
|
captured.name("ip").unwrap().as_str(),
|
||||||
|
captured.name("user").unwrap().as_str(),
|
||||||
|
captured.name("port").unwrap().as_str(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
34
src/main.rs
34
src/main.rs
@ -1,8 +1,8 @@
|
|||||||
|
pub mod iptables_save;
|
||||||
pub mod login_attempt;
|
pub mod login_attempt;
|
||||||
|
|
||||||
use linemux::MuxedLines;
|
use linemux::MuxedLines;
|
||||||
use login_attempt::LoginAttempt;
|
use login_attempt::LoginAttempt;
|
||||||
use regex::Regex;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -12,24 +12,32 @@ async fn main() -> std::io::Result<()> {
|
|||||||
lines.add_file("/host_ssh/auth.log").await?;
|
lines.add_file("/host_ssh/auth.log").await?;
|
||||||
let mut login_attempts: HashMap<String, usize> = HashMap::new();
|
let mut login_attempts: HashMap<String, usize> = HashMap::new();
|
||||||
|
|
||||||
println!("Listening to changes over /host_ssh/auth.log");
|
println!("listening to changes over /host_ssh/auth.log");
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
if let Some(login_attempt) = capture_failed_login_attempt(line.line()) {
|
if let Some(login_attempt) = LoginAttempt::capture(line.line()) {
|
||||||
|
println!(
|
||||||
|
"failed login attempt from {}@{}:{}",
|
||||||
|
login_attempt.user, login_attempt.ip, login_attempt.port
|
||||||
|
);
|
||||||
match login_attempts.get_mut(&login_attempt.ip) {
|
match login_attempts.get_mut(&login_attempt.ip) {
|
||||||
Some(count) => {
|
Some(count) => {
|
||||||
*count += 1;
|
*count += 1;
|
||||||
|
|
||||||
if *count == 3 {
|
if *count == 3 {
|
||||||
iptables
|
match iptables.append_unique(
|
||||||
.append_unique(
|
|
||||||
"filter",
|
"filter",
|
||||||
"INPUT",
|
"INPUT",
|
||||||
&format!("--source {} -j DROP", login_attempt.ip),
|
&format!("--source {} -j DROP", login_attempt.ip),
|
||||||
)
|
) {
|
||||||
.unwrap();
|
Ok(_) => {
|
||||||
login_attempts.remove(&login_attempt.ip);
|
|
||||||
println!("{} banned", login_attempt.ip);
|
println!("{} banned", login_attempt.ip);
|
||||||
}
|
}
|
||||||
|
Err(_) => {
|
||||||
|
println!("{} already banned", login_attempt.ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
login_attempts.remove(&login_attempt.ip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
login_attempts.insert(login_attempt.ip.clone(), 1);
|
login_attempts.insert(login_attempt.ip.clone(), 1);
|
||||||
@ -39,13 +47,3 @@ async fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_failed_login_attempt(line: &str) -> Option<LoginAttempt> {
|
|
||||||
let regex = Regex::new(r#"Failed password for (?:invalid user )?(?P<user>\S+) from (?P<ip>\S+) port (?P<port>\d+)"#).unwrap();
|
|
||||||
let captured = regex.captures(line)?;
|
|
||||||
Some(LoginAttempt::new(
|
|
||||||
captured.name("ip").unwrap().as_str(),
|
|
||||||
captured.name("user").unwrap().as_str(),
|
|
||||||
captured.name("port").unwrap().as_str(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user