Files
fortify-xdp/xdp-firewall/src/monitor/app.rs
Jirayu 6101de6887 Implement XDP firewall with real-time TUI monitoring
Features:
- High-performance packet filtering via eBPF/XDP
- Instant blocklist with dynamic CLI management
- Exact-match rules with Drop/Pass/Log actions
- CIDR-based IP range dropping via LPM trie
- Token-bucket rate limiting (IP-based and flow-based)
- Auto temp bans for rate limit violators
- Real-time event logging via BPF ring buffer
- Interactive TUI monitor with live stats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 09:10:52 +07:00

85 lines
2.3 KiB
Rust

use std::collections::VecDeque;
use xdp_firewall_common::{FirewallEvent, RuleKey, RuleValue, Stats};
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Pane {
Rules,
Blocklist,
Logs,
}
pub struct App {
pub iface: String,
pub quit: bool,
pub pane: Pane,
pub global_stats: Stats,
pub prev_global_stats: Stats,
pub rules: Vec<(RuleKey, RuleValue, Stats)>,
pub blocklist: Vec<(u32, u64)>,
pub logs: VecDeque<FirewallEvent>,
pub max_logs: usize,
pub pps: u64,
pub bps: u64,
pub dialog: Dialog,
pub rules_selected: usize,
pub blocklist_selected: usize,
}
#[derive(Clone, Default, PartialEq, Eq)]
pub enum Dialog {
#[default]
None,
BlockIp { input: String },
AddRule { src_ip: String, dst_ip: String, proto: String, src_port: String, dst_port: String, action: String },
ConfirmDelete,
}
impl App {
pub fn new(iface: String) -> Self {
Self {
iface,
quit: false,
pane: Pane::Rules,
global_stats: Stats::default(),
prev_global_stats: Stats::default(),
rules: Vec::new(),
blocklist: Vec::new(),
logs: VecDeque::new(),
max_logs: 100,
pps: 0,
bps: 0,
dialog: Dialog::None,
rules_selected: 0,
blocklist_selected: 0,
}
}
pub fn on_tick(&mut self, global: Stats, rules: Vec<(RuleKey, RuleValue, Stats)>, blocklist: Vec<(u32, u64)>) {
let elapsed = 0.1;
let pkts = global.packets.saturating_sub(self.prev_global_stats.packets);
let bytes = global.bytes.saturating_sub(self.prev_global_stats.bytes);
self.pps = (pkts as f64 / elapsed) as u64;
self.bps = (bytes as f64 / elapsed) as u64;
self.prev_global_stats = self.global_stats;
self.global_stats = global;
self.rules = rules;
self.blocklist = blocklist;
}
pub fn add_log(&mut self, ev: FirewallEvent) {
if self.logs.len() >= self.max_logs {
self.logs.pop_back();
}
self.logs.push_front(ev);
}
pub fn selected_rule_id(&self) -> Option<u32> {
self.rules.get(self.rules_selected).map(|(_, v, _)| v.rule_id)
}
pub fn selected_block_ip(&self) -> Option<u32> {
self.blocklist.get(self.blocklist_selected).map(|(ip, _)| *ip)
}
}