ipblc/src/ipblc.rs

266 lines
8.8 KiB
Rust
Raw Normal View History

2022-12-30 20:18:15 +01:00
use crate::config::{Context, GIT_VERSION};
use crate::fw::{fwblock, fwglobalinit};
2023-01-15 16:05:34 +01:00
use crate::ip::{filter, IpData, IpEvent};
use crate::ipevent;
2023-04-09 01:42:17 +02:00
use crate::monitoring::apiserver;
2023-05-13 10:40:46 +02:00
use crate::utils::{gethostname, read_lines, sleep_s};
2023-03-05 23:05:50 +01:00
use crate::webservice::send_to_ipbl_api;
2023-04-10 16:33:03 +02:00
use crate::websocket::{send_to_ipbl_websocket, websocketpubsub, websocketreqrep};
use chrono::prelude::*;
2022-12-30 20:18:15 +01:00
use chrono::prelude::{DateTime, Local};
2022-07-01 15:51:41 +02:00
use chrono::Duration;
use nix::sys::inotify::{InitFlags, Inotify, InotifyEvent};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::mpsc::{channel, Receiver, Sender};
2023-01-10 18:00:40 +01:00
use tokio::sync::RwLock;
2023-01-08 21:16:06 +01:00
pub const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const BL_CHAN_SIZE: usize = 32;
2023-04-09 01:42:17 +02:00
const WS_CHAN_SIZE: usize = 64;
2023-05-13 10:40:46 +02:00
const LOOP_MAX_WAIT: u64 = 5;
2022-12-30 20:18:15 +01:00
pub async fn run() {
let inotify = Inotify::init(InitFlags::empty()).unwrap();
let globalctx = Context::new(&inotify).await;
2023-01-15 22:07:56 +01:00
let ctxarc = Arc::new(RwLock::new(globalctx));
2023-03-05 23:05:50 +01:00
let mut fwlen: usize = 0;
2023-01-08 21:16:06 +01:00
let pkgversion = format!("{}@{}", env!("CARGO_PKG_VERSION"), GIT_VERSION);
let mut last_cfg_reload: DateTime<Local> = Local::now().trunc_subsecs(0);
println!("Launching {}, version {}", PKG_NAME, pkgversion);
fwglobalinit();
2023-01-08 21:16:06 +01:00
2023-04-09 01:42:17 +02:00
let ctxapi = Arc::clone(&ctxarc);
apiserver(&ctxapi).await.unwrap();
2023-03-05 23:05:50 +01:00
// initialize sockets
2023-04-09 01:42:17 +02:00
let (ipeventtx, mut ipeventrx): (Sender<IpEvent>, Receiver<IpEvent>) = channel(WS_CHAN_SIZE);
2023-04-10 11:31:16 +02:00
let ipeventtxarc = Arc::new(RwLock::new(ipeventtx));
2023-04-10 16:57:12 +02:00
// init pubsub
2023-04-10 16:33:03 +02:00
let ctxwsps = Arc::clone(&ctxarc);
2023-04-10 16:57:12 +02:00
let ipeventws = Arc::clone(&ipeventtxarc);
2023-04-10 16:33:03 +02:00
websocketpubsub(&ctxwsps, ipeventws).await;
2023-04-10 16:57:12 +02:00
let ctxwsrr = Arc::clone(&ctxarc);
let mut wssocketrr = websocketreqrep(&ctxwsrr).await;
// init file watcher
let inoarc = Arc::new(RwLock::new(inotify));
let inoclone = Arc::clone(&inoarc);
let mut blrx = watchfiles(inoclone).await;
2023-01-08 21:16:06 +01:00
let ctxclone = Arc::clone(&ctxarc);
2023-04-10 11:31:16 +02:00
let ipeventclone = Arc::clone(&ipeventtxarc);
tokio::spawn(async move {
2023-04-10 11:31:16 +02:00
compare_files_changes(&ctxclone, &mut blrx, &ipeventclone).await;
});
loop {
2023-04-10 11:31:16 +02:00
let mut ret: Vec<String> = Vec::new();
2023-01-08 21:16:06 +01:00
let ctxclone = Arc::clone(&ctxarc);
2023-01-08 14:09:13 +01:00
tokio::select! {
2023-04-09 15:05:09 +02:00
ipevent = ipeventrx.recv() => {
let received_ip = ipevent.unwrap();
2023-01-08 21:16:06 +01:00
let (toblock,server) = {
let ctx = ctxclone.read().await;
(ctx.get_blocklist_toblock().await,ctx.flags.server.clone())
};
2023-05-07 11:23:55 +02:00
2023-01-15 16:40:27 +01:00
if received_ip.msgtype == "bootstrap".to_string() {
2023-05-10 21:32:27 +02:00
for ip_to_send in toblock {
let ipe = ipevent!("init","ws",gethostname(true),ip_to_send);
2023-04-10 16:44:53 +02:00
if !send_to_ipbl_websocket(&mut wssocketrr, &ipe).await {
2023-04-10 16:33:03 +02:00
wssocketrr = websocketreqrep(&ctxwsrr).await;
2023-04-10 16:44:53 +02:00
break;
2023-04-10 14:10:56 +02:00
}
2023-01-08 14:09:13 +01:00
}
2023-01-15 16:53:58 +01:00
continue
2023-01-08 14:09:13 +01:00
}
2023-05-07 11:23:55 +02:00
// refresh context blocklist
let filtered_ipevent = {
ctxarc.write().await.update_blocklist(&received_ip).await
};
2023-03-05 23:05:50 +01:00
// send ip list to api and ws sockets
2023-01-15 23:54:15 +01:00
if let Some(ipevent) = filtered_ipevent {
2023-01-15 16:53:58 +01:00
if received_ip.msgtype != "init" {
2023-03-05 23:05:50 +01:00
println!("sending {} to api and ws", ipevent.ipdata.ip);
let ipe = ipevent!("add","ws",gethostname(true),ipevent.ipdata);
2023-05-10 21:32:27 +02:00
send_to_ipbl_api(&server.clone(), &ipe).await;
2023-04-10 11:31:16 +02:00
let status = send_to_ipbl_websocket(&mut wssocketrr, &ipe).await;
if !status {
2023-04-10 16:33:03 +02:00
wssocketrr = websocketreqrep(&ctxwsrr).await;
continue;
2023-04-10 11:31:16 +02:00
}
2023-01-15 16:53:58 +01:00
}
2022-07-01 15:51:41 +02:00
}
2023-01-08 14:09:13 +01:00
}
2023-05-13 10:40:46 +02:00
_val = sleep_s(LOOP_MAX_WAIT) => {}
2023-01-08 14:09:13 +01:00
};
2023-01-08 21:16:06 +01:00
2023-04-10 11:57:03 +02:00
let ctxclone = Arc::clone(&ctxarc);
handle_fwblock(ctxclone, &mut ret, &mut fwlen).await;
2023-01-08 21:16:06 +01:00
// log lines
if ret.len() > 0 {
println!("{ret}", ret = ret.join(", "));
}
2023-04-10 11:57:03 +02:00
let ctxclone = Arc::clone(&ctxarc);
let inoclone = Arc::clone(&inoarc);
handle_cfg_reload(&ctxclone, &mut last_cfg_reload, inoclone).await;
2023-04-10 11:57:03 +02:00
}
}
async fn handle_cfg_reload(
ctxclone: &Arc<RwLock<Context>>,
last_cfg_reload: &mut DateTime<Local>,
inoarc: Arc<RwLock<Inotify>>,
) {
2023-04-10 11:57:03 +02:00
let now_cfg_reload = Local::now().trunc_subsecs(0);
2023-05-13 10:40:46 +02:00
if (now_cfg_reload - *last_cfg_reload) > Duration::seconds(LOOP_MAX_WAIT as i64) {
let inotify = inoarc.read().await;
match ctxclone.write().await.load(&inotify).await {
2023-04-10 11:57:03 +02:00
Ok(_) => {
*last_cfg_reload = Local::now().trunc_subsecs(0);
2023-04-22 19:04:20 +02:00
}
Err(_) => {
println!("error reloading config");
2023-04-10 11:57:03 +02:00
}
}
};
}
async fn handle_fwblock(ctxclone: Arc<RwLock<Context>>, ret: &mut Vec<String>, fwlen: &mut usize) {
{
2023-04-10 11:57:03 +02:00
let mut ctx = ctxclone.write().await;
ctx.gc_blocklist().await;
}
let toblock = {
let ctx = ctxclone.read().await;
2023-05-22 08:19:11 +02:00
ctx.get_blocklist_toblock().await
};
2023-05-13 11:03:07 +02:00
// apply firewall blocking
match fwblock(&toblock, ret, fwlen) {
Ok(_) => {}
Err(err) => {
println!("Err: {err}, unable to push firewall rules, use super user")
}
};
}
async fn watchfiles(inoarc: Arc<RwLock<Inotify>>) -> Receiver<FileEvent> {
let (bltx, blrx): (Sender<FileEvent>, Receiver<FileEvent>) = channel(BL_CHAN_SIZE);
tokio::spawn(async move {
loop {
let events = inoarc.read().await.read_events().unwrap();
2023-01-08 21:16:06 +01:00
2022-09-21 21:03:01 +02:00
for inevent in events {
let date: DateTime<Local> = Local::now().trunc_subsecs(0);
2022-09-21 21:03:01 +02:00
bltx.send(FileEvent { inevent, date }).await.unwrap();
}
}
});
blrx
}
2022-09-23 13:17:20 +02:00
async fn get_last_file_size(w: &mut HashMap<String, u64>, path: &str) -> (u64, bool) {
let currentlen = match std::fs::metadata(&path.to_string()) {
2023-11-04 12:42:07 +01:00
Ok(u) => u.len(),
2022-09-23 13:17:20 +02:00
Err(_) => 0u64,
};
2022-09-21 21:03:01 +02:00
let lastlen = match w.insert(path.to_string(), currentlen) {
Some(u) => u,
2023-11-04 12:42:07 +01:00
None => currentlen,
};
2022-09-23 13:17:20 +02:00
(lastlen, lastlen != currentlen)
}
async fn compare_files_changes(
2023-01-10 18:00:40 +01:00
ctxarc: &Arc<RwLock<Context>>,
2022-09-21 21:03:01 +02:00
inrx: &mut Receiver<FileEvent>,
2023-04-10 11:31:16 +02:00
ipeventtx: &Arc<RwLock<Sender<IpEvent>>>,
) {
2022-09-21 21:03:01 +02:00
let mut tnets;
loop {
2022-09-21 21:03:01 +02:00
let modfiles = inrx.recv().await.unwrap();
let mut iplist: Vec<IpData> = vec![];
let sas = {
2023-01-10 18:00:40 +01:00
let ctx = ctxarc.read().await;
2023-01-08 21:16:06 +01:00
tnets = ctx.cfg.build_trustnets();
ctx.sas.clone()
};
2022-09-21 21:03:01 +02:00
match modfiles.inevent.name {
Some(name) => {
2022-09-21 21:03:01 +02:00
let filename = name.to_str().unwrap();
2023-12-12 22:41:21 +01:00
for (sak, sa) in sas.clone().iter_mut() {
2022-09-21 21:03:01 +02:00
if modfiles.inevent.wd == sa.wd {
let handle: String;
if sa.filename.as_str() == "" {
2022-09-21 21:03:01 +02:00
handle = format!("{}/{}", &sa.fullpath, filename);
} else if filename.starts_with(sa.filename.as_str()) {
handle = sa.fullpath.to_owned();
} else {
continue;
}
let (filesize, sizechanged) = {
2023-01-10 18:00:40 +01:00
let mut ctx = ctxarc.write().await;
2023-01-08 21:16:06 +01:00
let sa = ctx.sas.get_mut(sak).unwrap();
get_last_file_size(&mut sa.watchedfiles, &handle).await
};
2022-09-23 13:17:20 +02:00
if !sizechanged {
continue;
}
2022-09-21 21:03:01 +02:00
match read_lines(&handle, filesize) {
Some(lines) => {
filter(
lines,
2022-09-21 21:03:01 +02:00
&mut iplist,
&tnets,
&sa.regex,
2022-07-01 15:51:41 +02:00
&sa.set.src,
2022-09-21 21:03:01 +02:00
&modfiles.date,
);
}
None => {}
};
break;
}
}
2022-09-21 21:03:01 +02:00
for ip in iplist {
let ipe = ipevent!("add", "file", gethostname(true), ip);
let ipetx = ipeventtx.read().await;
ipetx.send(ipe).await.unwrap();
}
}
None => {}
}
}
}
2022-12-30 20:18:15 +01:00
pub struct FileEvent {
pub inevent: InotifyEvent,
pub date: DateTime<Local>,
}
impl std::fmt::Debug for FileEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{ie:?}", ie = self.inevent)
}
}