1
0

moving code from command server into cli

This commit is contained in:
2024-05-28 16:03:32 +02:00
parent 8a6021aa83
commit d53ca8a33a
8 changed files with 323 additions and 146 deletions

44
src/cli.rs Normal file
View File

@ -0,0 +1,44 @@
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(name = "martillo-maldito", about = "A simple iptables ban server")]
pub enum Arguments {
#[structopt(about = "Initialize ban server")]
BanServer {
#[structopt(name = "Ssh auth log file", short = "f", long = "ssh-file")]
ssh_auth_log: PathBuf,
#[structopt(name = "Iptables save file", short = "s", long = "iptables-save")]
iptables_save: Option<PathBuf>,
},
#[structopt(about = "Ban port")]
BanPort {
#[structopt(name = "Port to ban", short = "p", long = "port")]
port: u16,
},
#[structopt(about = "Unban port")]
UnbanPort {
#[structopt(name = "Port to unban", short = "p", long = "port")]
port: u16,
},
#[structopt(about = "Allow ip and port")]
AllowIpPort {
#[structopt(name = "Ip to allow", short = "i", long = "ip")]
ip: String,
#[structopt(name = "Port to allow", short = "p", long = "port")]
port: u16,
},
#[structopt(about = "Remove ip and port")]
RemoveIpPort {
#[structopt(name = "Ip to remove", short = "i", long = "ip")]
ip: String,
#[structopt(name = "Port to remove", short = "p", long = "port")]
port: u16,
},
}

View File

@ -1,7 +1,7 @@
use std::process::Command;
use std::{path::Path, process::Command};
pub fn save_iptables() {
pub fn save_iptables(path: &Path) {
let _ = Command::new("iptables-save")
.args(&["-f", "/host_iptables/rules.v4"])
.args(["-f", path.to_str().unwrap()])
.output();
}

41
src/iptables_wrapper.rs Normal file
View File

@ -0,0 +1,41 @@
pub fn ban_port(port: u16) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.append_unique(
"filter",
"INPUT",
&format!("-p tcp --dport {} -j DROP", port),
);
println!("banned port {}", port);
}
pub fn unban_port(port: u16) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.delete(
"filter",
"INPUT",
&format!("-p tcp --dport {} -j DROP", port),
);
println!("unbanned port {}", port);
}
pub fn allow_ip_port(ip: &str, port: u16) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.append_unique(
"filter",
"INPUT",
&format!("-p tcp --dport {} -s {} -j ACCEPT", port, ip),
);
println!("allowed {} to access {}", ip, port);
}
pub fn remove_ip_port(ip: &str, port: u16) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.delete(
"filter",
"INPUT",
&format!("-p tcp --dport {} -s {} -j ACCEPT", port, ip),
);
println!("removed access {} to {}", ip, port);
}

View File

