Build a complete Network Intrusion Detection System (NIDS) in Rust from the ground up.
┌─────────────────────────────────────────────────────────────────────────────┐
│ IDS ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PACKET │ │ RULE │ │ IP │ │ ALERT │ │
│ │ CAPTURE │──▶│ ENGINE │──▶│ REPUTATION │──▶│ SYSTEM │ │
│ │ │ │ │ │ │ │ │ │
│ │ • pcap/AF │ │ • Parser │ │ • Blocklist │ │ • Logging │ │
│ │ • BPF │ │ • Matcher │ │ • GeoIP │ │ • Email │ │
│ │ • Decode │ │ • Actions │ │ • Threat DB │ │ • Webhook │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │ │
│ └────────────────┴─────────────────┴─────────────────┘ │
│ │ │
│ ┌─────────────────┐ │
│ │ IPTABLES │ │
│ │ INTEGRATION │ │
│ │ ─────────── │ │
│ │ • Auto-block │ │
│ │ • Rate limit │ │
│ │ • Logging │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
| Section | Focus | Key Components |
|---|---|---|
| 01_Packet_Capture | Network traffic capture | libpcap, AF_PACKET, BPF filters |
| 02_Rule_Engine | Detection rules | Snort-like syntax, pattern matching |
| 03_IP_Reputation | Threat intelligence | Blocklists, scoring, GeoIP |
| 04_Alert_System | Response and notification | Logging, email, iptables |
By the end of this chapter, you will be able to:
- Capture and decode network packets in Rust
- Build a rule-based detection engine
- Implement IP reputation and threat scoring
- Create automated response and alerting systems
- Integrate with iptables for active blocking
- Build a production-ready IDS
- Completed Intermediate Rust projects
- Understanding of TCP/IP networking
- Basic Linux administration (iptables)
- Root access for packet capture
[dependencies]
pcap = "1.1" # Packet capture
pnet = "0.34" # Packet parsing
etherparse = "0.13" # Ethernet frame parsing
regex = "1.10" # Pattern matching
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" # Configuration
tokio = { version = "1", features = ["full"] } # Async runtime
lettre = "0.11" # Email alerts
reqwest = { version = "0.11", features = ["json"] } # Webhooks
clap = { version = "4.4", features = ["derive"] }
log = "0.4" # Logging framework
env_logger = "0.10" # Logger implementation# Install libpcap development files
sudo apt-get install libpcap-dev
# For iptables integration
sudo apt-get install iptables
# Verify capabilities (alternative to running as root)
sudo setcap cap_net_raw,cap_net_admin=eip ./target/release/rust-ids┌─────────────────────────────────────────────────────────────────────────────┐
│ PERMISSION REQUIREMENTS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Packet Capture: │
│ • CAP_NET_RAW - Capture raw network packets │
│ • CAP_NET_ADMIN - Configure network interfaces │
│ │
│ IPTables Integration: │
│ • Root access OR CAP_NET_ADMIN │
│ • Write access to /proc/sys/net/ipv4/ip_forward (optional) │
│ │
│ Logging: │
│ • Write access to log directory │
│ • Syslog access (optional) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Here's a preview of the complete system we'll build:
//! Minimal IDS - Preview of what you'll build
//!
//! This captures packets and checks them against simple rules
use std::net::IpAddr;
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
// ═══════════════════════════════════════════════════════════════════════════
// DATA STRUCTURES
// ═══════════════════════════════════════════════════════════════════════════
/// Represents a captured network packet
///
/// # Fields Explained
/// - `timestamp`: When the packet was captured (Unix epoch microseconds)
/// - `src_ip`: Source IP address
/// - `dst_ip`: Destination IP address
/// - `src_port`: Source port (0 for non-TCP/UDP)
/// - `dst_port`: Destination port
/// - `protocol`: IP protocol number (6=TCP, 17=UDP, 1=ICMP)
/// - `payload`: Raw packet payload
/// - `size`: Total packet size in bytes
#[derive(Debug, Clone)]
struct Packet {
timestamp: u64,
src_ip: IpAddr,
dst_ip: IpAddr,
src_port: u16,
dst_port: u16,
protocol: u8,
payload: Vec<u8>,
size: usize,
}
/// IDS Detection Rule
///
/// # Rule Anatomy
/// ```text
/// alert tcp any any -> 192.168.1.0/24 22 (msg:"SSH Connection"; sid:1001;)
/// ─┬─── ─┬─ ─┬─ ─┬─ ─────┬──────── ─┬─ ─────────────┬─────────────────
/// │ │ │ │ │ │ │
/// │ │ │ │ │ │ └── Options
/// │ │ │ │ │ └── Destination port
/// │ │ │ │ └── Destination network
/// │ │ │ └── Direction (-> unidirectional, <> bidirectional)
/// │ │ └── Source port
/// │ └── Protocol (tcp, udp, icmp, ip)
/// └── Action (alert, log, drop, pass)
/// ```
#[derive(Debug, Clone)]
struct Rule {
/// Unique rule identifier
id: u32,
/// Rule name/message
name: String,
/// Action to take (Alert, Log, Drop)
action: RuleAction,
/// Protocol to match
protocol: Option<Protocol>,
/// Source IP/network (None = any)
src_ip: Option<IpNetwork>,
/// Source port (None = any)
src_port: Option<PortMatch>,
/// Destination IP/network
dst_ip: Option<IpNetwork>,
/// Destination port
dst_port: Option<PortMatch>,
/// Content patterns to match in payload
content: Vec<ContentMatch>,
/// Severity level
severity: Severity,
}
/// What action to take when rule matches
#[derive(Debug, Clone, PartialEq)]
enum RuleAction {
/// Generate an alert
Alert,
/// Log the packet (no alert)
Log,
/// Drop the packet (requires inline mode)
Drop,
/// Allow packet (whitelist)
Pass,
}
/// Network protocols we detect
#[derive(Debug, Clone, PartialEq)]
enum Protocol {
TCP,
UDP,
ICMP,
Any,
}
/// IP network specification (address + optional CIDR)
#[derive(Debug, Clone)]
struct IpNetwork {
address: IpAddr,
prefix_len: u8,
}
/// Port matching specification
#[derive(Debug, Clone)]
enum PortMatch {
/// Match single port
Single(u16),
/// Match port range (inclusive)
Range(u16, u16),
/// Match any port
Any,
/// Match multiple specific ports
List(Vec<u16>),
}
/// Content pattern to match in payload
#[derive(Debug, Clone)]
struct ContentMatch {
/// The pattern to match
pattern: Vec<u8>,
/// Is this a negated match (match if NOT present)
negated: bool,
/// Case insensitive matching
nocase: bool,
/// Offset from start of payload
offset: Option<usize>,
/// Maximum search depth
depth: Option<usize>,
}
/// Alert severity levels
#[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq)]
enum Severity {
Low = 1,
Medium = 2,
High = 3,
Critical = 4,
}
/// Alert generated when a rule matches
#[derive(Debug, Clone)]
struct Alert {
/// Timestamp of the alert
timestamp: u64,
/// Rule that triggered
rule_id: u32,
/// Rule name/message
message: String,
/// Source IP
src_ip: IpAddr,
/// Destination IP
dst_ip: IpAddr,
/// Source port
src_port: u16,
/// Destination port
dst_port: u16,
/// Protocol
protocol: String,
/// Severity
severity: Severity,
/// Additional context
context: String,
}
/// IP reputation entry
#[derive(Debug, Clone)]
struct IpReputation {
/// The IP address
address: IpAddr,
/// Reputation score (0-100, higher = more suspicious)
score: u32,
/// Categories this IP belongs to
categories: Vec<String>,
/// When this entry was last updated
last_updated: u64,
/// Source of the intelligence
source: String,
}
// ═══════════════════════════════════════════════════════════════════════════
// THE IDS ENGINE
// ═══════════════════════════════════════════════════════════════════════════
/// The main IDS engine that coordinates detection
///
/// # Architecture
/// ```text
/// ┌─────────────────────────────────────────────────────────────┐
/// │ IDS Engine │
/// │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐│
/// │ │ Rules │ │ Blocklist │ │ Alert Handlers ││
/// │ │ Vec<Rule> │ │ HashSet<IP> │ │ Vec<Box<dyn Handler>> ││
/// │ └─────────────┘ └─────────────┘ └─────────────────────────┘│
/// │ │
/// │ ┌─────────────┐ │
/// │ │ Stats │ │
/// │ │ Arc<Mutex> │ │
/// │ └─────────────┘ │
/// └─────────────────────────────────────────────────────────────┘
/// ```
struct IdsEngine {
/// Detection rules
rules: Vec<Rule>,
/// Known malicious IPs (instant block)
blocklist: HashSet<IpAddr>,
/// IP reputation database
reputation: Vec<IpReputation>,
/// Statistics (thread-safe)
stats: Arc<Mutex<IdsStats>>,
/// Alert threshold for reputation
reputation_threshold: u32,
}
/// IDS Statistics
#[derive(Debug, Default)]
struct IdsStats {
packets_processed: u64,
alerts_generated: u64,
packets_dropped: u64,
bytes_processed: u64,
}
impl IdsEngine {
/// Creates a new IDS engine with default settings
fn new() -> Self {
IdsEngine {
rules: Vec::new(),
blocklist: HashSet::new(),
reputation: Vec::new(),
stats: Arc::new(Mutex::new(IdsStats::default())),
reputation_threshold: 70,
}
}
/// Loads rules from a configuration
fn load_rules(&mut self, rules: Vec<Rule>) {
self.rules = rules;
println!("[*] Loaded {} rules", self.rules.len());
}
/// Adds IPs to the blocklist
fn add_to_blocklist(&mut self, ips: Vec<IpAddr>) {
for ip in ips {
self.blocklist.insert(ip);
}
println!("[*] Blocklist contains {} IPs", self.blocklist.len());
}
/// Processes a single packet
///
/// # Processing Steps
/// 1. Update statistics
/// 2. Check blocklist (instant alert)
/// 3. Check IP reputation
/// 4. Match against rules
/// 5. Generate alerts if needed
fn process_packet(&self, packet: &Packet) -> Vec<Alert> {
let mut alerts = Vec::new();
// Update stats
if let Ok(mut stats) = self.stats.lock() {
stats.packets_processed += 1;
stats.bytes_processed += packet.size as u64;
}
// Step 1: Check blocklist
if self.blocklist.contains(&packet.src_ip) {
alerts.push(Alert {
timestamp: packet.timestamp,
rule_id: 0,
message: "Blocklisted IP detected".to_string(),
src_ip: packet.src_ip,
dst_ip: packet.dst_ip,
src_port: packet.src_port,
dst_port: packet.dst_port,
protocol: self.protocol_to_string(packet.protocol),
severity: Severity::Critical,
context: "Source IP is on blocklist".to_string(),
});
}
// Step 2: Check IP reputation
if let Some(rep) = self.get_reputation(&packet.src_ip) {
if rep.score >= self.reputation_threshold {
alerts.push(Alert {
timestamp: packet.timestamp,
rule_id: 0,
message: format!("High-risk IP (score: {})", rep.score),
src_ip: packet.src_ip,
dst_ip: packet.dst_ip,
src_port: packet.src_port,
dst_port: packet.dst_port,
protocol: self.protocol_to_string(packet.protocol),
severity: Severity::High,
context: format!("Categories: {:?}", rep.categories),
});
}
}
// Step 3: Match against rules
for rule in &self.rules {
if self.matches_rule(rule, packet) {
if rule.action == RuleAction::Alert {
alerts.push(Alert {
timestamp: packet.timestamp,
rule_id: rule.id,
message: rule.name.clone(),
src_ip: packet.src_ip,
dst_ip: packet.dst_ip,
src_port: packet.src_port,
dst_port: packet.dst_port,
protocol: self.protocol_to_string(packet.protocol),
severity: rule.severity.clone(),
context: String::new(),
});
}
}
}
// Update alert stats
if !alerts.is_empty() {
if let Ok(mut stats) = self.stats.lock() {
stats.alerts_generated += alerts.len() as u64;
}
}
alerts
}
/// Checks if a packet matches a rule
fn matches_rule(&self, rule: &Rule, packet: &Packet) -> bool {
// Check protocol
if let Some(ref proto) = rule.protocol {
if !self.protocol_matches(proto, packet.protocol) {
return false;
}
}
// Check source IP
if let Some(ref network) = rule.src_ip {
if !self.ip_in_network(&packet.src_ip, network) {
return false;
}
}
// Check destination IP
if let Some(ref network) = rule.dst_ip {
if !self.ip_in_network(&packet.dst_ip, network) {
return false;
}
}
// Check source port
if let Some(ref port_match) = rule.src_port {
if !self.port_matches(port_match, packet.src_port) {
return false;
}
}
// Check destination port
if let Some(ref port_match) = rule.dst_port {
if !self.port_matches(port_match, packet.dst_port) {
return false;
}
}
// Check content patterns
for content in &rule.content {
if !self.content_matches(content, &packet.payload) {
return false;
}
}
true
}
/// Checks if protocol matches
fn protocol_matches(&self, rule_proto: &Protocol, packet_proto: u8) -> bool {
match rule_proto {
Protocol::Any => true,
Protocol::TCP => packet_proto == 6,
Protocol::UDP => packet_proto == 17,
Protocol::ICMP => packet_proto == 1,
}
}
/// Checks if IP is in network
fn ip_in_network(&self, ip: &IpAddr, network: &IpNetwork) -> bool {
match (ip, &network.address) {
(IpAddr::V4(ip), IpAddr::V4(net)) => {
let ip_bits = u32::from(*ip);
let net_bits = u32::from(*net);
let mask = !0u32 << (32 - network.prefix_len);
(ip_bits & mask) == (net_bits & mask)
}
(IpAddr::V6(ip), IpAddr::V6(net)) => {
let ip_bits = u128::from(*ip);
let net_bits = u128::from(*net);
let mask = !0u128 << (128 - network.prefix_len);
(ip_bits & mask) == (net_bits & mask)
}
_ => false,
}
}
/// Checks if port matches
fn port_matches(&self, port_match: &PortMatch, port: u16) -> bool {
match port_match {
PortMatch::Any => true,
PortMatch::Single(p) => *p == port,
PortMatch::Range(start, end) => port >= *start && port <= *end,
PortMatch::List(ports) => ports.contains(&port),
}
}
/// Checks if content pattern matches payload
fn content_matches(&self, content: &ContentMatch, payload: &[u8]) -> bool {
let search_area = if let Some(offset) = content.offset {
if offset >= payload.len() {
return content.negated;
}
&payload[offset..]
} else {
payload
};
let search_area = if let Some(depth) = content.depth {
let end = depth.min(search_area.len());
&search_area[..end]
} else {
search_area
};
let pattern = if content.nocase {
content.pattern.to_ascii_lowercase()
} else {
content.pattern.clone()
};
let search = if content.nocase {
search_area.to_ascii_lowercase()
} else {
search_area.to_vec()
};
let found = search.windows(pattern.len())
.any(|window| window == pattern.as_slice());
if content.negated { !found } else { found }
}
/// Gets IP reputation
fn get_reputation(&self, ip: &IpAddr) -> Option<&IpReputation> {
self.reputation.iter().find(|r| r.address == *ip)
}
/// Converts protocol number to string
fn protocol_to_string(&self, proto: u8) -> String {
match proto {
1 => "ICMP".to_string(),
6 => "TCP".to_string(),
17 => "UDP".to_string(),
_ => format!("IP({})", proto),
}
}
}
// ═══════════════════════════════════════════════════════════════════════════
// IPTABLES INTEGRATION
// ═══════════════════════════════════════════════════════════════════════════
/// Manages iptables rules for active response
///
/// # Security Considerations
/// - Requires root or CAP_NET_ADMIN
/// - Be careful not to lock yourself out!
/// - Always have out-of-band access
struct IptablesManager {
/// Chain to use for our rules
chain: String,
/// Maximum number of IPs to block (prevent resource exhaustion)
max_blocks: usize,
/// Currently blocked IPs
blocked: HashSet<IpAddr>,
}
impl IptablesManager {
fn new(chain: &str) -> Self {
IptablesManager {
chain: chain.to_string(),
max_blocks: 10000,
blocked: HashSet::new(),
}
}
/// Initializes the IDS chain in iptables
///
/// Creates a dedicated chain for IDS rules:
/// ```bash
/// iptables -N IDS_BLOCK
/// iptables -I INPUT -j IDS_BLOCK
/// ```
fn initialize(&self) -> Result<(), String> {
// Create chain
let output = std::process::Command::new("iptables")
.args(["-N", &self.chain])
.output()
.map_err(|e| format!("Failed to run iptables: {}", e))?;
// Chain might already exist, that's okay
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
if !stderr.contains("Chain already exists") {
// Continue anyway, might work
}
}
// Insert jump to our chain
std::process::Command::new("iptables")
.args(["-C", "INPUT", "-j", &self.chain])
.output()
.ok(); // Check if rule exists
std::process::Command::new("iptables")
.args(["-I", "INPUT", "-j", &self.chain])
.output()
.map_err(|e| format!("Failed to insert jump rule: {}", e))?;
Ok(())
}
/// Blocks an IP address
///
/// ```bash
/// iptables -A IDS_BLOCK -s <ip> -j DROP
/// ```
fn block_ip(&mut self, ip: &IpAddr) -> Result<(), String> {
if self.blocked.contains(ip) {
return Ok(()); // Already blocked
}
if self.blocked.len() >= self.max_blocks {
return Err("Maximum block limit reached".to_string());
}
let output = std::process::Command::new("iptables")
.args(["-A", &self.chain, "-s", &ip.to_string(), "-j", "DROP"])
.output()
.map_err(|e| format!("Failed to run iptables: {}", e))?;
if output.status.success() {
self.blocked.insert(*ip);
println!("[+] Blocked IP: {}", ip);
Ok(())
} else {
Err(String::from_utf8_lossy(&output.stderr).to_string())
}
}
/// Unblocks an IP address
fn unblock_ip(&mut self, ip: &IpAddr) -> Result<(), String> {
if !self.blocked.contains(ip) {
return Ok(()); // Not blocked
}
let output = std::process::Command::new("iptables")
.args(["-D", &self.chain, "-s", &ip.to_string(), "-j", "DROP"])
.output()
.map_err(|e| format!("Failed to run iptables: {}", e))?;
if output.status.success() {
self.blocked.remove(ip);
println!("[-] Unblocked IP: {}", ip);
Ok(())
} else {
Err(String::from_utf8_lossy(&output.stderr).to_string())
}
}
/// Flushes all IDS rules
fn flush(&mut self) -> Result<(), String> {
std::process::Command::new("iptables")
.args(["-F", &self.chain])
.output()
.map_err(|e| format!("Failed to flush chain: {}", e))?;
self.blocked.clear();
Ok(())
}
}
// ═══════════════════════════════════════════════════════════════════════════
// MAIN FUNCTION
// ═══════════════════════════════════════════════════════════════════════════
fn main() {
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ RUST IDS - Intrusion Detection System ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
// Initialize the IDS engine
let mut engine = IdsEngine::new();
// Load sample rules
engine.load_rules(vec![
Rule {
id: 1001,
name: "SSH Connection Attempt".to_string(),
action: RuleAction::Alert,
protocol: Some(Protocol::TCP),
src_ip: None,
src_port: None,
dst_ip: None,
dst_port: Some(PortMatch::Single(22)),
content: vec![],
severity: Severity::Low,
},
Rule {
id: 1002,
name: "Potential SQL Injection".to_string(),
action: RuleAction::Alert,
protocol: Some(Protocol::TCP),
src_ip: None,
src_port: None,
dst_ip: None,
dst_port: Some(PortMatch::List(vec![80, 443, 8080])),
content: vec![
ContentMatch {
pattern: b"UNION SELECT".to_vec(),
negated: false,
nocase: true,
offset: None,
depth: None,
},
],
severity: Severity::High,
},
Rule {
id: 1003,
name: "Potential XSS Attack".to_string(),
action: RuleAction::Alert,
protocol: Some(Protocol::TCP),
src_ip: None,
src_port: None,
dst_ip: None,
dst_port: Some(PortMatch::List(vec![80, 443])),
content: vec![
ContentMatch {
pattern: b"<script>".to_vec(),
negated: false,
nocase: true,
offset: None,
depth: None,
},
],
severity: Severity::Medium,
},
]);
// Add sample blocklist
engine.add_to_blocklist(vec![
"192.0.2.1".parse().unwrap(), // TEST-NET
"198.51.100.1".parse().unwrap(), // TEST-NET-2
]);
println!("\n[*] IDS Engine initialized and ready");
println!("[*] In a real implementation, this would capture live packets");
println!("[*] See the individual sections for complete implementations");
}┌─────────────────────────────────────────────────────────────────────────────┐
│ IDS vs IPS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ IDS (Intrusion Detection System) │
│ ───────────────────────────────── │
│ • Passive monitoring │
│ • Alerts on suspicious activity │
│ • No packet modification │
│ • Deployed via port mirroring/TAP │
│ │
│ IPS (Intrusion Prevention System) │
│ ───────────────────────────────── │
│ • Inline deployment │
│ • Can drop/modify packets │
│ • Active blocking │
│ • Higher risk (can cause outages) │
│ │
│ Our System: Hybrid │
│ ───────────────────── │
│ • IDS detection + IPS response via iptables │
│ • Detection is passive (packet copy) │
│ • Response is active (firewall rules) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ DETECTION METHODS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. SIGNATURE-BASED │
│ └─► Match known attack patterns │
│ └─► Fast and accurate for known threats │
│ └─► Cannot detect zero-days │
│ │
│ 2. ANOMALY-BASED │
│ └─► Establish baseline behavior │
│ └─► Detect deviations from normal │
│ └─► Can detect unknown attacks │
│ └─► Higher false positive rate │
│ │
│ 3. REPUTATION-BASED │
│ └─► Check IP/domain against threat feeds │
│ └─► Quick and lightweight │
│ └─► Depends on feed quality │
│ │
│ 4. PROTOCOL-BASED │
│ └─► Validate protocol compliance │
│ └─► Detect malformed packets │
│ └─► State tracking │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
/// Process packets without copying data
///
/// # Why Zero-Copy?
/// Network IDS must process thousands of packets per second.
/// Copying packet data for each operation wastes CPU and memory.
fn process_packet_zero_copy<'a>(packet: &'a [u8]) -> Option<PacketHeader<'a>> {
// Parse header without copying
if packet.len() < 20 {
return None;
}
Some(PacketHeader {
data: packet,
ip_header_len: ((packet[0] & 0x0F) * 4) as usize,
})
}
struct PacketHeader<'a> {
data: &'a [u8], // Borrows original data
ip_header_len: usize,
}
impl<'a> PacketHeader<'a> {
fn src_ip(&self) -> [u8; 4] {
// Return slice of original data
[self.data[12], self.data[13], self.data[14], self.data[15]]
}
}use std::sync::atomic::{AtomicU64, Ordering};
/// Thread-safe statistics without locks
///
/// # Why Atomic?
/// Locks (Mutex) cause contention in high-throughput scenarios.
/// Atomic operations are lock-free and scale better.
struct LockFreeStats {
packets: AtomicU64,
bytes: AtomicU64,
alerts: AtomicU64,
}
impl LockFreeStats {
fn new() -> Self {
LockFreeStats {
packets: AtomicU64::new(0),
bytes: AtomicU64::new(0),
alerts: AtomicU64::new(0),
}
}
fn record_packet(&self, size: u64) {
// Relaxed ordering is fine for statistics
self.packets.fetch_add(1, Ordering::Relaxed);
self.bytes.fetch_add(size, Ordering::Relaxed);
}
fn get_stats(&self) -> (u64, u64, u64) {
(
self.packets.load(Ordering::Relaxed),
self.bytes.load(Ordering::Relaxed),
self.alerts.load(Ordering::Relaxed),
)
}
}use tokio::sync::mpsc;
/// Asynchronous alert processing
///
/// # Why Async?
/// Alert handling (email, webhook, database) is I/O bound.
/// Async allows processing alerts without blocking packet capture.
async fn alert_handler(mut rx: mpsc::Receiver<Alert>) {
while let Some(alert) = rx.recv().await {
// Process alert asynchronously
tokio::spawn(async move {
// Send email
send_email_alert(&alert).await;
// Send to SIEM
send_to_siem(&alert).await;
// Log to file
log_alert(&alert).await;
});
}
}
async fn send_email_alert(alert: &Alert) {
// Email sending implementation
}
async fn send_to_siem(alert: &Alert) {
// SIEM API call
}
async fn log_alert(alert: &Alert) {
// Async file logging
}Continue to the specific sections for detailed implementations.
→ 01_Packet_Capture | → 02_Rule_Engine | → 03_IP_Reputation | → 04_Alert_System