Files
rustnet/ARCHITECTURE.md
Marco Cadetg 4ae965a8a4 feat: remove CAP_NET_ADMIN and CAP_SYS_ADMIN, use read-only packet capture (#59)
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.
2025-10-19 17:03:58 +02:00

15 KiB

Architecture

This document describes the technical architecture and implementation details of RustNet.

Table of Contents

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/tcp and /proc/net/udp to 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 comm field)
    • May show thread names instead of full executable names
    • Multi-threaded applications show internal thread names
  • 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)

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 -P to 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 GetExtendedTcpTable and GetExtendedUdpTable from Windows IP Helper API
  • Retrieves connection tables with process IDs
  • Supports both IPv4 and IPv6 connections
  • Resolves process names using OpenProcess and QueryFullProcessImageNameW

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 netlink or 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_bpf group)
  • 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-level flag)
  • 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.