From b6b1cdd00029722c377d1827b2b07419a1171518 Mon Sep 17 00:00:00 2001 From: midefos Date: Wed, 14 Aug 2024 18:31:11 +0200 Subject: [PATCH] improving docker ban and allow --- src/cli.rs | 5 +- src/iptables_wrapper.rs | 101 ++++++++++++++++++++++++++++++++-------- src/main.rs | 11 +++-- 3 files changed, 92 insertions(+), 25 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index a368f23..e60467f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -15,7 +15,10 @@ pub enum Cli { iptables_save: Option, }, #[structopt(about = "List all banned ips")] - ListBannedIps, + ListBannedIps { + #[structopt(name = "Docker", short = "d", long = "docker")] + docker: bool, + }, #[structopt(about = "List all secured ports")] ListSecuredPorts { #[structopt(name = "Docker", short = "d", long = "docker")] diff --git a/src/iptables_wrapper.rs b/src/iptables_wrapper.rs index 05ea955..4293d8d 100644 --- a/src/iptables_wrapper.rs +++ b/src/iptables_wrapper.rs @@ -19,7 +19,9 @@ pub fn is_port_secured(port: u16, docker: bool) -> bool { pub fn list_secured_ports(docker: bool) -> Vec { let iptables = iptables::new(false).unwrap(); - let rules = iptables.list("filter", &get_chain(docker)); + + let chain = get_chain(docker); + let rules = iptables.list("filter", &chain); if rules.is_err() { return vec![]; } @@ -33,9 +35,11 @@ pub fn list_secured_ports(docker: bool) -> Vec { .collect() } -pub fn list_banned_ips() -> Vec { +pub fn list_banned_ips(docker: bool) -> Vec { let iptables = iptables::new(false).unwrap(); - let rules = iptables.list("filter", &get_chain(false)); + + let chain = get_chain(docker); + let rules = iptables.list("filter", &chain); if rules.is_err() { return vec![]; } @@ -44,7 +48,9 @@ pub fn list_banned_ips() -> Vec { rules .unwrap() .iter() - .filter(|r| r.contains("-A INPUT") && r.contains("-j DROP") && r.contains("-s")) + .filter(|r| { + r.contains(&format!("-A {}", chain)) && r.contains("-j DROP") && r.contains("-s") + }) .map(|r| extract_ip(&rgx, r).unwrap()) .collect() } @@ -57,7 +63,8 @@ pub fn map_secured_ports_allowed_ips(docker: bool) -> HashMap> } let iptables = iptables::new(false).unwrap(); - let rules = iptables.list("filter", &get_chain(docker)); + let chain = get_chain(docker); + let rules = iptables.list("filter", &chain); if rules.is_err() { return result; } @@ -68,7 +75,7 @@ pub fn map_secured_ports_allowed_ips(docker: bool) -> HashMap> let ips = rules .iter() .filter(|r| { - r.contains("-A INPUT -s") + r.contains(&format!("-A {} -s", chain)) && r.contains(&format!("-p tcp -m tcp --dport {} -j ACCEPT", port)) }) .map(|r| extract_ip(&rgx, r).unwrap()) @@ -79,8 +86,25 @@ pub fn map_secured_ports_allowed_ips(docker: bool) -> HashMap> result } -fn secure_port_rule(port: u16) -> String { - format!("-p tcp --dport {} -j DROP", port) +fn secure_port_rule(iptables: &IPTables, port: u16, docker: bool) -> Option { + if docker { + let internal_ip = get_internal_ip_for_docker_port(iptables, port)?; + Some(format!( + "-d {} -p tcp --dport {} -j DROP", + internal_ip, port + )) + } else { + Some(format!("-p tcp --dport {} -j DROP", port)) + } +} + +fn get_internal_ip_for_docker_port(iptables: &IPTables, port: u16) -> Option { + let rules = iptables.list("filter", "DOCKER").unwrap(); + let rule = rules + .iter() + .find(|r| r.contains(&format!("-p tcp -m tcp --dport {} -j ACCEPT", port))); + + rule.map(|r| extract_ip(&get_regex_for_ip(), r).unwrap()) } pub fn secure_port( @@ -92,7 +116,12 @@ pub fn secure_port( let table = "filter"; let chain = get_chain(docker); - let rule = secure_port_rule(port); + let rule = secure_port_rule(&iptables, port, docker); + if rule.is_none() { + return Err("Err gathering secure port rule".into()); + } + + let rule = rule.unwrap(); if let Some(position) = position { insert_unique(&iptables, table, &chain, &rule, position) } else { @@ -102,11 +131,31 @@ pub fn secure_port( pub fn unsecure_port(port: u16, docker: bool) -> Result<(), Box> { let iptables = iptables::new(false).unwrap(); - iptables.delete("filter", &get_chain(docker), &secure_port_rule(port)) + + let rule = secure_port_rule(&iptables, port, docker); + if rule.is_none() { + return Err("Err gathering secure port rule".into()); + } + + let rule = rule.unwrap(); + iptables.delete("filter", &get_chain(docker), &rule) } -fn allow_ip_for_port_rule(port: u16, ip: &str) -> String { - format!("-p tcp --dport {} -s {} -j ACCEPT", port, ip) +fn allow_ip_for_port_rule( + iptables: &IPTables, + port: u16, + ip: &str, + docker: bool, +) -> Option { + if docker { + let internal_ip = get_internal_ip_for_docker_port(iptables, port)?; + Some(format!( + "-p tcp --dport {} -s {} -d {} -j ACCEPT", + port, ip, internal_ip + )) + } else { + Some(format!("-p tcp --dport {} -s {} -j ACCEPT", port, ip)) + } } pub fn allow_ip_for_port( @@ -119,7 +168,12 @@ pub fn allow_ip_for_port( let table = "filter"; let chain = get_chain(docker); - let rule = allow_ip_for_port_rule(port, ip); + let rule = allow_ip_for_port_rule(&iptables, port, ip, docker); + if rule.is_none() { + return Err("Err gathering allow ip for port rule".into()); + } + + let rule = rule.unwrap(); if let Some(position) = position { insert_unique(&iptables, table, &chain, &rule, position) } else { @@ -133,11 +187,13 @@ pub fn remove_allow_ip_for_port( docker: bool, ) -> Result<(), Box> { let iptables = iptables::new(false).unwrap(); - iptables.delete( - "filter", - &get_chain(docker), - &allow_ip_for_port_rule(port, ip), - ) + let rule = allow_ip_for_port_rule(&iptables, port, ip, docker); + if rule.is_none() { + return Err("Err gathering allow ip for port rule".into()); + } + + let rule = rule.unwrap(); + iptables.delete("filter", &get_chain(docker), &rule) } fn get_chain(docker: bool) -> String { @@ -199,9 +255,16 @@ mod tests { } #[test] - fn no_match_extrac_ip() { + fn no_match_extract_ip() { let regex = get_regex_for_ip(); let input = "-A INPUT -j DROP"; assert_eq!(extract_ip(®ex, input), None); } + + #[test] + fn docker_extract_ip() { + let regex = get_regex_for_ip(); + let input = "-A DOCKER -d 172.18.0.2/32 ! -i br-127d33df48a4 -o br-127d33df48a4 -p tcp -m tcp --dport 8078 -j ACCEPT"; + assert_eq!(extract_ip(®ex, input), Some("172.18.0.2".to_string())); + } } diff --git a/src/main.rs b/src/main.rs index 5c2e2b0..2b8f8c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,9 +10,7 @@ use iptables_wrapper::{ }; use linemux::MuxedLines; use login_attempt::LoginAttempt; -use std::path::PathBuf; -use std::thread::spawn; -use std::{collections::HashMap, thread::sleep, time::Duration}; +use std::{collections::HashMap, path::PathBuf, thread::sleep, thread::spawn, time::Duration}; use structopt::StructOpt; #[tokio::main] @@ -24,8 +22,11 @@ async fn main() { } => { let _ = start_ban_server(ssh_auth_log, iptables_save).await; } - Cli::ListBannedIps => { - println!("{}", serde_json::to_string(&list_banned_ips()).unwrap()); + Cli::ListBannedIps { docker } => { + println!( + "{}", + serde_json::to_string(&list_banned_ips(docker)).unwrap() + ); } Cli::ListSecuredPorts { docker } => { println!(