← Back to home

Systems tool

NetProbe

A packet visibility tool focused on threading, capture boundaries, protocol truthfulness, and failure visibility across platforms.

C++20 · Npcap · pcap · threads 2025 GitHub repo ↗

SUMMARY

Modern C++20 real-time and offline traffic analyzer with protocol decoding, QUIC/TLS inspection, enrichment, and a capture/parse/render threading model.

Problem

Packet tools need to keep capture, parsing, and rendering from blocking each other while still showing what a machine is actually doing on the network.

What I built

I built a C++20 analyzer for live and offline traffic, with capture, parsing, filtering, enrichment, and rendering staged across a thread-safe pipeline.

Architecture / system design

The key architecture is capture -> parser -> renderer, connected with ownership boundaries and shutdown behavior that keep the UI/control loop from blocking packet capture.

Failure modes / what broke

The page calls out protocol-specific limits, especially around QUIC v1/v2 SNI extraction, where passive observation runs into cryptographic reality. Encrypted tunnels (ESP/IPsec, WireGuard, OpenVPN) and encrypted DNS (DoH/DoT/DoQ, ECH) are labeled honestly rather than misreported.

Proof / metrics / tests

The proof is functional scope rather than a throughput claim: live capture, offline pcap flow, threaded processing, and documented protocol boundaries.

Lessons learned

Low-level visibility tooling is as much about honest limits as clever parsing; some data is not available without changing the trust or decryption model.

field notes

Expanded field notes

THE THREADING LESSON

A systems tool for understanding network behavior: latency, hosts a machine is talking to, packet shapes, failure visibility. The threading model is the real lesson — the thread that draws pixels can never wait on the thread that reads the wire, or the tool freezes exactly when you need it most.

A real-time and offline traffic analyzer in modern C++. NetProbe captures live traffic through Npcap on Windows and libpcap on Linux/macOS — and replays offline .pcap/.pcapng — decoding the full stack: Ethernet, VLAN/QinQ, IPv4/IPv6 (with extension headers), TCP/UDP, ARP, ICMP/ICMPv6, and SCTP, plus named non-IP frames (LLDP, EAPOL, PPPoE, MPLS). It descends transparently through GRE, IP-in-IP, 6in4, VXLAN, GENEVE, MPLS, and PPPoE tunnels, while encrypted tunnels (ESP/IPsec, WireGuard, OpenVPN) are labeled instead of misreported. On the application layer it pulls TLS SNI on any port (reassembling ClientHellos split across TCP segments), QUIC v1 and v2 SNI, HTTP Host headers, and full DNS/mDNS records (A/AAAA/CNAME/PTR/SRV/TXT/HTTPS/SVCB), and flags encrypted DNS (DoH/DoT/DoQ, ECH). Everything renders through a Dear ImGui dockspace with ImPlot charts. Beyond raw frames it aggregates bidirectional flows, measures initial TCP RTT from the SYN / SYN-ACK delta, resolves GeoIP/ASN against GeoLite2 via libmaxminddb, and identifies the owning process per endpoint (Windows iphlpapi, Linux /proc, macOS proc_pidfdinfo).

Packets arrive in bursts far faster than any UI can draw. The architecture is a multi-threaded producer–consumer pipeline using std::jthread: a capture thread pushes PacketData into a bounded thread-safe queue (std::mutex + std::condition_variable, drop-oldest on overflow with a separate dropped-packet counter), parser workers drain it, and the ImGui render thread reads parsed summaries each frame. The render thread never touches the wire.

DESIGN NOTE

The rule that shaped everything: the thread that draws pixels must never wait on the thread that reads the wire. Decoupling them is the difference between a tool engineers trust during a traffic spike and one that freezes exactly when it matters.

HOW THE QUIC TRICK WORKS

QUIC v1 and v2 ClientHello SNI extraction isn't passive observation — it's cryptographic recovery. The connection's DCID seeds HKDF-SHA256 to derive packet-protection keys; AES-128-ECB strips header protection; AES-128-GCM decrypts the Initial payload; CRYPTO frames are reassembled into a TLS ClientHello and the SNI is read from the extensions. All driven through mbedTLS. The point: SNI is still observable over UDP/443 if you're willing to do the work the connection setup hasn't hidden yet.

60
unit + integration tests (gtest)
3
platform CI matrix (Win/Linux/macOS)
CI ✓
libfuzzer · ASan · UBSan
NetProbe threading architecture nic capture thread npcap queue drop-oldest parser parser parser imgui render thread never blocks on capture std::jthread pipeline
fig. 5 — producer–consumer pipeline. Bounded drop-oldest queue between capture and parser workers; the render thread reads parsed summaries each frame and never touches the wire.

hover or tab through any stage to trace the pipeline

contact

Open to backend systems, AI infrastructure, and product engineering roles.