Merge pull request 'update to 1.6.0' (#8) from develop into master
Reviewed-on: #8
This commit is contained in:
commit
b50a2d44d7
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -358,9 +358,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -428,9 +428,9 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||
checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@ -543,7 +543,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ipblc"
|
||||
version = "1.5.0"
|
||||
version = "1.6.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
@ -590,9 +590,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -992,9 +992,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
@ -1071,22 +1071,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.190"
|
||||
version = "1.0.192"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.190"
|
||||
version = "1.0.192"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1143,9 +1143,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@ -1192,9 +1192,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.38"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1251,7 +1251,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1271,9 +1271,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.33.0"
|
||||
version = "1.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
|
||||
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@ -1290,13 +1290,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1479,7 +1479,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.39",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -1513,7 +1513,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"syn 2.0.39",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ipblc"
|
||||
version = "1.5.0"
|
||||
version = "1.6.0"
|
||||
edition = "2021"
|
||||
authors = ["PaulBSD <paul@paulbsd.com>"]
|
||||
description = "ipblc is a tool that search and send attacking ip addresses to ipbl"
|
||||
@ -21,7 +21,7 @@ regex = "1.10"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.33", features = ["full", "sync"] }
|
||||
tokio = { version = "1.34", features = ["full", "sync"] }
|
||||
tungstenite = { version = "0.20", features = ["handshake", "rustls-tls-native-roots"] }
|
||||
|
||||
## to optimize binary size (slow compile time)
|
||||
|
@ -48,6 +48,7 @@ Options:
|
||||
- ✅ Local bound tcp api socket
|
||||
- ✅ ZMQ -> Websocket
|
||||
- ✅ Bug in RwLocks (agent often give up)
|
||||
- ❌ Create memory friendly structs for ipdata
|
||||
|
||||
|
||||
### Notes
|
||||
|
118
src/config.rs
118
src/config.rs
@ -28,6 +28,7 @@ pub struct Context {
|
||||
pub flags: Flags,
|
||||
pub sas: HashMap<String, SetMap>,
|
||||
pub hashwd: HashMap<String, WatchDescriptor>,
|
||||
pub reloadinterval: isize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -35,7 +36,7 @@ pub struct SetMap {
|
||||
pub filename: String,
|
||||
pub fullpath: String,
|
||||
pub regex: Regex,
|
||||
pub set: Set,
|
||||
pub set: SetCfg,
|
||||
pub watchedfiles: HashMap<String, u64>,
|
||||
pub wd: WatchDescriptor,
|
||||
}
|
||||
@ -64,6 +65,7 @@ impl Context {
|
||||
sas: HashMap::new(),
|
||||
blocklist: HashMap::new(),
|
||||
hashwd: HashMap::new(),
|
||||
reloadinterval: 5,
|
||||
};
|
||||
|
||||
print!("Loading config ... ");
|
||||
@ -282,7 +284,7 @@ impl Context {
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Config {
|
||||
pub sets: HashMap<String, Set>,
|
||||
pub sets: HashMap<String, SetCfg>,
|
||||
#[serde(skip_serializing)]
|
||||
pub trustnets: Vec<String>,
|
||||
pub ws: HashMap<String, WebSocketCfg>,
|
||||
@ -294,7 +296,7 @@ impl Config {
|
||||
Self {
|
||||
sets: HashMap::from([
|
||||
("smtp".to_string(),
|
||||
Set {
|
||||
SetCfg {
|
||||
src: "smtp".to_string(),
|
||||
filename: "mail.log".to_string(),
|
||||
regex: "(SASL LOGIN authentication failed)".to_string(),
|
||||
@ -303,7 +305,7 @@ impl Config {
|
||||
tryfail: 5,
|
||||
}),
|
||||
("ssh".to_string(),
|
||||
Set {
|
||||
SetCfg {
|
||||
src: "ssh".to_string(),
|
||||
filename: "auth.log".to_string(),
|
||||
regex: "(Invalid user|BREAK|not allowed because|no matching key exchange method found)".to_string(),
|
||||
@ -312,7 +314,7 @@ impl Config {
|
||||
tryfail: 5,
|
||||
},),
|
||||
("http".to_string(),
|
||||
Set {
|
||||
SetCfg {
|
||||
src: "http".to_string(),
|
||||
filename: "".to_string(),
|
||||
regex: "(anonymousfox.co)".to_string(),
|
||||
@ -321,7 +323,7 @@ impl Config {
|
||||
tryfail: 5,
|
||||
},),
|
||||
("openvpn".to_string(),
|
||||
Set {
|
||||
SetCfg {
|
||||
src: "openvpn".to_string(),
|
||||
filename: "status".to_string(),
|
||||
regex: "(UNDEF)".to_string(),
|
||||
@ -350,96 +352,40 @@ impl Config {
|
||||
}
|
||||
|
||||
pub async fn load(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
self.get_global_config(server).await?;
|
||||
self.get_trustnets(server).await?;
|
||||
self.get_sets(server).await?;
|
||||
self.get_ws_config(server).await?;
|
||||
self.get_config(server).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_global_config(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
let resp: Result<Response, ReqError> =
|
||||
httpclient().get(format!("{server}/config")).send().await;
|
||||
let req = match resp {
|
||||
Ok(re) => re,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let data: HashMap<String, GlobalConfig> = match req.json::<Vec<GlobalConfig>>().await {
|
||||
Ok(res) => {
|
||||
let mut out: HashMap<String, GlobalConfig> = HashMap::new();
|
||||
res.into_iter().map(|x| x).for_each(|x| {
|
||||
out.insert(x.key.to_string(), x);
|
||||
});
|
||||
out
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let key = "".to_string();
|
||||
self.api = data
|
||||
.get(&key.to_string())
|
||||
.unwrap_or(&GlobalConfig {
|
||||
key: "api".to_string(),
|
||||
value: "127.0.0.1:8060".to_string(),
|
||||
})
|
||||
.value
|
||||
.clone();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_trustnets(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
async fn get_config(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
let resp: Result<Response, ReqError> = httpclient()
|
||||
.get(format!("{server}/config/trustlist"))
|
||||
.get(format!("{server}/config?v=2"))
|
||||
.send()
|
||||
.await;
|
||||
let req = match resp {
|
||||
Ok(re) => re,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let data: Vec<String> = match req.json::<Vec<String>>().await {
|
||||
let data: GlobalConfigV2 = match req.json::<GlobalConfigV2>().await {
|
||||
Ok(res) => res,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
self.trustnets = data;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_sets(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
let resp: Result<Response, ReqError> = httpclient()
|
||||
.get(format!("{server}/config/sets"))
|
||||
.send()
|
||||
.await;
|
||||
let req = match resp {
|
||||
Ok(re) => re,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let data: Vec<Set> = match req.json::<Vec<Set>>().await {
|
||||
Ok(res) => res,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
for d in data {
|
||||
for d in data.sets {
|
||||
self.sets.insert(d.src.clone(), d);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_ws_config(&mut self, server: &String) -> Result<(), ReqError> {
|
||||
let resp: Result<Response, ReqError> =
|
||||
httpclient().get(format!("{server}/config/ws")).send().await;
|
||||
let req = match resp {
|
||||
Ok(re) => re,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let data: HashMap<String, WebSocketCfg> = match req.json::<Vec<WebSocketCfg>>().await {
|
||||
Ok(res) => {
|
||||
let mut out: HashMap<String, WebSocketCfg> = HashMap::new();
|
||||
res.into_iter().map(|x| x).for_each(|x| {
|
||||
out.insert(x.t.to_string(), x);
|
||||
});
|
||||
out
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
self.ws = data;
|
||||
self.trustnets = data.trustlists;
|
||||
|
||||
data.ws.into_iter().map(|x| x).for_each(|x| {
|
||||
self.ws.insert(x.t.to_string(), x);
|
||||
});
|
||||
|
||||
self.api = data
|
||||
.cfg
|
||||
.get(&"api".to_string())
|
||||
.unwrap_or(&self.api)
|
||||
.clone();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -508,13 +454,15 @@ pub fn httpclient() -> Client {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct GlobalConfig {
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
pub struct GlobalConfigV2 {
|
||||
pub cfg: HashMap<String, String>,
|
||||
pub sets: Vec<SetCfg>,
|
||||
pub trustlists: Vec<String>,
|
||||
pub ws: Vec<WebSocketCfg>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Set {
|
||||
pub struct SetCfg {
|
||||
pub src: String,
|
||||
pub filename: String,
|
||||
pub regex: String,
|
||||
@ -543,13 +491,13 @@ pub struct URL {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
impl PartialEq for Set {
|
||||
impl PartialEq for SetCfg {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.src == other.src
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Set {
|
||||
impl Hash for SetCfg {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.src.hash(state);
|
||||
}
|
||||
|
119
src/fw.rs
119
src/fw.rs
@ -19,6 +19,57 @@ pub fn fwglobalinit<'a>() -> ((Batch, Table), (Batch, Table)) {
|
||||
((batch4, table4), (batch6, table6))
|
||||
}
|
||||
|
||||
macro_rules! initrules {
|
||||
($batch:expr, $table:expr, $chain:ident) => {
|
||||
let mut $chain = Chain::new(&CString::new(PKG_NAME).unwrap(), &$table);
|
||||
$chain.set_hook(nftnl::Hook::In, 1);
|
||||
$chain.set_policy(nftnl::Policy::Accept);
|
||||
|
||||
$batch.add(&$chain, nftnl::MsgType::Add);
|
||||
|
||||
$batch.add(&Rule::new(&$chain), nftnl::MsgType::Del);
|
||||
|
||||
let mut rule = Rule::new(&$chain);
|
||||
|
||||
rule.add_expr(&nft_expr!(ct state));
|
||||
rule.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32));
|
||||
rule.add_expr(&nft_expr!(cmp != 0u32));
|
||||
rule.add_expr(&nft_expr!(counter));
|
||||
rule.add_expr(&nft_expr!(verdict accept));
|
||||
|
||||
$batch.add(&rule, nftnl::MsgType::Add);
|
||||
};}
|
||||
macro_rules! createrules {
|
||||
($ipdata:ident, $chain:ident, $batch:ident) => {
|
||||
let mut rule = Rule::new(&$chain);
|
||||
match $ipdata.t {
|
||||
4 => {
|
||||
let ip = $ipdata.ip.parse::<Ipv4Addr>().unwrap();
|
||||
rule.add_expr(&nft_expr!(payload ipv4 saddr));
|
||||
rule.add_expr(&nft_expr!(cmp == ip));
|
||||
},
|
||||
6 => {
|
||||
let ip = $ipdata.ip.parse::<Ipv6Addr>().unwrap();
|
||||
rule.add_expr(&nft_expr!(payload ipv6 saddr));
|
||||
rule.add_expr(&nft_expr!(cmp == ip));
|
||||
},
|
||||
_ => {
|
||||
let ip = $ipdata.ip.parse::<Ipv4Addr>().unwrap();
|
||||
rule.add_expr(&nft_expr!(payload ipv4 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));
|
||||
|
||||
$batch.add(&rule, nftnl::MsgType::Add);
|
||||
}
|
||||
}
|
||||
|
||||
fn fwinit(t: FwTableType) -> (Batch, Table) {
|
||||
let table_name: String;
|
||||
let table: Table;
|
||||
@ -54,73 +105,13 @@ pub fn fwblock(
|
||||
) -> std::result::Result<(), Error> {
|
||||
let ((mut batch4, table4), (mut batch6, table6)) = fwglobalinit();
|
||||
|
||||
// build chain for ipv4
|
||||
let mut chain4 = Chain::new(&CString::new(PKG_NAME).unwrap(), &table4);
|
||||
chain4.set_hook(nftnl::Hook::In, 1);
|
||||
chain4.set_policy(nftnl::Policy::Accept);
|
||||
|
||||
// add chain
|
||||
batch4.add(&chain4, nftnl::MsgType::Add);
|
||||
|
||||
batch4.add(&Rule::new(&chain4), nftnl::MsgType::Del);
|
||||
|
||||
let mut rule4 = Rule::new(&chain4);
|
||||
rule4.add_expr(&nft_expr!(ct state));
|
||||
rule4.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32));
|
||||
rule4.add_expr(&nft_expr!(cmp != 0u32));
|
||||
rule4.add_expr(&nft_expr!(counter));
|
||||
rule4.add_expr(&nft_expr!(verdict accept));
|
||||
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);
|
||||
initrules!(batch4, table4, chain4);
|
||||
initrules!(batch6, table6, chain6);
|
||||
|
||||
// build and add rules
|
||||
for ipdata in ips_add.clone() {
|
||||
match ipdata.t {
|
||||
4 => {
|
||||
let ip = ipdata.ip.parse::<Ipv4Addr>().unwrap();
|
||||
let mut rule = Rule::new(&chain4);
|
||||
rule.add_expr(&nft_expr!(payload ipv4 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));
|
||||
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!()
|
||||
}
|
||||
}
|
||||
createrules!(ipdata, chain4, batch4);
|
||||
createrules!(ipdata, chain6, batch6);
|
||||
}
|
||||
|
||||
// validate and send batch
|
||||
|
37
src/ip.rs
37
src/ip.rs
@ -54,6 +54,19 @@ pub struct IpData {
|
||||
pub hostname: String,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ipdata {
|
||||
($t:expr,$ip:expr,$src:expr,$date:expr,$hostname:expr) => {
|
||||
IpData {
|
||||
t: $t.clone(),
|
||||
ip: $ip.clone(),
|
||||
src: $src.clone(),
|
||||
date: $date.clone(),
|
||||
hostname: $hostname.clone(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl PartialEq for IpData {
|
||||
fn eq(&self, other: &IpData) -> bool {
|
||||
self.ip.as_bytes() == other.ip.as_bytes() && self.src == other.src
|
||||
@ -123,6 +136,14 @@ pub fn filter(
|
||||
}
|
||||
};
|
||||
|
||||
let ipaddr: IpAddr = match s_ipaddr.parse() {
|
||||
Ok(ip) => ip,
|
||||
Err(err) => {
|
||||
println!("unparseable IP: {err} {s_ipaddr}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let s_date: DateTime<Local>;
|
||||
match R_DATE.captures(l.as_str()) {
|
||||
Some(sdt) => {
|
||||
@ -136,22 +157,8 @@ pub fn filter(
|
||||
}
|
||||
};
|
||||
|
||||
let ipaddr: IpAddr = match s_ipaddr.parse() {
|
||||
Ok(ip) => ip,
|
||||
Err(err) => {
|
||||
println!("unparseable IP: {err} {s_ipaddr}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if !is_trusted(&ipaddr, &trustnets) {
|
||||
iplist.push(IpData {
|
||||
ip: s_ipaddr,
|
||||
t: t,
|
||||
src: src.to_owned(),
|
||||
date: s_date.to_rfc3339().to_owned(),
|
||||
hostname: hostname.to_owned(),
|
||||
});
|
||||
iplist.push(ipdata!(t, s_ipaddr, src, s_date.to_rfc3339(), hostname));
|
||||
ips += 1;
|
||||
};
|
||||
}
|
||||
|
38
src/ipblc.rs
38
src/ipblc.rs
@ -69,12 +69,10 @@ pub async fn run() {
|
||||
ipevent = ipeventrx.recv() => {
|
||||
let received_ip = ipevent.unwrap();
|
||||
|
||||
let (toblock,server);
|
||||
{
|
||||
let (toblock,server) = {
|
||||
let ctx = ctxclone.read().await;
|
||||
toblock = ctx.get_blocklist_toblock().await;
|
||||
server = ctx.flags.server.clone();
|
||||
}
|
||||
(ctx.get_blocklist_toblock().await,ctx.flags.server.clone())
|
||||
};
|
||||
|
||||
if received_ip.msgtype == "bootstrap".to_string() {
|
||||
for ip_to_send in toblock {
|
||||
@ -88,11 +86,9 @@ pub async fn run() {
|
||||
}
|
||||
|
||||
// refresh context blocklist
|
||||
let filtered_ipevent;
|
||||
{
|
||||
let mut ctx = ctxarc.write().await;
|
||||
filtered_ipevent = ctx.update_blocklist(&received_ip).await;
|
||||
}
|
||||
let filtered_ipevent = {
|
||||
ctxarc.write().await.update_blocklist(&received_ip).await
|
||||
};
|
||||
|
||||
// send ip list to api and ws sockets
|
||||
if let Some(ipevent) = filtered_ipevent {
|
||||
@ -132,9 +128,8 @@ async fn handle_cfg_reload(
|
||||
) {
|
||||
let now_cfg_reload = Local::now().trunc_subsecs(0);
|
||||
if (now_cfg_reload - *last_cfg_reload) > Duration::seconds(LOOP_MAX_WAIT as i64) {
|
||||
let mut ctx = ctxclone.write().await;
|
||||
let inotify = inoarc.read().await;
|
||||
match ctx.load(&inotify).await {
|
||||
match ctxclone.write().await.load(&inotify).await {
|
||||
Ok(_) => {
|
||||
*last_cfg_reload = Local::now().trunc_subsecs(0);
|
||||
}
|
||||
@ -201,19 +196,16 @@ async fn compare_files_changes(
|
||||
let modfiles = inrx.recv().await.unwrap();
|
||||
let mut iplist: Vec<IpData> = vec![];
|
||||
|
||||
let sask;
|
||||
let sas;
|
||||
{
|
||||
let sas = {
|
||||
let ctx = ctxarc.read().await;
|
||||
sas = ctx.sas.clone();
|
||||
sask = sas.keys();
|
||||
tnets = ctx.cfg.build_trustnets();
|
||||
}
|
||||
ctx.sas.clone()
|
||||
};
|
||||
|
||||
match modfiles.inevent.name {
|
||||
Some(name) => {
|
||||
let filename = name.to_str().unwrap();
|
||||
for sak in sask {
|
||||
for sak in sas.clone().keys() {
|
||||
let sa = sas.get(sak).unwrap();
|
||||
if modfiles.inevent.wd == sa.wd {
|
||||
let handle: String;
|
||||
@ -225,13 +217,11 @@ async fn compare_files_changes(
|
||||
continue;
|
||||
}
|
||||
|
||||
let (filesize, sizechanged);
|
||||
{
|
||||
let (filesize, sizechanged) = {
|
||||
let mut ctx = ctxarc.write().await;
|
||||
let sa = ctx.sas.get_mut(sak).unwrap();
|
||||
(filesize, sizechanged) =
|
||||
get_last_file_size(&mut sa.watchedfiles, &handle).await;
|
||||
}
|
||||
get_last_file_size(&mut sa.watchedfiles, &handle).await
|
||||
};
|
||||
|
||||
if !sizechanged {
|
||||
continue;
|
||||
|
@ -9,48 +9,63 @@ use tokio::sync::RwLock;
|
||||
|
||||
pub async fn apiserver(ctxarc: &Arc<RwLock<Context>>) -> io::Result<()> {
|
||||
let ctxarc = ctxarc.clone();
|
||||
let addr;
|
||||
{
|
||||
let ctx = ctxarc.read().await;
|
||||
addr = ctx.cfg.api.parse().unwrap();
|
||||
}
|
||||
let addr = { ctxarc.read().await.cfg.api.parse().unwrap() };
|
||||
|
||||
let socket = TcpSocket::new_v4().unwrap();
|
||||
socket.bind(addr).unwrap();
|
||||
match socket.bind(addr) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
println!("can't bind monitoring socket, exiting...");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
socket.set_reuseaddr(true).unwrap();
|
||||
let listener = socket.listen(1024).unwrap();
|
||||
let listener = socket.listen(128).unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
match listener.accept().await {
|
||||
Ok((stream, _addr)) => {
|
||||
//let mut buf = [0; 1024];
|
||||
let data;
|
||||
{
|
||||
let ctx = ctxarc.read().await;
|
||||
data = serde_json::to_string(&ctx.blocklist);
|
||||
}
|
||||
stream.readable().await.unwrap();
|
||||
let (reader, mut writer) = stream.into_split();
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
|
||||
match data {
|
||||
Ok(dt) => {
|
||||
let (_reader, mut writer) = stream.into_split();
|
||||
match writer.write_all(format!("{dt}").as_bytes()).await {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
println!("{err}");
|
||||
}
|
||||
}
|
||||
match reader.try_read(&mut buf) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("error: {}", e);
|
||||
}
|
||||
};
|
||||
let msg = match String::from_utf8(buf.to_vec()) {
|
||||
Ok(o) => o.trim_matches(char::from(0)).trim().to_string(),
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
|
||||
let res = format_result(&ctxarc, msg.as_str()).await;
|
||||
|
||||
match writer.write_all(format!("{res}").as_bytes()).await {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
println!("unable to serialize data: {err}");
|
||||
println!("ee {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("couldn't get client: {}", err)
|
||||
println!("unable to serialize data: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn format_result(ctxarc: &Arc<RwLock<Context>>, mode: &str) -> String {
|
||||
let data;
|
||||
let ctx = ctxarc.read().await;
|
||||
match mode {
|
||||
"cfg" => data = serde_json::to_string(&ctx.cfg).unwrap(),
|
||||
"blocklist" => data = serde_json::to_string(&ctx.blocklist).unwrap(),
|
||||
_ => data = serde_json::to_string(&ctx.blocklist).unwrap(),
|
||||
};
|
||||
data
|
||||
}
|
||||
|
28
src/old.rs
Normal file
28
src/old.rs
Normal file
@ -0,0 +1,28 @@
|
||||
pub fn _search_subfolders(path: &Path) -> Vec<String> {
|
||||
let dirs = std::fs::read_dir(path).unwrap();
|
||||
let mut folders: Vec<String> = vec![];
|
||||
for dir in dirs {
|
||||
let dirpath = dir.unwrap().path();
|
||||
let path = Path::new(dirpath.as_path());
|
||||
if path.is_dir() {
|
||||
folders.push(dirpath.to_str().unwrap().to_string());
|
||||
for f in _search_subfolders(path) {
|
||||
folders.push(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
folders
|
||||
}
|
||||
|
||||
pub fn _dedup<T: Ord + PartialOrd>(list: &mut Vec<T>) -> usize {
|
||||
// Begin with sorting entries
|
||||
list.sort();
|
||||
// Then deduplicate
|
||||
list.dedup();
|
||||
// Return the length
|
||||
list.len()
|
||||
}
|
||||
|
||||
pub async fn _sleep_ms(ms: u64) {
|
||||
sleep(Duration::from_millis(ms)).await;
|
||||
}
|
36
src/utils.rs
36
src/utils.rs
@ -1,16 +1,9 @@
|
||||
use lazy_static::lazy_static;
|
||||
use nix::unistd;
|
||||
use regex::Regex;
|
||||
use std::boxed::Box;
|
||||
use std::fs::File;
|
||||
use std::io::*;
|
||||
use std::path::Path;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
lazy_static! {
|
||||
static ref R_FILE_GZIP: Regex = Regex::new(r".*\.gz.*").unwrap();
|
||||
}
|
||||
|
||||
pub fn read_lines(filename: &String, offset: u64) -> Option<Box<dyn Read>> {
|
||||
let mut file = match File::open(filename) {
|
||||
Ok(f) => f,
|
||||
@ -24,19 +17,6 @@ pub fn read_lines(filename: &String, offset: u64) -> Option<Box<dyn Read>> {
|
||||
Some(lines)
|
||||
}
|
||||
|
||||
pub fn _dedup<T: Ord + PartialOrd>(list: &mut Vec<T>) -> usize {
|
||||
// Begin with sorting entries
|
||||
list.sort();
|
||||
// Then deduplicate
|
||||
list.dedup();
|
||||
// Return the length
|
||||
list.len()
|
||||
}
|
||||
|
||||
pub async fn _sleep_ms(ms: u64) {
|
||||
sleep(Duration::from_millis(ms)).await;
|
||||
}
|
||||
|
||||
pub async fn sleep_s(s: u64) {
|
||||
sleep(Duration::from_secs(s)).await;
|
||||
}
|
||||
@ -53,19 +33,3 @@ pub fn gethostname(show_fqdn: bool) -> String {
|
||||
}
|
||||
hostname[0].to_string()
|
||||
}
|
||||
|
||||
pub fn _search_subfolders(path: &Path) -> Vec<String> {
|
||||
let dirs = std::fs::read_dir(path).unwrap();
|
||||
let mut folders: Vec<String> = vec![];
|
||||
for dir in dirs {
|
||||
let dirpath = dir.unwrap().path();
|
||||
let path = Path::new(dirpath.as_path());
|
||||
if path.is_dir() {
|
||||
folders.push(dirpath.to_str().unwrap().to_string());
|
||||
for f in _search_subfolders(path) {
|
||||
folders.push(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
folders
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user