Remove CAP_NET_ADMIN requirement and eliminate need for CAP_SYS_ADMIN on modern kernels by using non-promiscuous mode for packet capture. This significantly reduces security surface by following principle of least privilege.
15 KiB
Architecture
This document describes the technical architecture and implementation details of RustNet.
Table of Contents
- Multi-threaded Architecture
- Key Components
- Platform-Specific Implementations
- Performance Considerations
- Dependencies
- Security Considerations
Multi-threaded Architecture
RustNet uses a multi-threaded architecture for efficient packet processing:
┌─────────────────┐
│ Packet Capture │ ──packets──> Crossbeam Channel
│ (libpcap) │ │
└─────────────────┘ │
├──> ┌──────────────────┐
├──> │ Packet Processor │ ──> DashMap
├──> │ (Thread 0) │ │
└──> │ (Thread N) │ │
└──────────────────┘ │
│
┌─────────────────┐ │
│Process Enrichment│ ────────────────────────────────────────────> DashMap
│ (Platform API) │ │
└─────────────────┘ │
│
┌─────────────────┐ │
│Snapshot Provider│ <─────────────────────────────────────────── DashMap
└─────────────────┘ │
│ │
└──> RwLock<Vec<Connection>> (for UI) │
│
┌─────────────────┐ │
│ Cleanup Thread │ <─────────────────────────────────────────── DashMap
└─────────────────┘
Key Components
1. Packet Capture Thread
Uses libpcap to capture raw packets from the network interface. This thread runs independently and feeds packets into a Crossbeam channel for processing.
Responsibilities:
- Open network interface for packet capture (non-promiscuous, read-only mode)
- Apply BPF filters if needed
- Capture raw packets
- Send packets to processing queue
2. Packet Processors
Multiple worker threads (up to 4 by default, based on CPU cores) that parse packets and perform Deep Packet Inspection (DPI) analysis.
Responsibilities:
- Parse Ethernet, IP, TCP, UDP, ICMP, ARP headers
- Extract connection 5-tuple (protocol, src IP, src port, dst IP, dst port)
- Perform DPI to detect application protocols:
- HTTP with host information
- HTTPS/TLS with SNI (Server Name Indication)
- DNS queries and responses
- SSH connections with version detection
- QUIC protocol with CONNECTION_CLOSE frame detection
- Track connection states and lifecycle
- Update connection metadata in DashMap
- Calculate bandwidth metrics
3. Process Enrichment
Platform-specific APIs to associate network connections with running processes. This component runs periodically to enrich connection data with process information.
Responsibilities:
- Map socket inodes to process IDs
- Resolve process names and command lines
- Update connection records with process information
- Handle permission-related fallbacks
See Platform-Specific Implementations for details on each platform.
4. Snapshot Provider
Creates consistent snapshots of connection data for the UI at regular intervals (default: 1 second). This ensures the UI has a stable view of connections without race conditions.
Responsibilities:
- Read from DashMap at configured intervals
- Apply filtering based on user criteria (localhost, etc.)
- Sort connections based on user-selected column
- Create immutable snapshot for UI rendering
- Provide RwLock-protected Vec for UI thread
5. Cleanup Thread
Removes inactive connections using smart, protocol-aware timeouts. This prevents memory leaks and keeps the connection list relevant.
Timeout Strategy:
TCP Connections
- HTTP/HTTPS (detected via DPI): 10 minutes - supports HTTP keep-alive
- SSH (detected via DPI): 30 minutes - accommodates long interactive sessions
- Active established (< 1 min idle): 10 minutes
- Idle established (> 1 min idle): 5 minutes
- TIME_WAIT: 30 seconds - standard TCP timeout
- CLOSED: 5 seconds - rapid cleanup
- SYN_SENT, FIN_WAIT, etc.: 30-60 seconds
UDP Connections
- HTTP/3 (QUIC with HTTP): 10 minutes - connection reuse
- HTTPS/3 (QUIC with HTTPS): 10 minutes - connection reuse
- SSH over UDP: 30 minutes - long-lived sessions
- DNS: 30 seconds - short-lived queries
- Regular UDP: 60 seconds - standard timeout
QUIC Connections (Detected State)
- Connected (active) (< 1 min idle): 10 minutes
- Connected (idle) (> 1 min idle): 5 minutes
- With CONNECTION_CLOSE frame: 1-10 seconds (based on close type)
- Initial/Handshaking: 60 seconds - allow connection establishment
- Draining: 10 seconds - RFC 9000 draining period
Visual Staleness Indicators:
Connections change color based on proximity to timeout:
- White (default): < 75% of timeout
- Yellow: 75-90% of timeout (warning)
- Red: > 90% of timeout (critical)
6. Rate Refresh Thread
Updates bandwidth calculations every second with gentle decay. This provides smooth bandwidth visualization without abrupt changes.
Responsibilities:
- Calculate bytes/second for download and upload
- Apply exponential decay to older measurements
- Update visual bandwidth indicators
- Maintain rolling window of packet rates
7. DashMap
Concurrent hashmap (DashMap<ConnectionKey, Connection>) for storing connection state. This lock-free data structure enables efficient concurrent access from multiple threads.
Key Features:
- Fine-grained locking (per-shard)
- No global lock contention
- Safe concurrent reads and writes
- High performance under concurrent load
Platform-Specific Implementations
Process Lookup
RustNet uses platform-specific APIs to associate network connections with processes:
Linux
Standard Mode (procfs):
- Parses
/proc/net/tcpand/proc/net/udpto get socket inodes - Iterates through
/proc/<pid>/fd/to find socket file descriptors - Maps inodes to process IDs and resolves process names from
/proc/<pid>/cmdline
eBPF Mode (Default on Linux):
- Uses kernel eBPF programs attached to socket syscalls
- Captures socket creation events with process context
- Provides lower overhead than procfs scanning
- Limitations:
- Process names limited to 16 characters (kernel
commfield) - May show thread names instead of full executable names
- Multi-threaded applications show internal thread names
- Process names limited to 16 characters (kernel
- Capability requirements:
- Modern Linux (5.8+):
CAP_NET_RAW(packet capture),CAP_BPF,CAP_PERFMON(eBPF) - Legacy Linux (pre-5.8):
CAP_NET_RAW(packet capture),CAP_SYS_ADMIN(eBPF) - Note: CAP_NET_ADMIN is NOT required (uses read-only, non-promiscuous packet capture)
- Modern Linux (5.8+):
Fallback Behavior:
- If eBPF fails to load (permissions, kernel compatibility), automatically falls back to procfs mode
- TUI Statistics panel shows active detection method
See EBPF_BUILD.md for detailed eBPF build and deployment information.
macOS
PKTAP Mode (with sudo):
- Uses PKTAP (Packet Tap) kernel interface
- Extracts process information directly from packet metadata
- Requires root privileges (privileged kernel interface)
- Faster and more accurate than lsof
lsof Mode (without sudo or fallback):
- Uses
lsof -i -n -Pto list network connections - Parses output to associate sockets with processes
- Higher CPU overhead but works without root
- Used automatically when PKTAP is unavailable
Detection:
- TUI Statistics panel shows "pktap" or "lsof" based on active method
- Automatically selects best available method
Windows
IP Helper API:
- Uses
GetExtendedTcpTableandGetExtendedUdpTablefrom Windows IP Helper API - Retrieves connection tables with process IDs
- Supports both IPv4 and IPv6 connections
- Resolves process names using
OpenProcessandQueryFullProcessImageNameW
Requirements:
- May require Administrator privileges depending on system configuration
- Requires Npcap or WinPcap for packet capture
Network Interfaces
The tool automatically detects and lists available network interfaces using platform-specific methods:
- Linux: Uses
netlinkor falls back to/sys/class/net/ - macOS: Uses
getifaddrs()system call - Windows: Uses
GetAdaptersInfo()from IP Helper API - All platforms: Falls back to pcap's
pcap_findalldevs()when native methods fail
Performance Considerations
Multi-threaded Processing
Packet processing is distributed across multiple threads (up to 4 by default, based on CPU cores). This enables:
- Parallel packet parsing and DPI analysis
- Better utilization of multi-core systems
- Reduced latency for high packet rates
Concurrent Data Structures
DashMap provides lock-free concurrent access with:
- Per-shard locking (16 shards by default)
- No global lock contention
- Read-heavy workload optimization
- Safe concurrent modifications
Batch Processing
Packets are processed in batches to improve cache efficiency:
- Multiple packets processed before context switching
- Reduced system call overhead
- Better CPU cache utilization
Selective DPI
Deep packet inspection can be disabled with --no-dpi for lower overhead:
- Reduces CPU usage by 20-40% on high-traffic networks
- Still tracks basic connection information
- Useful for performance-constrained environments
Configurable Intervals
Adjust refresh rates based on your needs:
- UI refresh: Default 1000ms (adjustable with
--refresh-interval) - Process enrichment: Every 2 seconds
- Cleanup check: Every 5 seconds
- Rate calculation: Every 1 second
Memory Management
Connection cleanup prevents unbounded memory growth:
- Protocol-aware timeouts remove stale connections
- Visual staleness warnings before removal
- Configurable timeout thresholds
Snapshot isolation prevents UI blocking:
- UI reads from immutable snapshots
- Background threads update DashMap concurrently
- No lock contention between UI and packet processing
Dependencies
RustNet is built with the following key dependencies:
Core Dependencies
- ratatui - Terminal user interface framework with full widget support
- crossterm - Cross-platform terminal manipulation
- pcap - Packet capture library bindings for libpcap/Npcap
- pnet_datalink - Network interface enumeration and low-level networking
Concurrency & Threading
- dashmap - Concurrent hashmap with fine-grained locking
- crossbeam - Multi-threading utilities and lock-free channels
- parking_lot - Efficient synchronization primitives (RwLock, Mutex)
Networking & Protocols
- dns-lookup - DNS resolution capabilities
- etherparse - Ethernet, IP, TCP, UDP packet parsing
- trust-dns-proto - DNS protocol parsing (for DPI)
Command-line & Logging
- clap - Command-line argument parsing with derive features
- simplelog - Flexible logging framework
- log - Logging facade
- anyhow - Error handling and context
Platform-Specific
- procfs (Linux) - Process information from /proc filesystem (runtime fallback)
- libbpf-rs (Linux) - eBPF program loading and management
- libbpf-sys (Linux) - Low-level libbpf bindings for eBPF
- windows-sys (Windows) - Windows API bindings for IP Helper API
Utilities
- arboard - Clipboard access for copying addresses
- num_cpus - CPU core detection for threading
- chrono - Date and time handling
- ring - Cryptographic operations (for TLS/SNI parsing)
- aes - AES encryption support (for protocol detection)
Security Considerations
Privileged Access
RustNet requires privileged access for packet capture:
- Raw socket access - Intercept network traffic at low level (read-only, non-promiscuous mode)
- BPF device access - Load packet filters into kernel
- eBPF programs - Optional kernel probes for enhanced process tracking (Linux only)
Mitigation:
- Use Linux capabilities instead of full root (CAP_NET_RAW for packet capture, CAP_BPF+CAP_PERFMON for eBPF)
- Use macOS group-based access (
access_bpfgroup) - Audit which users have packet capture permissions
- Operates in read-only mode - cannot modify or inject packets
Read-Only Operation
The tool only monitors traffic; it does not:
- Modify packets
- Block connections
- Inject traffic
- Alter routing tables
- Change firewall rules
Log File Privacy
Log files may contain sensitive information:
- IP addresses and ports
- Hostnames and SNI data
- Process names and PIDs
- DNS queries and responses
Best Practices:
- Disable logging by default (no
--log-levelflag) - Secure log directory permissions
- Implement log rotation and retention policies
- Review logs for sensitive data before sharing
No External Communication
RustNet operates entirely locally:
- No telemetry or analytics
- No network requests (except monitored traffic)
- No cloud services or remote APIs
- All data stays on your system
eBPF Security
When using experimental eBPF support:
- Requires additional kernel capabilities (
CAP_BPF,CAP_PERFMON) - eBPF programs are verified by kernel before loading
- Limited to read-only operations (no packet modification)
- Automatically falls back to procfs if eBPF fails
Audit and Compliance
For production environments:
- Audit logging of who runs RustNet with packet capture privileges
- Network monitoring policies and compliance with data protection regulations
- User access reviews for privileged network access
- Automated capability management via configuration management systems
Threat Model
What RustNet protects against:
- Unauthorized users cannot capture packets without proper permissions
- Capability-based permissions limit blast radius of compromise
What RustNet does NOT protect against:
- Users with packet capture permissions can see all unencrypted traffic
- Root/Administrator users can modify RustNet or capture packets directly
- Physical access to the machine enables packet capture
- Network-level attacks (RustNet is a monitoring tool, not a security appliance)
For detailed permission setup and security best practices, see INSTALL.md.