Compare commits

...

1 Commits

Author SHA1 Message Date
563fbb557f fix: add better fw handling
All checks were successful
continuous-integration/drone/push Build is passing
* use stabilized rustables fw rule additions
* update dependencies
2025-02-27 00:13:09 +01:00
9 changed files with 348 additions and 240 deletions

509
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -12,18 +12,18 @@ repository = "https://git.paulbsd.com/paulbsd/ipblc"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.5", features = ["string"] } clap = { version = "4.5", features = ["string"] }
git-version = "0.3" git-version = "0.3"
ipnet = "2.10" ipnet = "2.11"
lazy_static = "1.5" lazy_static = "1.5"
nix = { version = "0.29", features = ["hostname", "inotify"] } nix = { version = "0.29", features = ["hostname", "inotify"] }
regex = "1.11" regex = "1.11"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
rustables = "0.8.5" rustables = "0.8.6"
rustables-macros = "0.1.2" rustables-macros = "0.1.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
sd-notify = { version = "0.4" } sd-notify = { version = "0.4" }
tokio = { version = "1.41", features = ["full", "sync"] } tokio = { version = "1.43", features = ["full", "sync"] }
tungstenite = { version = "0.24", features = ["handshake", "rustls-tls-native-roots"] } tungstenite = { version = "0.26", features = ["handshake", "rustls-tls-native-roots"] }
## to optimize binary size (slow compile time) ## to optimize binary size (slow compile time)
#[profile.release] #[profile.release]

View File

