better logging & config reloading

This commit is contained in:
Tove 2026-01-03 09:44:39 +01:00
parent e5f81110d0
commit b49c8404b8
9 changed files with 330 additions and 30 deletions

279
Cargo.lock generated
View file

@ -8,10 +8,26 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bombai"
version = "0.1.0"
dependencies = [
"chrono",
"deborrow",
"flate2",
"horrorhttp",
@ -20,12 +36,47 @@ dependencies = [
"readformat",
]
[[package]]
name = "bumpalo"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "cc"
version = "1.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crc32fast"
version = "1.5.0"
@ -50,6 +101,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "551a13c0871ba8964b30d2407fdfd4c9b8e5f289950c152ff3d0d8de5be6b948"
[[package]]
name = "find-msvc-tools"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
[[package]]
name = "flate2"
version = "1.1.5"
@ -62,13 +119,59 @@ dependencies = [
[[package]]
name = "horrorhttp"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9940b42c31d4b7bc31b55b7aaa8c3bfb08ab9ffc5142aa7f882ff7a59719fd1a"
checksum = "68634f0a3125d68573063348ef1cbdb8f1a7e48fa830b4f3a4d27116100e078f"
dependencies = [
"readformat",
]
[[package]]
name = "iana-time-zone"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "js-sys"
version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "microlock"
version = "0.3.1"
@ -99,13 +202,179 @@ version = "0.2.1"
source = "git+https://github.com/tudbut/nanoserde#fc010f51957432aec80dba0a70af0dadc3cbe38f"
[[package]]
name = "readformat"
version = "1.0.3"
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cc7f16cea0fc473653b54865015941baf47c6f2b796b54c518a5d0e8e631a98"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "proc-macro2"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "readformat"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94c3a263091233283319d916f89668dac0ee49ffefa7cb7537c03810c7693674"
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simd-adler32"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]]
name = "syn"
version = "2.0.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasm-bindgen"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]

View file

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
chrono = "0.4.42"
deborrow = "0.3.1"
flate2 = "1.1.5"
horrorhttp = "0.2.1"

View file

@ -90,6 +90,11 @@ i dont like big dependency trees. so this one is small.
```
tudbut@Tud-NixX260 ~/g/bombai (main)> cargo tree
bombai v0.1.0 (/home/tudbut/gitshit/bombai)
├── chrono v0.4.42
│ ├── iana-time-zone v0.1.64
│ └── num-traits v0.2.19
│ [build-dependencies]
│ └── autocfg v1.5.0
├── deborrow v0.3.1
│ └── deborrow-macro v0.2.0 (proc-macro)
├── flate2 v1.1.5

View file

@ -3,7 +3,7 @@ use std::{collections::HashMap, net::IpAddr, time::Duration};
use horrorhttp::Connection;
use readformat::readf;
use crate::{CONFIG, ClientID, Counter, Directive, timed::Timeout};
use crate::{CONFIG, ClientID, Counter, Directive, log, timed::Timeout};
pub enum CheckResponse {
Okay,
@ -128,26 +128,26 @@ pub fn request_is_okay(
.path
.starts_with(CONFIG["fail_response.continuous_failure.path"].str())
{
println!(" is in continuous failure");
log!("Checker": "Is in continuous failure");
return CheckResponse::Fail;
}
for (i, directive) in directives.iter().enumerate() {
if directive.check_and_insert(connection, discrim_ip, transformed_ua) {
if directive.costly {
println!(" matched costly directive {i}");
log!("Checker": "Matched costly directive {i}");
if (!known.contains_key(&ClientID::IpAddr(discrim_ip))
|| !known.contains_key(&ClientID::TransformedUA(transformed_ua.to_owned())))
&& let Some(d) = directive.fail_if_first
{
println!(" request is first, but directive forbids it");
log!("Checker": "Request is first, but directive forbids it");
return CheckResponse::FailAsFirst(d);
}
if directive.counter_is_bad(discrim_ip, transformed_ua) {
println!(" counter is bad");
log!("Checker": "Counter is bad");
return CheckResponse::Fail;
}
} else {
println!(" matched non-costly directive {i} :)");
log!("Checker": "Matched non-costly directive {i} :)");
return CheckResponse::Okay;
}
}

View file

@ -2,6 +2,8 @@ use std::{collections::BTreeMap, fs, sync::LazyLock};
use nanoserde::{Toml, TomlParser};
use crate::log;
const DEFAULT_CONFIG: &str = include_str!("./bombai.toml");
pub static CONFIG: LazyLock<BTreeMap<String, Toml>> = LazyLock::new(load_config);
@ -11,7 +13,7 @@ fn load_config() -> BTreeMap<String, Toml> {
Ok(x) => x,
Err(_) => {
fs::write("./bombai.toml", DEFAULT_CONFIG).unwrap();
println!("dropped default config file because no other config was found");
log!("Config": "Dropped default config file because no other config was found");
DEFAULT_CONFIG.to_owned()
}
}

6
src/log.rs Normal file
View file

@ -0,0 +1,6 @@
#[macro_export]
macro_rules! log {
($area:literal: $($a:tt)*) => {
println!("[{}] [Bombai] [{}] {}", ::chrono::Local::now().time().format("%H:%M:%S"), $area, format!($($a)*));
};
}

View file

@ -1,6 +1,7 @@
pub mod checker;
pub mod config;
pub mod dashboard;
pub mod log;
pub mod processing;
pub mod responder;
pub mod timed;
@ -153,12 +154,12 @@ impl ConnectionState for Intercept {
let mut known = self.known.lock().unwrap();
if CONFIG["by_ua.enable"].boolean() {
println!(
log!("Handler":
"Handling request from {ip} ({discrim_ip} with {transformed_ua}) for {}.",
connection.path
);
} else {
println!(
log!("Handler":
"Handling request from {ip} ({discrim_ip}) for {}.",
connection.path
);
@ -185,7 +186,7 @@ impl ConnectionState for Intercept {
known.insert(ClientID::TransformedUA(transformed_ua), timeout(()));
dashboard::update_successes(true);
addr_timeouts.remove(&discrim_ip);
println!("Request is OK.");
log!("Handler": "Request is OK.");
Some(Box::new(ResponseWriter::new().with_status(
CONFIG["handler.pass_response"].num() as u32,
"Misdirected Request",
@ -206,8 +207,8 @@ impl ConnectionState for Intercept {
);
}
}
println!("Request is not OK. Sending you to the gallows.");
println!(" User-Agent: {transformed_ua}");
log!("Handler": "Request is not OK. Sending you to the gallows.");
log!("Handler": "User-Agent: {transformed_ua}");
Some(Box::new(BullshitResponder))
}
}
@ -240,7 +241,7 @@ fn main() {
let port = CONFIG["handler.listen_port"].num() as u16;
let server = TcpListener::bind(("::0", port)).unwrap();
println!("listening on [::0]:{port}");
log!("Handler": "listening on [::0]:{port}");
while let Ok((stream, _addr)) = server.accept() {
horrorhttp::handle(
stream,
@ -264,17 +265,28 @@ fn cleanup(
move || {
let lock = TimedLock::unlocked();
loop {
lock.lock_for(Duration::from_secs_f64(CONFIG["cleanup_time"].num() * 15.0).into());
if !lock.is_locked() {
lock.lock_for(Duration::from_secs_f64(CONFIG["cleanup_time"].num() * 15.0).into());
addr_timeouts.lock().unwrap().remove_expired();
ua_timeouts.lock().unwrap().remove_expired();
known.lock().unwrap().remove_expired();
for directive in directives {
directive.visited_paths.lock().unwrap().remove_expired();
log!("GC": "Garbage collecting...");
let mut total_removed = 0;
fn remove_expired<'a, T: Expire>(mut x: MutexGuard<'a, T>) -> usize {
let len = x.len();
x.remove_expired();
len - x.len()
}
total_removed += remove_expired(addr_timeouts.lock().unwrap());
total_removed += remove_expired(ua_timeouts.lock().unwrap());
total_removed += remove_expired(known.lock().unwrap());
for directive in directives {
total_removed += remove_expired(directive.visited_paths.lock().unwrap());
}
log!("GC": "Finished. Removed {total_removed} objects");
}
log!("Config": "Reloading config");
config::reload_config();
lock.wait_here();
lock.wait_here_for(Duration::from_mins(1).into());
}
}
}

View file

@ -5,7 +5,7 @@ use std::time::SystemTime;
use flate2::{Compression, write::GzEncoder};
use horrorhttp::{Connection, ConnectionState, ResponseWriter};
use crate::CONFIG;
use crate::{CONFIG, log};
static BODY: LazyLock<Vec<u8>> = LazyLock::new(gen_body);
static KILOBYTE: LazyLock<Vec<u8>> = LazyLock::new(|| {
@ -66,7 +66,7 @@ impl ConnectionState for GeneratedBullshitSpammer {
u64::MAX
};
println!(" i am spammer of bytes");
log!("Responder": "Spamming bytes");
// write begin
let _ = connection.socket.write_all(&begin);
@ -88,14 +88,14 @@ impl ConnectionState for GeneratedBullshitSpammer {
let _ = connection.socket.write_all(end);
self.0 += end.len() as u64;
println!(" stopped spamming after {} bytes", self.0);
log!("Responder": "Stopped spamming after {} bytes", self.0);
None
}
}
fn gen_body() -> Vec<u8> {
if CONFIG["fail_response.generated.gzip"].boolean() {
println!(" i am constructor of zip bomb");
log!("Responder": "Constructing zip bomb");
let mut encoder = GzEncoder::new(Vec::new(), Compression::fast());
encoder.write_all(&get_begin()).unwrap();
@ -109,7 +109,7 @@ fn gen_body() -> Vec<u8> {
.as_bytes(),
)
.unwrap();
println!(" done");
log!("Responder": "Done");
encoder.finish().unwrap()
} else {
vec![]

View file

@ -61,10 +61,15 @@ impl<T: Hash> Hash for Timeout<T> {
pub trait Expire {
fn remove_expired(&mut self);
fn len(&self) -> usize;
}
impl<K, V> Expire for HashMap<K, Timeout<V>> {
fn remove_expired(&mut self) {
self.retain(|_, v| !v.expired());
}
fn len(&self) -> usize {
HashMap::len(self)
}
}