@ -1,37 +1,57 @@
pub mod cli;
pub mod iptables_save;
pub mod iptables_wrapper;
pub mod login_attempt;
pub mod tpc_command_server;
use crate::tpc_command_server::start_tcp_command_server;
use cli::Arguments;
use iptables_wrapper::{allow_ip_port, ban_port, remove_ip_port, unban_port};
use linemux::MuxedLines;
use login_attempt::LoginAttempt;
use std::path::PathBuf;
use std::thread;
use std::{collections::HashMap, thread::sleep, time::Duration};
use structopt::StructOpt;
#[tokio::main]
async fn main() -> std::io::Result<()> {
async fn main() {
let opts = Arguments::from_args();
match opts {
Arguments::BanServer {
ssh_auth_log,
iptables_save,
} => {
let _ = start_ban_server(ssh_auth_log, iptables_save).await;
}
Arguments::BanPort { port } => ban_port(port),
Arguments::UnbanPort { port } => unban_port(port),
Arguments::AllowIpPort { ip, port } => allow_ip_port(&ip, port),
Arguments::RemoveIpPort { ip, port } => remove_ip_port(&ip, port),
}
}
async fn start_ban_server(
ssh_auth_log: PathBuf,
iptables_save: Option<PathBuf>,
) -> std::io::Result<()> {
let iptables = iptables::new(false).unwrap();
let mut lines = MuxedLines::new()?;
lines.add_file("/host_ssh/auth.log").await?;
lines.add_file(&ssh_auth_log).await?;
let mut login_attempts: HashMap<String, usize> = HashMap::new();
let seconds_iptables = Duration::from_secs(60);
println!(
"starting iptables-save, run every {} seconds",
seconds_iptables.as_secs()
);
if let Some(iptables_save) = iptables_save {
let seconds_iptables = Duration::from_secs(60);
println!(
"starting iptables-save, run every {} seconds",
seconds_iptables.as_secs()
);
thread::spawn(move || loop {
sleep(seconds_iptables);
iptables_save::save_iptables(&iptables_save);
println!("saved iptables rules");
});
}
thread::spawn(move || loop {
sleep(seconds_iptables);
iptables_save::save_iptables();
println!("saved iptables rules");
});
thread::spawn(|| {
start_tcp_command_server();
});
println!("listening to changes over /host_ssh/auth.log");
println!("listening to changes over {}", ssh_auth_log.display());
while let Ok(Some(line)) = lines.next_line().await {
if let Some(login_attempt) = LoginAttempt::capture(line.line()) {
println!(

View File

@ -1,103 +0,0 @@
use std::io::{BufRead, BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
pub fn start_tcp_command_server() {
let listener = TcpListener::bind("127.0.0.1:9999").unwrap();
println!("listening on port 9999 for tcp commands");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
thread::spawn(move || handle_client(&stream));
}
Err(e) => {
eprintln!("err with tcp conn: {}", e);
}
}
}
}
fn handle_client(mut stream: &TcpStream) {
for line in BufReader::new(stream).lines() {
let buffer = match line {
Ok(data) => data,
Err(_) => return,
};
if buffer.is_empty() {
break;
}
let mut parts = buffer.trim().split_whitespace();
if let Some(command) = parts.next() {
let arguments: Vec<&str> = parts.collect();
let response = handle_command(command, arguments);
stream.write_all(response.as_bytes()).unwrap();
} else {
stream.write_all("invalid command".as_bytes()).unwrap();
}
}
}
fn handle_command(command: &str, arguments: Vec<&str>) -> String {
match command {
"banport" => {
if let Some(port) = arguments.get(0) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.append_unique(
"filter",
"INPUT",
&format!("-p tcp --dport {} -j DROP", port),
);
format!("banned port {} for all ips", port)
} else {
"missing args for banport: port".to_string()
}
}
"unbanport" => {
if let Some(port) = arguments.get(0) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.delete(
"filter",
"INPUT",
&format!("-p tcp --dport {} -j DROP", port),
);
format!("unbanned port {}", port)
} else {
"missing args for unbanport: port".to_string()
}
}
"allowipport" => {
if let (Some(ip), Some(port)) = (arguments.get(0), arguments.get(1)) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.append_unique(
"filter",
"INPUT",
&format!("-s {} -p tcp --dport {} -j ACCEPT", ip, port),
);
format!("allowed {} to access {}", ip, port)
} else {
"missing args for allowipport: ip and port".to_string()
}
}
"removeipport" => {
if let (Some(ip), Some(port)) = (arguments.get(0), arguments.get(1)) {
let iptables = iptables::new(false).unwrap();
let _ = iptables.delete(
"filter",
"INPUT",
&format!("-s {} -p tcp --dport {} -j ACCEPT", ip, port),
);
format!("rm {} access to {}", ip, port)
} else {
"missing args for rmipport: ip and port".to_string()
}
}
_ => {
format!("unknown command: {}", command)
}
}
}