@ -2,13 +2,12 @@ use crate::ip::{BlockIpData, IpData, IpEvent};
use crate::utils::{gethostname, sleep_s}; use crate::utils::{gethostname, sleep_s};
use std::{ use std::{
collections::HashMap, collections::{HashMap, HashSet},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
path::Path, path::Path,
}; };
use chrono::prelude::*; use chrono::{prelude::*, Duration};
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;
@ -201,7 +200,7 @@ impl Context {
.with_timezone(&chrono::Local); .with_timezone(&chrono::Local);
let blocktime = set.blocktime; let blocktime = set.blocktime;
let blocked = false; let blocked = false;
let handle = u64::MIN; let handle = HashSet::new();
if ipevent.mode == "file".to_string() && gethostname(true) == ipevent.hostname { if ipevent.mode == "file".to_string() && gethostname(true) == ipevent.hostname {
let block = let block =
self.blocklist self.blocklist

View File

@ -6,9 +6,8 @@ use std::{
sync::Arc, sync::Arc,
}; };
use tokio::sync::RwLock;
use rustables::{expr::*, *}; use rustables::{expr::*, *};
use tokio::sync::RwLock;
pub enum FwTableType { pub enum FwTableType {
IPv4, IPv4,
@ -38,6 +37,10 @@ macro_rules! makerules {
Rule::new(&$chain) Rule::new(&$chain)
.unwrap() .unwrap()
.saddr(ip.into()) .saddr(ip.into())
.with_expr(Conntrack::new(ConntrackKey::State))
.with_expr(Bitwise::new(10u32.to_le_bytes(), 0u32.to_be_bytes()).unwrap())
.with_expr(Cmp::new(CmpOp::Neq, 0u32.to_be_bytes()))
.with_expr(Counter::default())
.drop() .drop()
.add_to_batch(&mut $batch); .add_to_batch(&mut $batch);
}; };
@ -50,14 +53,14 @@ pub fn fwglobalinit(t: FwTableType, reset: bool) -> (Batch, Chain) {
match t { match t {
FwTableType::IPv4 => { FwTableType::IPv4 => {
table_name = format!("{PKG_NAME}4"); table_name = format!("{PKG_NAME}4");
table = Table::new(ProtocolFamily::Ipv4).with_name(table_name); table = Table::new(ProtocolFamily::Inet).with_name(table_name);
chain = Chain::new(&table) chain = Chain::new(&table)
.with_policy(ChainPolicy::Accept) .with_policy(ChainPolicy::Accept)
.with_name(PKG_NAME); .with_name(PKG_NAME);
} }
FwTableType::IPv6 => { FwTableType::IPv6 => {
table_name = format!("{PKG_NAME}6"); table_name = format!("{PKG_NAME}6");
table = Table::new(ProtocolFamily::Ipv6).with_name(table_name); table = Table::new(ProtocolFamily::Inet).with_name(table_name);
chain = Chain::new(&table) chain = Chain::new(&table)
.with_policy(ChainPolicy::Accept) .with_policy(ChainPolicy::Accept)
.with_name(PKG_NAME); .with_name(PKG_NAME);
@ -106,8 +109,10 @@ pub fn fwunblock<'a>(ip_del: &BlockIpData) -> std::result::Result<&String, error
match ip_del.ipdata.t { match ip_del.ipdata.t {
4 => { 4 => {
let r = Rule::new(&chain4).unwrap().with_handle(ip_del.handle); for h in &ip_del.handle {
batch4.add(&r, MsgType::Del); let r = Rule::new(&chain4).unwrap().with_handle(*h);
batch4.add(&r, MsgType::Del);
}
match batch4.send() { match batch4.send() {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -116,8 +121,10 @@ pub fn fwunblock<'a>(ip_del: &BlockIpData) -> std::result::Result<&String, error
} }
} }
6 => { 6 => {
let r = Rule::new(&chain6).unwrap().with_handle(ip_del.handle); for h in &ip_del.handle {
batch6.add(&r, MsgType::Del); let r = Rule::new(&chain6).unwrap().with_handle(*h);
batch6.add(&r, MsgType::Del);
}
match batch6.send() { match batch6.send() {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -136,13 +143,13 @@ pub async fn get_current_rules(
fwlen: &mut usize, fwlen: &mut usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut ips_all_count = 0; let mut ips_all_count = 0;
let tables = vec![format!("{PKG_NAME}4"), format!("{PKG_NAME}6")]; let tables: &[String] = &[format!("{PKG_NAME}4"), format!("{PKG_NAME}6")];
for table_name in tables { for table_name in tables {
let get_table = || -> Result<Option<Table>, Error> { let get_table = || -> Result<Option<Table>, Error> {
let tables = list_tables().unwrap(); let tables = list_tables().unwrap();
for table in tables { for table in tables {
if let Some(name) = table.get_name() { if let Some(name) = table.get_name() {
if *name == table_name { if name == table_name {
return Ok(Some(table)); return Ok(Some(table));
} }
} }
@ -170,7 +177,7 @@ pub async fn get_current_rules(
let mut ctx = { ctx.write().await }; let mut ctx = { ctx.write().await };
let rules = list_rules_for_chain(&chain).unwrap().clone(); let rules = list_rules_for_chain(&chain).unwrap().clone();
for (ip, c) in ctx.blocklist.iter_mut() { for (ip, b) in ctx.blocklist.iter_mut() {
let ip_parsed: IpAddr = ip.parse().unwrap(); let ip_parsed: IpAddr = ip.parse().unwrap();
let cmprule = Rule::new(&chain).unwrap().saddr(ip_parsed).drop(); let cmprule = Rule::new(&chain).unwrap().saddr(ip_parsed).drop();
@ -185,8 +192,8 @@ pub async fn get_current_rules(
for expr in rule.get_expressions().unwrap().iter() { for expr in rule.get_expressions().unwrap().iter() {
if let Some(expr::ExpressionVariant::Cmp(_)) = expr.get_data() { if let Some(expr::ExpressionVariant::Cmp(_)) = expr.get_data() {
if gexpr == expr.clone() { if gexpr == expr.clone() {
b.handle.insert(*rule.get_handle().unwrap());
ips_all_count += 1; ips_all_count += 1;
c.handle = *rule.get_handle().unwrap();
} }
} }
} }

View File

@ -2,13 +2,13 @@ use crate::utils::gethostname;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::HashSet,
fmt::{Display, Formatter}, fmt::{Display, Formatter},
io::{BufRead, BufReader, Read}, io::{BufRead, BufReader, Read},
net::IpAddr, net::IpAddr,
}; };
use chrono::offset::LocalResult; use chrono::{offset::LocalResult, prelude::*};
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;
@ -55,7 +55,7 @@ pub struct BlockIpData {
pub blocktime: i64, pub blocktime: i64,
pub starttime: DateTime<Local>, pub starttime: DateTime<Local>,
pub blocked: bool, pub blocked: bool,
pub handle: u64, pub handle: HashSet<u64>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, Eq)]

View File

@ -9,13 +9,13 @@ use crate::websocket::{send_to_ipbl_websocket, websocketpubsub, websocketreqrep}
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use chrono::prelude::*; use chrono::{prelude::*, Duration};
use chrono::prelude::{DateTime, Local};
use chrono::Duration;
use nix::sys::inotify::{InitFlags, Inotify, InotifyEvent}; use nix::sys::inotify::{InitFlags, Inotify, InotifyEvent};
use sd_notify::*; use sd_notify::*;
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::{
use tokio::sync::RwLock; mpsc::{channel, Receiver, Sender},
RwLock,
};
pub const PKG_NAME: &str = env!("CARGO_PKG_NAME"); pub const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const BL_CHAN_SIZE: usize = 32; const BL_CHAN_SIZE: usize = 32;

View File

@ -3,9 +3,7 @@ use crate::config::Context;
use std::{io, sync::Arc}; use std::{io, sync::Arc};
use serde_json; use serde_json;
use tokio::io::AsyncWriteExt; use tokio::{io::AsyncWriteExt, net::TcpListener, sync::RwLock};
use tokio::net::TcpListener;
use tokio::sync::RwLock;
pub async fn apiserver(ctxarc: &Arc<RwLock<Context>>) -> io::Result<()> { pub async fn apiserver(ctxarc: &Arc<RwLock<Context>>) -> io::Result<()> {
let ctxarc = ctxarc.clone(); let ctxarc = ctxarc.clone();

View File

@ -2,8 +2,7 @@ use crate::config::{httpclient, Context};
use crate::ip::{IpData, IpEvent}; use crate::ip::{IpData, IpEvent};
use crate::utils::sleep_s; use crate::utils::sleep_s;
use reqwest::Client; use reqwest::{Client, Error as ReqError};
use reqwest::Error as ReqError;
const MAX_FAILED_API_RATE: u64 = 10; const MAX_FAILED_API_RATE: u64 = 10;

View File

@ -9,10 +9,8 @@ use std::{
}; };
use serde_json::json; use serde_json::json;
use tokio::sync::mpsc::Sender; use tokio::sync::{mpsc::Sender, RwLock};
use tokio::sync::RwLock; use tungstenite::{stream::*, *};
use tungstenite::stream::*;
use tungstenite::*;
pub async fn websocketreqrep( pub async fn websocketreqrep(
ctxarc: &Arc<RwLock<Context>>, ctxarc: &Arc<RwLock<Context>>,
@ -102,7 +100,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.send(Message::Text(msg.to_string())).unwrap(); socket.send(Message::Text(msg.to_string().into())).unwrap();
Ok(socket) Ok(socket)
} }
@ -113,7 +111,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.send(Message::Text(msg)) { match ws.send(Message::Text(msg.into())) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
println!("err send read: {e:?}"); println!("err send read: {e:?}");