Initial commit: Rampart v0.2.0
Multi-layer DDoS protection for Minecraft servers. - rampart-core: Edge node with XDP/eBPF + Rust L7 filtering - rampart-manager: REST API with JWT auth, Redis sync - rampart-cli: CLI tool for operators - velocity-plugin: Domain check, HMAC verify, server registry, load balancer - paper-plugin: Auto-registration, heartbeat, HMAC verify - dashboard: React + Vite web UI for management
This commit is contained in:
commit
cf9608ce5d
159 changed files with 15341 additions and 0 deletions
63
crates/rampart-core/src/metrics.rs
Normal file
63
crates/rampart-core/src/metrics.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use prometheus::{Encoder, IntCounterVec, IntGauge, register_int_counter_vec, register_int_gauge};
|
||||
use std::sync::LazyLock;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
pub static CONNECTIONS_TOTAL: LazyLock<IntCounterVec> = LazyLock::new(|| {
|
||||
register_int_counter_vec!("rampart_connections_total", "Total connections handled", &["result"])
|
||||
.expect("CONNECTIONS_TOTAL")
|
||||
});
|
||||
|
||||
pub static RATE_LIMIT_HITS: LazyLock<IntCounterVec> = LazyLock::new(|| {
|
||||
register_int_counter_vec!("rampart_rate_limit_hits", "Rate limit hits", &["action"]).expect("RATE_LIMIT_HITS")
|
||||
});
|
||||
|
||||
pub static ACTIVE_CONNECTIONS: LazyLock<IntGauge> = LazyLock::new(|| {
|
||||
register_int_gauge!("rampart_active_connections", "Active connections").expect("ACTIVE_CONNECTIONS")
|
||||
});
|
||||
|
||||
pub static BLACKLIST_SIZE: LazyLock<IntGauge> =
|
||||
LazyLock::new(|| register_int_gauge!("rampart_blacklist_size", "Blacklist entries").expect("BLACKLIST_SIZE"));
|
||||
|
||||
pub static DEATH_CODE_BANS_TOTAL: LazyLock<IntCounterVec> = LazyLock::new(|| {
|
||||
register_int_counter_vec!("rampart_death_code_bans_total", "Death code auto-bans", &["code"])
|
||||
.expect("DEATH_CODE_BANS_TOTAL")
|
||||
});
|
||||
|
||||
pub async fn run_metrics_server(addr: &str) {
|
||||
let listener = match TcpListener::bind(addr).await {
|
||||
Ok(l) => l,
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to bind metrics server: {e}");
|
||||
return;
|
||||
},
|
||||
};
|
||||
loop {
|
||||
let (mut stream, _) = match listener.accept().await {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
tracing::error!("Metrics accept error: {e}");
|
||||
continue;
|
||||
},
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let mut buf = [0u8; 1024];
|
||||
if stream.read(&mut buf).await.is_err() {
|
||||
return;
|
||||
}
|
||||
let metric_families = prometheus::gather();
|
||||
let encoder = prometheus::TextEncoder::new();
|
||||
let mut payload = Vec::new();
|
||||
if encoder.encode(&metric_families, &mut payload).is_err() {
|
||||
return;
|
||||
}
|
||||
let header = format!(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: text/plain; version=0.0.4\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
|
||||
payload.len()
|
||||
);
|
||||
let mut response = header.into_bytes();
|
||||
response.extend_from_slice(&payload);
|
||||
let _ = stream.write_all(&response).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue