Lightweight TCP connection health monitor for systems that require fast detection of degraded, stale, or silently dead network paths. Cerberus evaluates connection stability using an application event-driven sampling model, applying statistical metrics over a sliding window of recent observations. The primary goal is to detect early symptoms of failure within one to two seconds when possible, while maintaining a minimal monitoring footprint.
Traditional TCP monitoring surfaces only coarse indicators such as connection up/down state or kernel-level retransmissions. These signals often lag behind real degradations. Cerberus provides a higher-resolution, application-level view of connection quality by computing derived metrics from message-level timing and behavior. This enables early detection of latency spikes, stalls, zombie connections, and silent failure modes that kernel TCP does not surface quickly enough.
- Dynamic Socket Monitoring - Specify monitoring targets per API request (no restart needed)
- Sub-10ms Response Time - Fast enough for real-time decision making
- Zero Dependencies - Standalone binary with embedded HTTP server
- Multi-Factor Health Scoring - Queue analysis, RTT, retransmissions, trend detection
- No Root Required - Uses
/proc/net/tcp,/proc/net/tcp6, and Linux INET_DIAG protocol via Netlink
Perfect for systems sending 1-2KB messages where:
- Every message matters (payment processing, trading systems)
- Latency is critical (<200ms expected delivery)
- Connection health directly impacts reliability
- Nginx reverse proxy to external clients
- Message queue producers checking broker connections
- API gateways sending to microservices
- Real-time notification delivery systems
- Real-time monitoring of TCP connections in low-latency applications
- Large file transfers (use different thresholds)
- Connections with expected high buffering
- Non-TCP protocols
Before building and running Cerberus, ensure you have:
-
Rust: Version 1.85 or higher
# Check your version cargo --version -
Operating System: Linux with kernel 3.10+ (RHEL 7+)
- RHEL 7 (kernel 3.10): May require root or CAP_NET_ADMIN for netlink features
- RHEL 8/9 (kernel 4.18+): No root required, all features work
- macOS: Code compiles but monitoring features are disabled (development/testing only)
All Rust dependencies are automatically handled by Cargo:
serde+serde_json- JSON serializationparking_lot- Fast RwLock implementation for concurrencythreadpool- HTTP server worker thread managementctrlc- Graceful shutdown handlinglibc- Linux syscalls (Netlink, socket operations)
- Active TCP connections required for functional testing
iperf3recommended for local testing (see Development Setup)
cd cerberus
cargo build --release
# Run on default port 8888
./target/release/cerberus
# Run on custom port
./target/release/cerberus 9000curl -X POST http://localhost:8888/monitor \
-H "Content-Type: application/json" \
-d '{
"local_ip": "10.0.1.5",
"local_port": 80,
"remote_ip": "93.184.216.34",
"remote_port": 443
}'Response:
{
"timestamp": 1764639861743,
"found": true,
"connection": {
"local_address": "192.168.21.201:5201",
"remote_address": "192.168.18.100:51555",
"state": "ESTABLISHED",
"state_code": 1,
"send_queue_bytes": 612612,
"recv_queue_bytes": 0
},
"tcp_metrics": {
"rtt_ms": 48.186,
"rtt_var_ms": 1.8,
"bytes_sent": 238591584,
"bytes_retrans": 84546,
"congestion_window": 53,
"unacked_packets": 53,
"retrans_events": 0,
"min_rtt_ms": 41.595,
"delivery_rate_bps": 1553220,
"rwnd_limited_us": 55000,
"busy_time_us": 116154000,
"total_retrans": 61,
"snd_ssthresh": 48,
"pmtu": 1500
},
"health": {
"status": "STALE",
"score": 23,
"safe_to_send": false,
"reasons": "CRITICAL: Send queue >= 4KB (2+ messages stuck); Active retransmissions detected; Retransmit rate: 0.04%; Data queued with unacked packets (stalling); Unacked > 70% of cwnd (congestion); Queue growing trend detected; Queue already elevated + growing; Queue persistently high for 10 consecutive samples; Queue accelerating (967 bytes/sec²)",
"trend_metrics": {
"send_queue_velocity": 2400.479290592875,
"recv_queue_velocity": 0.0,
"send_queue_acceleration": 967.495327955306,
"recv_queue_acceleration": 0.0,
"send_queue_variance": 82158.8253606393,
"recv_queue_variance": 0.0,
"send_queue_ma_short": 474936.0,
"send_queue_ma_long": 474843.6,
"send_queue_persistent": true,
"send_queue_high_count": 10,
"queue_growing": true,
"queue_shrinking": false,
"high_volatility": false,
"sample_count": 10,
"stale_suspect_send": {
"value": false,
"explanation": "Send-side active (0ms since last data sent, threshold: 1500ms)"
},
"stale_suspect_recv": {
"value": false,
"explanation": "Recv-side active (1ms since last ACK, threshold: 1500ms)"
},
"stale_confirmed_send": {
"value": false,
"explanation": "Send-side OK (0ms since last data sent, threshold: 3000ms)"
},
"stale_confirmed_recv": {
"value": false,
"explanation": "Recv-side OK (1ms since last ACK, threshold: 3000ms)"
},
"half_open_suspect": {
"value": false,
"explanation": "Connection responsive (last ACK: 1ms ago, 53 unacked bytes)"
},
"half_open_confirmed": {
"value": false,
"explanation": "Connection not half-open (ACKs being received normally)"
},
"loss_detected": {
"value": true,
"explanation": "CRITICAL: 1 packet retransmission(s) detected in window. For ~1KB messages, this adds RTT delay and indicates connection issues."
},
"loss_rate_pct": {
"value": 0.0697350069735007,
"explanation": "Loss rate 0.07% (1386 bytes lost of 1987524 sent, threshold: 1.0%)"
},
"rtt_drift": {
"value": 1.1584565452578435,
"explanation": "RTT drift 1.2x baseline (48.19ms current vs 41.59ms min, threshold: 3.0x)"
},
"jitter_index": {
"value": 0.03735524841240194,
"explanation": "Jitter 0.04 (1.80ms variance / 48.19ms RTT, threshold: 0.35)"
},
"recv_limited_pct": {
"value": 0.0,
"explanation": "Receiver OK: 0.0% rwnd-limited (threshold: 40%)"
},
"sender_limited_pct": {
"value": 0.0,
"explanation": "Sender OK: 0.0% sndbuf-limited (threshold: 40%)"
},
"congestion_suspected": {
"value": true,
"explanation": "Congestion suspected (early warning): cwnd decreased from 60 to 53 segments, 1 retransmissions in window. Watch connection closely."
},
"congestion_confirmed": {
"value": false,
"explanation": "Not congested (cwnd 53 >= ssthresh 48)"
},
"rto_inflation": {
"value": 5.167476030382269,
"explanation": "RTO INFLATED: 5.2x RTT (249ms RTO vs 48.19ms RTT, threshold: 4.0x). TCP expects packet loss - connection near failure."
}
}
}
}curl -X POST http://localhost:8888/monitor \
-H "Content-Type: application/json" \
-d '{
"local_ip": "10.0.1.5",
"local_port": 80,
"remote_ip": "93.184.216.34"
}'Returns array of all connections from local_ip:local_port to remote_ip, sorted by health (worst first).
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Upstream │─────▶│ Nginx │─────▶│ Client │
│ App │ │ (Proxy) │ │ (External) │
└──────┬──────┘ └──────────────┘ └─────────────┘
│
│ HTTP API
▼
┌─────────────────────────────────────────┐
│ Cerberus │
│ ┌─────────────┐ ┌────────────────┐ │
│ │ /proc/net/ │◀───│ Health │ │
│ │ tcp │ │ Assessor │ │
│ └─────────────┘ └────────────────┘ │
│ ┌─────────-----────┐ │
│ │ Linux INET_DIAG │ │
│ └──────────-----───┘ │
└─────────────────────────────────────────┘
Cerberus consists of three layers: event ingestion, metrics engine, and API.
+-----------------------------+
| External Application |
| Emits message-level events |
+--------------+--------------+
|
v
+-----------------------------+
| Event Ingestion Layer |
| Parses samples and updates |
| the sliding window |
+--------------+--------------+
|
v
+-----------------------------+
| Sliding Window Engine |
| Maintains last N samples, |
| computes all derived metrics|
+--------------+--------------+
|
v
+-----------------------------+
| Metrics API |
| Query current metrics, JSON |
| output, thresholds, alerts |
+-----------------------------+
# Default port 8888
./cerberus
# Custom HTTP port
./cerberus 9000All API requests to /monitor must specify the monitoring target:
{
"local_ip": "10.0.1.5", // REQUIRED - Local IP to monitor
"local_port": 80, // REQUIRED - Local port to monitor
"remote_ip": "93.184.216.34", // REQUIRED - Remote IP to match
"remote_port": 443, // optional - omit to match all ports
"established_only": true, // optional, default: true
"sort_by_health": true // optional, default: true
}| Status | Score | Safe to Send | Description | Common Causes |
|---|---|---|---|---|
| HEALTHY | 0-1 | Yes | Normal operation | All metrics optimal |
| CAUTION | 1-2 | Yes | Monitor closely | Slight RTT elevation, minor queue buildup |
| SUSPECT | 3-4 | Maybe | Potential issues | Moderate RTT or queue, retransmission events |
| DEGRADED | 5-6 | No | Connection struggling | Send queue ≥2KB, high unacked ratio |
| STALE | 7+ | No | Connection broken | Critical send queue, active retransmissions, severe RTT |
Cerberus evaluates multiple factors:
-
Send Queue Size - Bytes stuck in kernel send buffer (indicates bottleneck)
- HEALTHY: <1KB
- CAUTION: 1-2KB (partial message stuck)
- SUSPECT: 2KB+ (full message stuck)
- DEGRADED: 4KB+ (2+ messages stuck)
-
Round Trip Time (RTT) - Network latency to remote peer
- HEALTHY: <200ms
- CAUTION: 200-500ms
- SUSPECT: 500ms-1s
- STALE: >1s
-
Retransmissions - Packet loss and recovery attempts
- Active retransmissions → STALE (no data flowing)
- Recent retransmission events → SUSPECT (network unreliable)
-
Unacked Packet Ratio - Congestion window utilization
-
70% of CWND → DEGRADED (severe congestion)
-
50% of CWND → CAUTION (moderate congestion)
-
| Metric | Field | Unit | Available Since | What It Tells You |
|---|---|---|---|---|
| RTT | tcpi_rtt | microseconds | Kernel 3.10+ (RHEL 7+) | Network latency to peer |
| RTT Variance | tcpi_rttvar | microseconds | Kernel 3.10+ (RHEL 7+) | Latency stability/jitter |
| Bytes Sent | tcpi_bytes_sent | bytes | Kernel 5.5+ (RHEL 9+) | Total data transmitted |
| Bytes Retransmitted | tcpi_bytes_retrans | bytes | Kernel 5.5+ (RHEL 9+) | Data loss amount |
| Congestion Window | tcpi_snd_cwnd | packets | Kernel 3.10+ (RHEL 7+) | Send capacity |
| Unacked Packets | tcpi_unacked | packets | Kernel 3.10+ (RHEL 7+) | In-flight data |
| Retrans Events | tcpi_retrans | count | Kernel 3.10+ (RHEL 7+) | Current retransmits |
Performance & Throughput Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Minimum RTT | tcpi_min_rtt | microseconds | Kernel 4.6+ (RHEL 8+) | Baseline latency - best possible performance to this peer |
| Delivery Rate | tcpi_delivery_rate | bytes/sec | Kernel 4.6+ (RHEL 8+) | Actual throughput - real data delivery speed |
| Pacing Rate | tcpi_pacing_rate | bytes/sec | Kernel 4.2+ (RHEL 8+) | Send rate limit - how fast kernel is pacing sends |
| Max Pacing Rate | tcpi_max_pacing_rate | bytes/sec | Kernel 4.2+ (RHEL 8+) | Maximum allowed send rate. |
| Bytes Acked | tcpi_bytes_acked | bytes | Kernel 4.2+ (RHEL 8+) | Successfully delivered data. |
| Bytes Received | tcpi_bytes_received | bytes | Kernel 4.2+ (RHEL 8+) | Total data received |
Bottleneck Detection Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Busy Time | tcpi_busy_time | microseconds | Kernel 4.9+ (RHEL 8+) | Time with data in flight - % utilization |
| RWND Limited Time | tcpi_rwnd_limited | microseconds | Kernel 4.9+ (RHEL 8+) | Receiver bottleneck - peer can't keep up |
| SNDBUF Limited Time | tcpi_sndbuf_limited | microseconds | Kernel 4.9+ (RHEL 8+) | Application bottleneck - you're not sending fast enough |
| Not Sent Bytes | tcpi_notsent_bytes | bytes | Kernel 4.6+ (RHEL 8+) | Queued but not sent - internal buffering |
Loss & Recovery Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Lost Packets | tcpi_lost | packets | Kernel 3.10+ (RHEL 7+) | Packet loss count |
| SACKed Packets | tcpi_sacked | packets | Kernel 3.10+ (RHEL 7+) | Selective ACK'd packets - partial recovery |
| Total Retrans | tcpi_total_retrans | count | Kernel 3.10+ (RHEL 7+) | Lifetime retransmissions |
| Reordering | tcpi_reordering | packets | Kernel 3.10+ (RHEL 7+) | Packet reorder metric |
| Reordering Seen | tcpi_reord_seen | count | Kernel 5.5+ (RHEL 9+) | Reordering events |
| Out-of-Order Packets | tcpi_rcv_ooopack | packets | Kernel 5.8+ (RHEL 9+) | Receive side reordering |
| DSACK Duplicates | tcpi_dsack_dups | packets | Kernel 5.5+ (RHEL 9+) | Duplicate SACKs - spurious retrans detection |
Congestion Control Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| CA State | tcpi_ca_state | enum | Kernel 3.10+ (RHEL 7+) | Congestion state (0=Open, 1=Disorder, 2=CWR, 3=Recovery, 4=Loss) |
| Send Threshold | tcpi_snd_ssthresh | packets | Kernel 3.10+ (RHEL 7+) | Slow start threshold |
| Receive Threshold | tcpi_rcv_ssthresh | packets | Kernel 3.10+ (RHEL 7+) | Receive slow start threshold |
| Backoff | tcpi_backoff | multiplier | Kernel 3.10+ (RHEL 7+) | Exponential backoff level |
Segment & MSS Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Send MSS | tcpi_snd_mss | bytes | Kernel 3.10+ (RHEL 7+) | Max segment size - MTU related |
| Receive MSS | tcpi_rcv_mss | bytes | Kernel 3.10+ (RHEL 7+) | Peer's max segment size |
| Path MTU | tcpi_pmtu | bytes | Kernel 3.10+ (RHEL 7+) | Path MTU discovery result |
| Advertised MSS | tcpi_advmss | bytes | Kernel 3.10+ (RHEL 7+) | MSS advertised to peer |
| Segments Out | tcpi_segs_out | count | Kernel 4.2+ (RHEL 8+) | Total segments sent |
| Segments In | tcpi_segs_in | count | Kernel 4.2+ (RHEL 8+) | Total segments received |
| Data Segments Out | tcpi_data_segs_out | count | Kernel 4.6+ (RHEL 8+) | Data-carrying segments sent |
| Data Segments In | tcpi_data_segs_in | count | Kernel 4.6+ (RHEL 8+) | Data-carrying segments received |
Timing & Timeout Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| RTO | tcpi_rto | microseconds | Kernel 3.10+ (RHEL 7+) | Retransmit timeout |
| ATO | tcpi_ato | microseconds | Kernel 3.10+ (RHEL 7+) | ACK timeout |
| Last Data Sent | tcpi_last_data_sent | milliseconds | Kernel 3.10+ (RHEL 7+) | Time since last data - idle detection |
| Last ACK Received | tcpi_last_ack_recv | milliseconds | Kernel 3.10+ (RHEL 7+) | Time since last ACK |
| Last Data Received | tcpi_last_data_recv | milliseconds | Kernel 3.10+ (RHEL 7+) | Time since peer sent data |
Window & Buffer Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Receive Window | tcpi_rcv_space | bytes | Kernel 3.10+ (RHEL 7+) | Receive buffer size |
| Receive RTT | tcpi_rcv_rtt | microseconds | Kernel 3.10+ (RHEL 7+) | Receiver's RTT estimate |
| Send Window | tcpi_snd_wnd | bytes | Kernel 5.8+ (RHEL 9+) | Advertised send window |
ECN & Delivery Metrics
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| Delivered Packets | tcpi_delivered | packets | Kernel 5.5+ (RHEL 9+) | Data packets delivered |
| Delivered CE | tcpi_delivered_ce | packets | Kernel 5.5+ (RHEL 9+) | ECN-marked packets delivered |
State & Options
| Metric | Field | Unit | Available Since | Why You'd Want This |
|---|---|---|---|---|
| TCP State | tcpi_state | enum | Kernel 3.10+ (RHEL 7+) | Connection state (1=ESTABLISHED, etc.) |
| TCP Options | tcpi_options | bitmap | Kernel 3.10+ (RHEL 7+) | Enabled options (timestamps, SACK, window scale) |
| Window Scales | tcpi_snd_wscale / tcpi_rcv_wscale | bits | Kernel 3.10+ (RHEL 7+) | Window scaling factors |
| Probes | tcpi_probes | count | Kernel 3.10+ (RHEL 7+) | Zero-window probes sent |
| Retransmits | tcpi_retransmits | count | Kernel 3.10+ (RHEL 7+) | Number of retransmit attempts |
Health Check - Verify service is running
curl http://localhost:8888/health
# Response: {"status": "ok"}Configuration - Show server info
curl http://localhost:8888/config
# Response: {
# "http_server_info": "Cerberus TCP Monitor vx.x.x - Dynamic socket monitoring per request",
# "monitor_per_request": true
# }git clone https://github.com/SergiyBabenkov/cerberus.git
cd cerberus
# Development build (default, uses netlink)
cargo build
# Release build with optimizations
cargo build --release
# Run tests
cargo test
# Run linter
cargo clippy
# Format code
cargo fmt# Run with default port (8888)
cargo run
# Run with custom port
cargo run -- 9000
# Run release build
./target/release/cerberus
# Production deployment with custom port
./target/release/cerberus 9000Built for high-frequency message delivery systems where reliability matters. Inspired by the need for sub-second stale connection detection in financial transaction processing.