parent
5036dc3ba8
commit
7a49ac320c
@ -10,6 +10,7 @@ platform:
|
|||||||
steps:
|
steps:
|
||||||
- name: test and build
|
- name: test and build
|
||||||
image: rust:1
|
image: rust:1
|
||||||
|
pull: always
|
||||||
commands:
|
commands:
|
||||||
- apt-get update -y
|
- apt-get update -y
|
||||||
- apt-get install -y libnftnl-dev libmnl-dev
|
- apt-get install -y libnftnl-dev libmnl-dev
|
||||||
@ -26,6 +27,7 @@ steps:
|
|||||||
- tag
|
- tag
|
||||||
- name: release
|
- name: release
|
||||||
image: rust:1
|
image: rust:1
|
||||||
|
pull: always
|
||||||
commands:
|
commands:
|
||||||
- apt-get update -y
|
- apt-get update -y
|
||||||
- apt-get install -y libnftnl-dev libmnl-dev
|
- apt-get install -y libnftnl-dev libmnl-dev
|
||||||
@ -75,6 +77,7 @@ platform:
|
|||||||
steps:
|
steps:
|
||||||
- name: test and build
|
- name: test and build
|
||||||
image: rust:1
|
image: rust:1
|
||||||
|
pull: always
|
||||||
commands:
|
commands:
|
||||||
- apt-get update -y
|
- apt-get update -y
|
||||||
- apt-get install -y libnftnl-dev libmnl-dev
|
- apt-get install -y libnftnl-dev libmnl-dev
|
||||||
@ -91,6 +94,7 @@ steps:
|
|||||||
- tag
|
- tag
|
||||||
- name: release
|
- name: release
|
||||||
image: rust:1
|
image: rust:1
|
||||||
|
pull: always
|
||||||
commands:
|
commands:
|
||||||
- apt-get update -y
|
- apt-get update -y
|
||||||
- apt-get install -y libnftnl-dev libmnl-dev
|
- apt-get install -y libnftnl-dev libmnl-dev
|
||||||
|
550
Cargo.lock
generated
550
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ipblc"
|
name = "ipblc"
|
||||||
version = "1.2.2"
|
version = "1.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["PaulBSD <paul@paulbsd.com>"]
|
authors = ["PaulBSD <paul@paulbsd.com>"]
|
||||||
description = "ipblc is a tool that search and send attacking ip addresses to ipbl"
|
description = "ipblc is a tool that search and send attacking ip addresses to ipbl"
|
||||||
@ -10,19 +10,19 @@ repository = "https://git.paulbsd.com/paulbsd/ipblc"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
clap = { version = "4.2", features = ["string"] }
|
clap = { version = "4.4", features = ["string"] }
|
||||||
git-version = "0.3"
|
git-version = "0.3"
|
||||||
ipnet = "2.7"
|
ipnet = "2.9"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
mnl = "0.2"
|
mnl = "0.2"
|
||||||
nftnl = "0.6"
|
nftnl = "0.6"
|
||||||
nix = "0.26"
|
nix = { version = "0.27", features = ["hostname", "inotify"] }
|
||||||
regex = "1.8"
|
regex = "1.10"
|
||||||
reqwest = { version = "0.11", default-features = false, features = ["json","rustls-tls"] }
|
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "1.28", features = ["full", "sync"] }
|
tokio = { version = "1.33", features = ["full", "sync"] }
|
||||||
tungstenite = { version = "0.19", features = ["handshake","rustls-tls-native-roots"] }
|
tungstenite = { version = "0.20", features = ["handshake", "rustls-tls-native-roots"] }
|
||||||
|
|
||||||
## to optimize binary size (slow compile time)
|
## to optimize binary size (slow compile time)
|
||||||
#[profile.release]
|
#[profile.release]
|
||||||
|
@ -2,5 +2,5 @@ FROM rustembedded/cross:aarch64-unknown-linux-musl
|
|||||||
|
|
||||||
RUN dpkg --add-architecture arm64
|
RUN dpkg --add-architecture arm64
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get install -y libasound2-dev:arm64 libzmq3-dev libnftnl-dev libmnl-dev libmnl0:arm64 libnftnl7:arm64 libmnl0:amd64 libnftnl0:arm64
|
RUN apt-get install -y libnftnl-dev libmnl-dev libmnl0:arm64 libnftnl7:arm64 libmnl0:amd64 libnftnl0:arm64
|
||||||
RUN apt-get clean
|
RUN apt-get clean
|
||||||
|
@ -6,7 +6,7 @@ use chrono::Duration;
|
|||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
use git_version::git_version;
|
use git_version::git_version;
|
||||||
use ipnet::IpNet;
|
use ipnet::IpNet;
|
||||||
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify, WatchDescriptor};
|
use nix::sys::inotify::{AddWatchFlags, Inotify, WatchDescriptor};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{Client, Error as ReqError, Response};
|
use reqwest::{Client, Error as ReqError, Response};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -17,16 +17,15 @@ use std::path::Path;
|
|||||||
pub const GIT_VERSION: &str = git_version!(args = ["--always", "--dirty="]);
|
pub const GIT_VERSION: &str = git_version!(args = ["--always", "--dirty="]);
|
||||||
const MASTERSERVER: &str = "ipbl.paulbsd.com";
|
const MASTERSERVER: &str = "ipbl.paulbsd.com";
|
||||||
const WSSUBSCRIPTION: &str = "ipbl";
|
const WSSUBSCRIPTION: &str = "ipbl";
|
||||||
const CONFIG_RETRY: u64 = 1;
|
const CONFIG_RETRY: u64 = 2;
|
||||||
const WEB_CLIENT_TIMEOUT: i64 = 5;
|
const WEB_CLIENT_TIMEOUT: i64 = 5;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub blocklist: HashMap<String, BlockIpData>,
|
pub blocklist: HashMap<String, BlockIpData>,
|
||||||
pub cfg: Config,
|
pub cfg: Config,
|
||||||
pub discovery: Discovery,
|
pub discovery: Discovery,
|
||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
pub instance: Box<Inotify>,
|
|
||||||
pub sas: HashMap<String, SetMap>,
|
pub sas: HashMap<String, SetMap>,
|
||||||
pub hashwd: HashMap<String, WatchDescriptor>,
|
pub hashwd: HashMap<String, WatchDescriptor>,
|
||||||
}
|
}
|
||||||
@ -48,7 +47,7 @@ pub struct Flags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub async fn new() -> Self {
|
pub async fn new(inotify: &Inotify) -> Self {
|
||||||
// Get flags
|
// Get flags
|
||||||
let argp: ArgMatches = Context::argparse();
|
let argp: ArgMatches = Context::argparse();
|
||||||
let debug: bool = argp.get_one::<bool>("debug").unwrap().to_owned();
|
let debug: bool = argp.get_one::<bool>("debug").unwrap().to_owned();
|
||||||
@ -63,13 +62,12 @@ impl Context {
|
|||||||
urls: HashMap::new(),
|
urls: HashMap::new(),
|
||||||
},
|
},
|
||||||
sas: HashMap::new(),
|
sas: HashMap::new(),
|
||||||
instance: Box::new(Inotify::init(InitFlags::empty()).unwrap()),
|
|
||||||
blocklist: HashMap::new(),
|
blocklist: HashMap::new(),
|
||||||
hashwd: HashMap::new(),
|
hashwd: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
print!("Loading config ... ");
|
print!("Loading config ... ");
|
||||||
ctx.load().await.unwrap();
|
ctx.load(&inotify).await.unwrap();
|
||||||
|
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
@ -113,7 +111,7 @@ impl Context {
|
|||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn load(&mut self, inotify: &Inotify) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if cfg!(test) {
|
if cfg!(test) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -128,7 +126,7 @@ impl Context {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("error loading config: {err}, retrying in {CONFIG_RETRY} secs");
|
println!("error loading config: {err}, retrying in {CONFIG_RETRY}s");
|
||||||
last_in_err = true;
|
last_in_err = true;
|
||||||
sleep_s(CONFIG_RETRY).await;
|
sleep_s(CONFIG_RETRY).await;
|
||||||
}
|
}
|
||||||
@ -137,7 +135,7 @@ impl Context {
|
|||||||
if last_in_err {
|
if last_in_err {
|
||||||
println!("creating sas");
|
println!("creating sas");
|
||||||
}
|
}
|
||||||
self.create_sas().await?;
|
self.create_sas(&inotify).await?;
|
||||||
if last_in_err {
|
if last_in_err {
|
||||||
println!("created sas");
|
println!("created sas");
|
||||||
}
|
}
|
||||||
@ -153,9 +151,9 @@ impl Context {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_blocklist_toblock(&mut self) -> Vec<IpData> {
|
pub async fn get_blocklist_toblock(&self) -> Vec<IpData> {
|
||||||
let mut res: Vec<IpData> = vec![];
|
let mut res: Vec<IpData> = vec![];
|
||||||
for (_, block) in self.blocklist.iter_mut() {
|
for (_, block) in self.blocklist.iter() {
|
||||||
match self.cfg.sets.get(&block.ipdata.src) {
|
match self.cfg.sets.get(&block.ipdata.src) {
|
||||||
Some(set) => {
|
Some(set) => {
|
||||||
if block.tryfail >= set.tryfail {
|
if block.tryfail >= set.tryfail {
|
||||||
@ -228,15 +226,17 @@ impl Context {
|
|||||||
removed
|
removed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_sas(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
pub async fn create_sas(
|
||||||
|
&mut self,
|
||||||
|
inotify: &Inotify,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
for (src, set) in self.cfg.sets.iter() {
|
for (src, set) in self.cfg.sets.iter() {
|
||||||
let p = Path::new(set.path.as_str());
|
let p = Path::new(set.path.as_str());
|
||||||
if p.is_dir() {
|
if p.is_dir() {
|
||||||
let wd = match self.hashwd.get(&set.path.to_string()) {
|
let wd = match self.hashwd.get(&set.path.to_string()) {
|
||||||
Some(wd) => *wd,
|
Some(wd) => *wd,
|
||||||
None => {
|
None => {
|
||||||
let res = self
|
let res = inotify
|
||||||
.instance
|
|
||||||
.add_watch(set.path.as_str(), AddWatchFlags::IN_MODIFY)
|
.add_watch(set.path.as_str(), AddWatchFlags::IN_MODIFY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.hashwd.insert(set.path.to_string(), res);
|
self.hashwd.insert(set.path.to_string(), res);
|
||||||
@ -443,6 +443,26 @@ impl Config {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn _get_last(server: &String) -> Result<Vec<IpData>, ReqError> {
|
||||||
|
let resp = httpclient()
|
||||||
|
.get(format!("{server}/ips/last"))
|
||||||
|
.query(&[("interval", "3 hours")])
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let req = match resp {
|
||||||
|
Ok(re) => re,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
let data: Vec<IpData> = match req.json::<Vec<IpData>>().await {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_trustnets(&self) -> Vec<IpNet> {
|
pub fn build_trustnets(&self) -> Vec<IpNet> {
|
||||||
let mut trustnets: Vec<IpNet> = vec![];
|
let mut trustnets: Vec<IpNet> = vec![];
|
||||||
for trustnet in &self.trustnets {
|
for trustnet in &self.trustnets {
|
||||||
@ -462,6 +482,7 @@ impl Config {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: gethostname(true),
|
hostname: gethostname(true),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "".to_string(),
|
ip: "".to_string(),
|
||||||
src: "".to_string(),
|
src: "".to_string(),
|
||||||
date: "".to_string(),
|
date: "".to_string(),
|
||||||
@ -538,10 +559,12 @@ impl Hash for Set {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ip::*;
|
use crate::ip::*;
|
||||||
|
use nix::sys::inotify::InitFlags;
|
||||||
use Context;
|
use Context;
|
||||||
|
|
||||||
pub async fn prepare_test_data() -> Context {
|
pub async fn prepare_test_data() -> Context {
|
||||||
let mut ctx = Context::new().await;
|
let inotify = Inotify::init(InitFlags::empty()).unwrap();
|
||||||
|
let mut ctx = Context::new(&inotify).await;
|
||||||
let now: DateTime<Local> = Local::now().trunc_subsecs(0);
|
let now: DateTime<Local> = Local::now().trunc_subsecs(0);
|
||||||
ctx.blocklist = HashMap::new();
|
ctx.blocklist = HashMap::new();
|
||||||
|
|
||||||
@ -551,6 +574,7 @@ mod test {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: String::from("localhost"),
|
hostname: String::from("localhost"),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "1.1.1.1".to_string(),
|
ip: "1.1.1.1".to_string(),
|
||||||
hostname: "test1".to_string(),
|
hostname: "test1".to_string(),
|
||||||
date: now.to_rfc3339().to_string(),
|
date: now.to_rfc3339().to_string(),
|
||||||
@ -566,6 +590,7 @@ mod test {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: String::from("localhost"),
|
hostname: String::from("localhost"),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "1.1.1.2".to_string(),
|
ip: "1.1.1.2".to_string(),
|
||||||
hostname: "test2".to_string(),
|
hostname: "test2".to_string(),
|
||||||
date: now.to_rfc3339().to_string(),
|
date: now.to_rfc3339().to_string(),
|
||||||
@ -580,6 +605,7 @@ mod test {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: String::from("localhost"),
|
hostname: String::from("localhost"),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "1.1.1.3".to_string(),
|
ip: "1.1.1.3".to_string(),
|
||||||
hostname: "testgood".to_string(),
|
hostname: "testgood".to_string(),
|
||||||
date: now.to_rfc3339().to_string(),
|
date: now.to_rfc3339().to_string(),
|
||||||
@ -593,6 +619,7 @@ mod test {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: String::from("localhost"),
|
hostname: String::from("localhost"),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "1.1.1.4".to_string(),
|
ip: "1.1.1.4".to_string(),
|
||||||
hostname: "testgood".to_string(),
|
hostname: "testgood".to_string(),
|
||||||
date: now.to_rfc3339().to_string(),
|
date: now.to_rfc3339().to_string(),
|
||||||
@ -606,6 +633,7 @@ mod test {
|
|||||||
mode: String::from("ws"),
|
mode: String::from("ws"),
|
||||||
hostname: String::from("localhost"),
|
hostname: String::from("localhost"),
|
||||||
ipdata: IpData {
|
ipdata: IpData {
|
||||||
|
t: 4,
|
||||||
ip: "1.1.1.4".to_string(),
|
ip: "1.1.1.4".to_string(),
|
||||||
hostname: "testgood".to_string(),
|
hostname: "testgood".to_string(),
|
||||||
date: now.to_rfc3339().to_string(),
|
date: now.to_rfc3339().to_string(),
|
||||||
@ -613,11 +641,24 @@ mod test {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
ctx.update_blocklist(&mut IpEvent {
|
||||||
|
msgtype: String::from("add"),
|
||||||
|
mode: String::from("ws"),
|
||||||
|
hostname: String::from("localhost"),
|
||||||
|
ipdata: IpData {
|
||||||
|
t: 6,
|
||||||
|
ip: "2a00:1450:4007:805::2003".to_string(),
|
||||||
|
hostname: "testgood".to_string(),
|
||||||
|
date: now.to_rfc3339().to_string(),
|
||||||
|
src: "http".to_string(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
let mut ip1 = ctx.blocklist.get_mut(&"1.1.1.1".to_string()).unwrap();
|
let ip1 = ctx.blocklist.get_mut(&"1.1.1.1".to_string()).unwrap();
|
||||||
ip1.starttime = DateTime::from(now) - Duration::minutes(61);
|
ip1.starttime = DateTime::from(now) - Duration::minutes(61);
|
||||||
|
|
||||||
let mut ip2 = ctx.blocklist.get_mut(&"1.1.1.2".to_string()).unwrap();
|
let ip2 = ctx.blocklist.get_mut(&"1.1.1.2".to_string()).unwrap();
|
||||||
ip2.starttime = DateTime::from(now) - Duration::minutes(62);
|
ip2.starttime = DateTime::from(now) - Duration::minutes(62);
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
@ -627,8 +668,14 @@ mod test {
|
|||||||
let ctx = prepare_test_data().await;
|
let ctx = prepare_test_data().await;
|
||||||
|
|
||||||
let pending = ctx.get_blocklist_pending().await;
|
let pending = ctx.get_blocklist_pending().await;
|
||||||
assert_eq!(pending.len(), 4);
|
assert_eq!(pending.len(), 5);
|
||||||
let ips = ["1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4"];
|
let ips = [
|
||||||
|
"1.1.1.1",
|
||||||
|
"1.1.1.2",
|
||||||
|
"1.1.1.3",
|
||||||
|
"1.1.1.4",
|
||||||
|
"2a00:1450:4007:805::2003",
|
||||||
|
];
|
||||||
for i in ips {
|
for i in ips {
|
||||||
let ip = ctx
|
let ip = ctx
|
||||||
.blocklist
|
.blocklist
|
||||||
@ -646,7 +693,7 @@ mod test {
|
|||||||
let mut ctx = prepare_test_data().await;
|
let mut ctx = prepare_test_data().await;
|
||||||
ctx.gc_blocklist().await;
|
ctx.gc_blocklist().await;
|
||||||
let toblock = ctx.get_blocklist_toblock().await;
|
let toblock = ctx.get_blocklist_toblock().await;
|
||||||
assert_eq!(toblock.len(), 2);
|
assert_eq!(toblock.len(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
142
src/fw.rs
142
src/fw.rs
@ -2,13 +2,44 @@ use crate::ip::IpData;
|
|||||||
use crate::ipblc::PKG_NAME;
|
use crate::ipblc::PKG_NAME;
|
||||||
|
|
||||||
use nftnl::{nft_expr, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table};
|
use nftnl::{nft_expr, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table};
|
||||||
use std::{ffi::CString, io::Error, net::Ipv4Addr};
|
use std::{
|
||||||
|
ffi::CString,
|
||||||
|
io::Error,
|
||||||
|
net::{Ipv4Addr, Ipv6Addr},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn fwinit() -> (Batch, Table) {
|
pub enum FwTableType {
|
||||||
|
IPv4,
|
||||||
|
IPv6,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fwglobalinit<'a>() -> ((Batch, Table), (Batch, Table)) {
|
||||||
|
let (batch4, table4) = fwinit(FwTableType::IPv4);
|
||||||
|
let (batch6, table6) = fwinit(FwTableType::IPv6);
|
||||||
|
((batch4, table4), (batch6, table6))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fwinit(t: FwTableType) -> (Batch, Table) {
|
||||||
|
let table_name: String;
|
||||||
|
let table: Table;
|
||||||
|
match t {
|
||||||
|
FwTableType::IPv4 => {
|
||||||
|
table_name = format!("{PKG_NAME}4");
|
||||||
|
table = Table::new(
|
||||||
|
&CString::new(format!("{table_name}")).unwrap(),
|
||||||
|
ProtoFamily::Ipv4,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
FwTableType::IPv6 => {
|
||||||
|
table_name = format!("{PKG_NAME}6");
|
||||||
|
table = Table::new(
|
||||||
|
&CString::new(format!("{table_name}")).unwrap(),
|
||||||
|
ProtoFamily::Ipv6,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut batch = Batch::new();
|
let mut batch = Batch::new();
|
||||||
|
|
||||||
let table = Table::new(&CString::new(PKG_NAME).unwrap(), ProtoFamily::Ipv4);
|
|
||||||
|
|
||||||
batch.add(&table, nftnl::MsgType::Add);
|
batch.add(&table, nftnl::MsgType::Add);
|
||||||
batch.add(&table, nftnl::MsgType::Del);
|
batch.add(&table, nftnl::MsgType::Del);
|
||||||
|
|
||||||
@ -21,45 +52,82 @@ pub fn fwblock(
|
|||||||
ret: &mut Vec<String>,
|
ret: &mut Vec<String>,
|
||||||
fwlen: &mut usize,
|
fwlen: &mut usize,
|
||||||
) -> std::result::Result<(), Error> {
|
) -> std::result::Result<(), Error> {
|
||||||
// convert chain
|
let ((mut batch4, table4), (mut batch6, table6)) = fwglobalinit();
|
||||||
let ips_add = convert(ips_add);
|
|
||||||
let (mut batch, table) = fwinit();
|
|
||||||
|
|
||||||
// build chain
|
// build chain for ipv4
|
||||||
let mut chain = Chain::new(&CString::new(PKG_NAME).unwrap(), &table);
|
let mut chain4 = Chain::new(&CString::new(PKG_NAME).unwrap(), &table4);
|
||||||
chain.set_hook(nftnl::Hook::In, 1);
|
chain4.set_hook(nftnl::Hook::In, 1);
|
||||||
chain.set_policy(nftnl::Policy::Accept);
|
chain4.set_policy(nftnl::Policy::Accept);
|
||||||
|
|
||||||
// add chain
|
// add chain
|
||||||
batch.add(&chain, nftnl::MsgType::Add);
|
batch4.add(&chain4, nftnl::MsgType::Add);
|
||||||
|
|
||||||
let rule = Rule::new(&chain);
|
batch4.add(&Rule::new(&chain4), nftnl::MsgType::Del);
|
||||||
batch.add(&rule, nftnl::MsgType::Del);
|
|
||||||
|
|
||||||
let mut rule = Rule::new(&chain);
|
let mut rule4 = Rule::new(&chain4);
|
||||||
rule.add_expr(&nft_expr!(ct state));
|
rule4.add_expr(&nft_expr!(ct state));
|
||||||
rule.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32));
|
rule4.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32));
|
||||||
rule.add_expr(&nft_expr!(cmp != 0u32));
|
rule4.add_expr(&nft_expr!(cmp != 0u32));
|
||||||
rule.add_expr(&nft_expr!(counter));
|
rule4.add_expr(&nft_expr!(counter));
|
||||||
rule.add_expr(&nft_expr!(verdict accept));
|
rule4.add_expr(&nft_expr!(verdict accept));
|
||||||
batch.add(&rule, nftnl::MsgType::Add);
|
batch4.add(&rule4, nftnl::MsgType::Add);
|
||||||
|
|
||||||
|
// build chain for ipv6
|
||||||
|
let mut chain6 = Chain::new(&CString::new(PKG_NAME).unwrap(), &table6);
|
||||||
|
chain6.set_hook(nftnl::Hook::In, 1);
|
||||||
|
chain6.set_policy(nftnl::Policy::Accept);
|
||||||
|
|
||||||
|
// add chain
|
||||||
|
batch6.add(&chain6, nftnl::MsgType::Add);
|
||||||
|
|
||||||
|
batch6.add(&Rule::new(&chain6), nftnl::MsgType::Del);
|
||||||
|
|
||||||
|
let mut rule6 = Rule::new(&chain6);
|
||||||
|
rule6.add_expr(&nft_expr!(ct state));
|
||||||
|
rule6.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32));
|
||||||
|
rule6.add_expr(&nft_expr!(cmp != 0u32));
|
||||||
|
rule6.add_expr(&nft_expr!(counter));
|
||||||
|
rule6.add_expr(&nft_expr!(verdict accept));
|
||||||
|
batch6.add(&rule6, nftnl::MsgType::Add);
|
||||||
|
|
||||||
// build and add rules
|
// build and add rules
|
||||||
for ip in ips_add.clone() {
|
for ipdata in ips_add.clone() {
|
||||||
let mut rule = Rule::new(&chain);
|
match ipdata.t {
|
||||||
rule.add_expr(&nft_expr!(payload ipv4 saddr));
|
4 => {
|
||||||
rule.add_expr(&nft_expr!(cmp == ip));
|
let ip = ipdata.ip.parse::<Ipv4Addr>().unwrap();
|
||||||
rule.add_expr(&nft_expr!(ct state));
|
let mut rule = Rule::new(&chain4);
|
||||||
rule.add_expr(&nft_expr!(bitwise mask 10u32, xor 0u32));
|
rule.add_expr(&nft_expr!(payload ipv4 saddr));
|
||||||
rule.add_expr(&nft_expr!(cmp != 0u32));
|
rule.add_expr(&nft_expr!(cmp == ip));
|
||||||
rule.add_expr(&nft_expr!(counter));
|
rule.add_expr(&nft_expr!(ct state));
|
||||||
rule.add_expr(&nft_expr!(verdict drop));
|
rule.add_expr(&nft_expr!(bitwise mask 10u32, xor 0u32));
|
||||||
batch.add(&rule, nftnl::MsgType::Add);
|
rule.add_expr(&nft_expr!(cmp != 0u32));
|
||||||
|
rule.add_expr(&nft_expr!(counter));
|
||||||
|
rule.add_expr(&nft_expr!(verdict drop));
|
||||||
|
batch4.add(&rule, nftnl::MsgType::Add);
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
let ip = ipdata.ip.parse::<Ipv6Addr>().unwrap();
|
||||||
|
let mut rule = Rule::new(&chain6);
|
||||||
|
rule.add_expr(&nft_expr!(payload ipv6 saddr));
|
||||||
|
rule.add_expr(&nft_expr!(cmp == ip));
|
||||||
|
rule.add_expr(&nft_expr!(ct state));
|
||||||
|
rule.add_expr(&nft_expr!(bitwise mask 10u32, xor 0u32));
|
||||||
|
rule.add_expr(&nft_expr!(cmp != 0u32));
|
||||||
|
rule.add_expr(&nft_expr!(counter));
|
||||||
|
rule.add_expr(&nft_expr!(verdict drop));
|
||||||
|
batch6.add(&rule, nftnl::MsgType::Add);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate and send batch
|
// validate and send batch
|
||||||
let finalized_batch = batch.finalize();
|
for b in [batch4, batch6] {
|
||||||
send_and_process(&finalized_batch)?;
|
let bf = b.finalize();
|
||||||
|
send_and_process(&bf).unwrap();
|
||||||
|
}
|
||||||
if fwlen != &mut ips_add.len() {
|
if fwlen != &mut ips_add.len() {
|
||||||
ret.push(format!("{length} ip in firewall", length = ips_add.len()));
|
ret.push(format!("{length} ip in firewall", length = ips_add.len()));
|
||||||
}
|
}
|
||||||
@ -94,11 +162,3 @@ fn socket_recv<'a>(
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert(input: &Vec<IpData>) -> Vec<Ipv4Addr> {
|
|
||||||
let mut output: Vec<Ipv4Addr> = vec![];
|
|
||||||
for val in input {
|
|
||||||
output.push(val.ip.parse::<Ipv4Addr>().unwrap());
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
85
src/ip.rs
85
src/ip.rs
@ -1,4 +1,3 @@
|
|||||||
use crate::config::httpclient;
|
|
||||||
use crate::utils::gethostname;
|
use crate::utils::gethostname;
|
||||||
|
|
||||||
use chrono::offset::LocalResult;
|
use chrono::offset::LocalResult;
|
||||||
@ -6,7 +5,6 @@ use chrono::prelude::*;
|
|||||||
use ipnet::IpNet;
|
use ipnet::IpNet;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::Error as ReqError;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -27,12 +25,16 @@ pub struct IpEvent {
|
|||||||
pub ipdata: IpData,
|
pub ipdata: IpData,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq)]
|
#[macro_export]
|
||||||
pub struct IpData {
|
macro_rules! ipevent {
|
||||||
pub ip: String,
|
($msgtype:expr,$mode:expr,$hostname:expr,$ipdata:expr) => {
|
||||||
pub src: String,
|
IpEvent {
|
||||||
pub date: String,
|
msgtype: String::from($msgtype),
|
||||||
pub hostname: String,
|
mode: String::from($mode),
|
||||||
|
hostname: $hostname,
|
||||||
|
ipdata: $ipdata,
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@ -43,6 +45,15 @@ pub struct BlockIpData {
|
|||||||
pub starttime: DateTime<Local>,
|
pub starttime: DateTime<Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq)]
|
||||||
|
pub struct IpData {
|
||||||
|
pub t: isize,
|
||||||
|
pub ip: String,
|
||||||
|
pub src: String,
|
||||||
|
pub date: String,
|
||||||
|
pub hostname: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for IpData {
|
impl PartialEq for IpData {
|
||||||
fn eq(&self, other: &IpData) -> bool {
|
fn eq(&self, other: &IpData) -> bool {
|
||||||
self.ip.as_bytes() == other.ip.as_bytes() && self.src == other.src
|
self.ip.as_bytes() == other.ip.as_bytes() && self.src == other.src
|
||||||
@ -91,15 +102,18 @@ pub fn filter(
|
|||||||
if let Ok(l) = line {
|
if let Ok(l) = line {
|
||||||
if regex.is_match(l.as_str()) {
|
if regex.is_match(l.as_str()) {
|
||||||
let s_ipaddr: String;
|
let s_ipaddr: String;
|
||||||
|
let t: isize;
|
||||||
|
|
||||||
match R_IPV4.captures(l.as_str()) {
|
match R_IPV4.captures(l.as_str()) {
|
||||||
Some(sv4) => {
|
Some(sv4) => {
|
||||||
s_ipaddr = sv4.get(0).unwrap().as_str().to_string();
|
s_ipaddr = sv4.get(0).unwrap().as_str().to_string();
|
||||||
|
t = 4;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
match R_IPV6.captures(l.as_str()) {
|
match R_IPV6.captures(l.as_str()) {
|
||||||
Some(sv6) => {
|
Some(sv6) => {
|
||||||
s_ipaddr = sv6.get(0).unwrap().as_str().to_string();
|
s_ipaddr = sv6.get(0).unwrap().as_str().to_string();
|
||||||
|
t = 6;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
continue;
|
continue;
|
||||||
@ -132,6 +146,7 @@ pub fn filter(
|
|||||||
if !is_trusted(&ipaddr, &trustnets) {
|
if !is_trusted(&ipaddr, &trustnets) {
|
||||||
iplist.push(IpData {
|
iplist.push(IpData {
|
||||||
ip: s_ipaddr,
|
ip: s_ipaddr,
|
||||||
|
t: t,
|
||||||
src: src.to_owned(),
|
src: src.to_owned(),
|
||||||
date: s_date.to_rfc3339().to_owned(),
|
date: s_date.to_rfc3339().to_owned(),
|
||||||
hostname: hostname.to_owned(),
|
hostname: hostname.to_owned(),
|
||||||
@ -145,30 +160,24 @@ pub fn filter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_date(input: regex::Captures) -> DateTime<Local> {
|
fn parse_date(input: regex::Captures) -> DateTime<Local> {
|
||||||
let mut ymd: Vec<u64> = vec![];
|
let mut ymd: Vec<u32> = vec![];
|
||||||
let mut hms: Vec<u64> = vec![];
|
let mut hms: Vec<u32> = vec![];
|
||||||
|
let ymd_range = 2..5;
|
||||||
|
let hms_range = 5..8;
|
||||||
|
|
||||||
let (daterange, hourrange) = (2..5, 5..8);
|
for cap in ymd_range {
|
||||||
|
ymd.push(input.get(cap).unwrap().as_str().parse::<u32>().unwrap());
|
||||||
for i in daterange {
|
|
||||||
ymd.push(input.get(i).unwrap().as_str().parse::<u64>().unwrap());
|
|
||||||
}
|
}
|
||||||
for i in hourrange {
|
for cap in hms_range {
|
||||||
hms.push(input.get(i).unwrap().as_str().parse::<u64>().unwrap());
|
hms.push(input.get(cap).unwrap().as_str().parse::<u32>().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let date: DateTime<Local> = match Local.with_ymd_and_hms(
|
let date: DateTime<Local> =
|
||||||
ymd[0] as i32,
|
match Local.with_ymd_and_hms(ymd[0] as i32, ymd[1], ymd[2], hms[0], hms[1], hms[2]) {
|
||||||
ymd[1] as u32,
|
LocalResult::Single(s) => s,
|
||||||
ymd[2] as u32,
|
LocalResult::Ambiguous(a, _b) => a,
|
||||||
hms[0] as u32,
|
LocalResult::None => Local::now().trunc_subsecs(0),
|
||||||
hms[1] as u32,
|
};
|
||||||
hms[2] as u32,
|
|
||||||
) {
|
|
||||||
LocalResult::Single(s) => s,
|
|
||||||
LocalResult::Ambiguous(a, _b) => a,
|
|
||||||
LocalResult::None => Local::now(),
|
|
||||||
};
|
|
||||||
date
|
date
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,23 +189,3 @@ fn is_trusted(ip: &IpAddr, trustnets: &Vec<IpNet>) -> bool {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn _get_last(server: &String) -> Result<Vec<IpData>, ReqError> {
|
|
||||||
let resp = httpclient()
|
|
||||||
.get(format!("{server}/ips/last"))
|
|
||||||
.query(&[("interval", "3 hours")])
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let req = match resp {
|
|
||||||
Ok(re) => re,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
|
|
||||||
let data: Vec<IpData> = match req.json::<Vec<IpData>>().await {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
|
73
src/ipblc.rs
73
src/ipblc.rs
@ -1,6 +1,7 @@
|
|||||||
use crate::config::{Context, GIT_VERSION};
|
use crate::config::{Context, GIT_VERSION};
|
||||||
use crate::fw::{fwblock, fwinit};
|
use crate::fw::{fwblock, fwglobalinit};
|
||||||
use crate::ip::{filter, IpData, IpEvent};
|
use crate::ip::{filter, IpData, IpEvent};
|
||||||
|
use crate::ipevent;
|
||||||
use crate::monitoring::apiserver;
|
use crate::monitoring::apiserver;
|
||||||
use crate::utils::{gethostname, read_lines, sleep_s};
|
use crate::utils::{gethostname, read_lines, sleep_s};
|
||||||
use crate::webservice::send_to_ipbl_api;
|
use crate::webservice::send_to_ipbl_api;
|
||||||
@ -9,7 +10,7 @@ use crate::websocket::{send_to_ipbl_websocket, websocketpubsub, websocketreqrep}
|
|||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use chrono::prelude::{DateTime, Local};
|
use chrono::prelude::{DateTime, Local};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use nix::sys::inotify::InotifyEvent;
|
use nix::sys::inotify::{InitFlags, Inotify, InotifyEvent};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||||
@ -21,15 +22,17 @@ const WS_CHAN_SIZE: usize = 64;
|
|||||||
const LOOP_MAX_WAIT: u64 = 5;
|
const LOOP_MAX_WAIT: u64 = 5;
|
||||||
|
|
||||||
pub async fn run() {
|
pub async fn run() {
|
||||||
let globalctx = Context::new().await;
|
let inotify = Inotify::init(InitFlags::empty()).unwrap();
|
||||||
|
let globalctx = Context::new(&inotify).await;
|
||||||
let ctxarc = Arc::new(RwLock::new(globalctx));
|
let ctxarc = Arc::new(RwLock::new(globalctx));
|
||||||
|
|
||||||
let mut fwlen: usize = 0;
|
let mut fwlen: usize = 0;
|
||||||
|
|
||||||
let pkgversion = format!("{}@{}", env!("CARGO_PKG_VERSION"), GIT_VERSION);
|
let pkgversion = format!("{}@{}", env!("CARGO_PKG_VERSION"), GIT_VERSION);
|
||||||
|
|
||||||
let mut last_cfg_reload: DateTime<Local> = Local::now().trunc_subsecs(0);
|
let mut last_cfg_reload: DateTime<Local> = Local::now().trunc_subsecs(0);
|
||||||
println!("Launching {}, version {}", PKG_NAME, pkgversion);
|
println!("Launching {}, version {}", PKG_NAME, pkgversion);
|
||||||
fwinit();
|
fwglobalinit();
|
||||||
|
|
||||||
let ctxapi = Arc::clone(&ctxarc);
|
let ctxapi = Arc::clone(&ctxarc);
|
||||||
apiserver(&ctxapi).await.unwrap();
|
apiserver(&ctxapi).await.unwrap();
|
||||||
@ -47,7 +50,9 @@ pub async fn run() {
|
|||||||
let mut wssocketrr = websocketreqrep(&ctxwsrr).await;
|
let mut wssocketrr = websocketreqrep(&ctxwsrr).await;
|
||||||
|
|
||||||
// init file watcher
|
// init file watcher
|
||||||
let mut blrx = watchfiles(&ctxarc).await;
|
let inoarc = Arc::new(RwLock::new(inotify));
|
||||||
|
let inoclone = Arc::clone(&inoarc);
|
||||||
|
let mut blrx = watchfiles(inoclone).await;
|
||||||
|
|
||||||
let ctxclone = Arc::clone(&ctxarc);
|
let ctxclone = Arc::clone(&ctxarc);
|
||||||
let ipeventclone = Arc::clone(&ipeventtxarc);
|
let ipeventclone = Arc::clone(&ipeventtxarc);
|
||||||
@ -66,19 +71,14 @@ pub async fn run() {
|
|||||||
|
|
||||||
let (toblock,server);
|
let (toblock,server);
|
||||||
{
|
{
|
||||||
let mut ctx = ctxclone.write().await;
|
let ctx = ctxclone.read().await;
|
||||||
toblock = ctx.get_blocklist_toblock().await;
|
toblock = ctx.get_blocklist_toblock().await;
|
||||||
server = ctx.flags.server.clone();
|
server = ctx.flags.server.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
if received_ip.msgtype == "bootstrap".to_string() {
|
if received_ip.msgtype == "bootstrap".to_string() {
|
||||||
for ip_to_send in toblock {
|
for ip_to_send in toblock {
|
||||||
let ipe = IpEvent{
|
let ipe = ipevent!("init","ws",gethostname(true),ip_to_send);
|
||||||
msgtype: String::from("init"),
|
|
||||||
mode: String::from("ws"),
|
|
||||||
hostname: gethostname(true),
|
|
||||||
ipdata: ip_to_send,
|
|
||||||
};
|
|
||||||
if !send_to_ipbl_websocket(&mut wssocketrr, &ipe).await {
|
if !send_to_ipbl_websocket(&mut wssocketrr, &ipe).await {
|
||||||
wssocketrr = websocketreqrep(&ctxwsrr).await;
|
wssocketrr = websocketreqrep(&ctxwsrr).await;
|
||||||
break;
|
break;
|
||||||
@ -98,12 +98,7 @@ pub async fn run() {
|
|||||||
if let Some(ipevent) = filtered_ipevent {
|
if let Some(ipevent) = filtered_ipevent {
|
||||||
if received_ip.msgtype != "init" {
|
if received_ip.msgtype != "init" {
|
||||||
println!("sending {} to api and ws", ipevent.ipdata.ip);
|
println!("sending {} to api and ws", ipevent.ipdata.ip);
|
||||||
let ipe = IpEvent{
|
let ipe = ipevent!("add","ws",gethostname(true),ipevent.ipdata);
|
||||||
msgtype: String::from("add"),
|
|
||||||
mode: String::from("ws"),
|
|
||||||
hostname: gethostname(true),
|
|
||||||
ipdata: ipevent.ipdata,
|
|
||||||
};
|
|
||||||
send_to_ipbl_api(&server.clone(), &ipe).await;
|
send_to_ipbl_api(&server.clone(), &ipe).await;
|
||||||
let status = send_to_ipbl_websocket(&mut wssocketrr, &ipe).await;
|
let status = send_to_ipbl_websocket(&mut wssocketrr, &ipe).await;
|
||||||
if !status {
|
if !status {
|
||||||
@ -125,15 +120,21 @@ pub async fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ctxclone = Arc::clone(&ctxarc);
|
let ctxclone = Arc::clone(&ctxarc);
|
||||||
handle_cfg_reload(&ctxclone, &mut last_cfg_reload).await;
|
let inoclone = Arc::clone(&inoarc);
|
||||||
|
handle_cfg_reload(&ctxclone, &mut last_cfg_reload, inoclone).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_cfg_reload(ctxclone: &Arc<RwLock<Context>>, last_cfg_reload: &mut DateTime<Local>) {
|
async fn handle_cfg_reload(
|
||||||
|
ctxclone: &Arc<RwLock<Context>>,
|
||||||
|
last_cfg_reload: &mut DateTime<Local>,
|
||||||
|
inoarc: Arc<RwLock<Inotify>>,
|
||||||
|
) {
|
||||||
let now_cfg_reload = Local::now().trunc_subsecs(0);
|
let now_cfg_reload = Local::now().trunc_subsecs(0);
|
||||||
if (now_cfg_reload - *last_cfg_reload) > Duration::seconds(LOOP_MAX_WAIT as i64) {
|
if (now_cfg_reload - *last_cfg_reload) > Duration::seconds(LOOP_MAX_WAIT as i64) {
|
||||||
let mut ctx = ctxclone.write().await;
|
let mut ctx = ctxclone.write().await;
|
||||||
match ctx.load().await {
|
let inotify = inoarc.read().await;
|
||||||
|
match ctx.load(&inotify).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
*last_cfg_reload = Local::now().trunc_subsecs(0);
|
*last_cfg_reload = Local::now().trunc_subsecs(0);
|
||||||
}
|
}
|
||||||
@ -145,9 +146,12 @@ async fn handle_cfg_reload(ctxclone: &Arc<RwLock<Context>>, last_cfg_reload: &mu
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_fwblock(ctxclone: Arc<RwLock<Context>>, ret: &mut Vec<String>, fwlen: &mut usize) {
|
async fn handle_fwblock(ctxclone: Arc<RwLock<Context>>, ret: &mut Vec<String>, fwlen: &mut usize) {
|
||||||
let toblock = {
|
{
|
||||||
let mut ctx = ctxclone.write().await;
|
let mut ctx = ctxclone.write().await;
|
||||||
ctx.gc_blocklist().await;
|
ctx.gc_blocklist().await;
|
||||||
|
}
|
||||||
|
let toblock = {
|
||||||
|
let ctx = ctxclone.read().await;
|
||||||
ctx.get_blocklist_toblock().await
|
ctx.get_blocklist_toblock().await
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -160,19 +164,11 @@ async fn handle_fwblock(ctxclone: Arc<RwLock<Context>>, ret: &mut Vec<String>, f
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn watchfiles(ctxarc: &Arc<RwLock<Context>>) -> Receiver<FileEvent> {
|
async fn watchfiles(inoarc: Arc<RwLock<Inotify>>) -> Receiver<FileEvent> {
|
||||||
let (bltx, blrx): (Sender<FileEvent>, Receiver<FileEvent>) = channel(BL_CHAN_SIZE);
|
let (bltx, blrx): (Sender<FileEvent>, Receiver<FileEvent>) = channel(BL_CHAN_SIZE);
|
||||||
let ctxclone = Arc::clone(ctxarc);
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let events;
|
let events = inoarc.read().await.read_events().unwrap();
|
||||||
let instance;
|
|
||||||
{
|
|
||||||
let ctx = ctxclone.read().await;
|
|
||||||
instance = ctx.instance.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
events = instance.read_events().unwrap();
|
|
||||||
|
|
||||||
for inevent in events {
|
for inevent in events {
|
||||||
let date: DateTime<Local> = Local::now().trunc_subsecs(0);
|
let date: DateTime<Local> = Local::now().trunc_subsecs(0);
|
||||||
@ -209,7 +205,7 @@ async fn compare_files_changes(
|
|||||||
let sas;
|
let sas;
|
||||||
{
|
{
|
||||||
let ctx = ctxarc.read().await;
|
let ctx = ctxarc.read().await;
|
||||||
sas = ctx.clone().sas;
|
sas = ctx.sas.clone();
|
||||||
sask = sas.keys();
|
sask = sas.keys();
|
||||||
tnets = ctx.cfg.build_trustnets();
|
tnets = ctx.cfg.build_trustnets();
|
||||||
}
|
}
|
||||||
@ -258,14 +254,9 @@ async fn compare_files_changes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ip in iplist {
|
for ip in iplist {
|
||||||
let ipevent = IpEvent {
|
let ipe = ipevent!("add", "file", gethostname(true), ip);
|
||||||
msgtype: String::from("add"),
|
let ipetx = ipeventtx.read().await;
|
||||||
hostname: gethostname(true),
|
ipetx.send(ipe).await.unwrap();
|
||||||
mode: String::from("file"),
|
|
||||||
ipdata: ip,
|
|
||||||
};
|
|
||||||
let ipetx = ipeventtx.write().await;
|
|
||||||
ipetx.send(ipevent).await.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -22,7 +22,6 @@ pub async fn apiserver(ctxarc: &Arc<RwLock<Context>>) -> io::Result<()> {
|
|||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
//apitx.send(String::from("")).await.unwrap();
|
|
||||||
match listener.accept().await {
|
match listener.accept().await {
|
||||||
Ok((stream, _addr)) => {
|
Ok((stream, _addr)) => {
|
||||||
//let mut buf = [0; 1024];
|
//let mut buf = [0; 1024];
|
||||||
|
@ -1 +1 @@
|
|||||||
((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))
|
(((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*)|(((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?)
|
@ -31,6 +31,7 @@ async fn push_ip(client: &Client, server: &str, ip: &IpData) -> Result<(), ReqEr
|
|||||||
let mut data: Vec<IpData> = vec![];
|
let mut data: Vec<IpData> = vec![];
|
||||||
|
|
||||||
data.push(IpData {
|
data.push(IpData {
|
||||||
|
t: ip.t,
|
||||||
ip: ip.ip.to_string(),
|
ip: ip.ip.to_string(),
|
||||||
src: ip.src.to_string(),
|
src: ip.src.to_string(),
|
||||||
date: ip.date.to_string(),
|
date: ip.date.to_string(),
|
||||||
@ -56,6 +57,7 @@ async fn _push_ip_bulk(
|
|||||||
|
|
||||||
for ip in ips {
|
for ip in ips {
|
||||||
data.push(IpData {
|
data.push(IpData {
|
||||||
|
t: ip.t,
|
||||||
ip: ip.ip.to_string(),
|
ip: ip.ip.to_string(),
|
||||||
src: ip.src.to_string(),
|
src: ip.src.to_string(),
|
||||||
date: ip.date.to_string(),
|
date: ip.date.to_string(),
|
||||||
|
@ -41,7 +41,7 @@ pub async fn websocketpubsub(
|
|||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let mut ws = websocket.write().await;
|
let mut ws = websocket.write().await;
|
||||||
match ws.read_message() {
|
match ws.read() {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
let tosend: IpEvent = match serde_json::from_str(msg.to_string().as_str()) {
|
let tosend: IpEvent = match serde_json::from_str(msg.to_string().as_str()) {
|
||||||
Ok(o) => o,
|
Ok(o) => o,
|
||||||
@ -52,7 +52,7 @@ pub async fn websocketpubsub(
|
|||||||
if tosend.ipdata.hostname != gethostname(true)
|
if tosend.ipdata.hostname != gethostname(true)
|
||||||
|| tosend.msgtype == "init".to_string()
|
|| tosend.msgtype == "init".to_string()
|
||||||
{
|
{
|
||||||
let txps = txpubsub.write().await;
|
let txps = txpubsub.read().await;
|
||||||
txps.send(tosend).await.unwrap();
|
txps.send(tosend).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,9 +90,7 @@ pub async fn websocketconnect<'a>(
|
|||||||
}
|
}
|
||||||
println!("connected to {endpoint}");
|
println!("connected to {endpoint}");
|
||||||
let msg = json!({ "hostname": hostname });
|
let msg = json!({ "hostname": hostname });
|
||||||
socket
|
socket.send(Message::Text(msg.to_string())).unwrap();
|
||||||
.write_message(Message::Text(msg.to_string()))
|
|
||||||
.unwrap();
|
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +101,7 @@ pub async fn send_to_ipbl_websocket(
|
|||||||
let msg = format!("{val}", val = serde_json::to_string(&ip).unwrap());
|
let msg = format!("{val}", val = serde_json::to_string(&ip).unwrap());
|
||||||
|
|
||||||
if ws.can_write() {
|
if ws.can_write() {
|
||||||
match ws.write_message(Message::Text(msg)) {
|
match ws.send(Message::Text(msg)) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("err send read: {e:?}");
|
println!("err send read: {e:?}");
|
||||||
@ -115,7 +113,7 @@ pub async fn send_to_ipbl_websocket(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ws.can_read() {
|
if ws.can_read() {
|
||||||
match ws.read_message() {
|
match ws.read() {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("err send read: {e:?}");
|
println!("err send read: {e:?}");
|
||||||
|
Loading…
Reference in New Issue
Block a user