srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_summarize.cpp
AgeCommit message (Collapse)AuthorFilesLines
2026-05-31Add LLDP - dispatched by ethertype, no IP layer at allsrdusr1-2/+22
Real switches broadcast this every ~30s, but this project had zero treatment for it (0x88CC was previously the test suite's own example of an "unhandled ethertype"). Dispatched by ethertype the same way ARP is, since LLDP sits directly on Ethernet. TLV-encoded; only the three mandatory TLVs (Chassis ID, Port ID, TTL) plus System Name are rendered, while every other TLV is still walked over correctly so nothing after it is lost. Live-verified two ways, since this machine is on WiFi (LLDP isn't relayed to wireless clients even when a real switch sends it) with no LLDP daemon installed to generate traffic locally either: a 15-second passive capture confirmed no organic LLDP traffic exists to accidentally rely on, then a real 802.1AB frame was sent via a raw AF_PACKET socket onto the actual NIC (not fed directly to parse_lldp() in a unit test) and captured through the full pipeline, decoding correctly.
2026-05-29Fix IPv4/IPv6 fragment continuation data being decoded as fake transport headerssrdusr1-0/+28
A real correctness bug, not just missing visibility: a non-first fragment's payload is pure continuation data with no TCP/UDP/ICMP header in it at all, but it was being handed to the transport parsers unconditionally, which could misread arbitrary payload bytes as port numbers, sequence numbers, etc. and print a plausible-looking but entirely fake decode. IPv4 gained identification/more_fragments/fragment_offset fields; a nonzero offset now stops summarize_packet before transport dispatch, reporting the fragment instead. IPv6 expresses fragmentation as an extension header instead, so the fix lives in walk_ipv6_extension_headers(): it already walked past Fragment headers, but never checked the offset before continuing on as if a transport header followed - the same bug, reached through a different path. Fixed with an ESP-style hard stop on a nonzero offset. Caught and fixed a second bug while writing the first fix, before it ever ran: the fragment's Identification field was a loop-local variable, discarded the moment the walk continued past a *first* fragment (offset zero) to keep decoding the real payload underneath -- every later return reported no fragment id even though one applied. Fixed by hoisting it to a variable that persists across iterations, the same category of mistake as an earlier IGMPv3 bug. Fuzzed afterward regardless (fuzz_ipv4, fuzz_ipv6, fuzz_summarize, ~16.8M combined runs) - clean. Live-verified with a real 4000-byte ping to the local gateway over the actual 1500-MTU interface: both directions fragmented into 3 pieces each, the first decoded normally with a fragmentation note, and the continuation fragments correctly showed only fragment metadata, no fake ICMP decode attempted.
2025-11-19Add RTP/RTCP as a labeled heuristic fallback for unmatched UDP trafficsrdusr1-0/+30
Architecturally different from every other protocol added so far: RTP has no fixed well-known port at all - it's negotiated per call via SDP/SIP/WebRTC signaling this project doesn't parse - so L7Registry's port-keyed dispatch doesn't apply. Handled instead as a fallback tried only when a UDP packet's normal port-based lookup finds nothing, with every match labeled "?" (e.g. "RTCP? SR") to mark it as inferred from packet shape rather than certain - the same honesty Wireshark itself applies to heuristic dissection, which is off by default there for exactly this reason. The two heuristics aren't equally trusted, and the code says so: RTCP checks a narrow packet-type range (200-204) plus an exact self-declared length, both unlikely to occur by chance; RTP leans mostly on the 2-bit version field, since its other structural checks are trivially satisfied whenever those bits happen to be zero, the common case even for unrelated traffic. Shipped anyway - a labeled guess on real RTP/RTCP traffic is more useful than silence - but this is the first place in the project where a match doesn't mean certainty. Live-verified against genuine media traffic: ffmpeg streaming a real RTP video test pattern to loopback, correctly decoded with incrementing sequence numbers and a consistent SSRC across the stream, plus a real RTCP Sender Report ffmpeg sent alongside it.
2025-07-01Add FTP, SMTP, TFTP, and IGMP; fix an IGMPv3 group-address misparsesrdusr1-0/+22
FTP and SMTP share HTTP's line-based response-code-or-command shape but keep their own command vocabularies in separate files rather than sharing a parser. FTP passwords are shown as-is, not redacted - FTP sends them in the clear regardless, matching Wireshark's own behavior. TFTP is a small binary opcode protocol (RFC 1350) instead. IGMP sits directly on IP like ICMP, so it's dispatched by protocol number rather than through the port-keyed L7Registry the other three use. Live-verified: FTP/SMTP against minimal real TCP servers written for this (nothing installed locally), a full command/response exchange decoded correctly in both directions. TFTP against a real atftpd server and atftp client - the RRQ decoded correctly even though the transfer itself didn't complete (an atftpd sandbox issue, not this code). IGMP against real multicast traffic on wlp1s0, including a genuine query from the actual router. That live IGMP traffic caught a real bug before it shipped further: parse_igmp() read bytes[4:8] as a group address for every message type, but IGMPv3 reports use those bytes for Reserved+RecordCount instead - a real V3 report showed "group=0.0.0.1" (0 reserved, 1 record, misread as an IP). Fixed by only populating group for the types where it's genuinely an address; re-verified against the same live traffic, and a regression test locks in the exact pattern.
2025-06-26Unwrap VLAN (802.1Q/802.1ad) tags before protocol dispatchsrdusr1-0/+16
The single highest-value coverage gap so far, and structural rather than a new dissector: a VLAN-tagged frame's ethertype reads as 0x8100, so every existing decoder - ARP, IPv4, IPv6, and everything built on top of them - was completely invisible on any tagged network. walk_vlan_tags() (ethernet.hpp) is composable and separate from parse_ethernet(), the same relationship walk_ipv6_extension_headers() has to parse_ipv6(): the base parse stays an unconditional fixed-header decode, and this is what a caller reaches for when it needs the real protocol underneath. Handles stacked (QinQ) tags, bounded at 4 levels against a corrupt/hostile frame claiming an unbounded chain. Live-verified with genuine kernel-tagged frames, not synthetic bytes: a dummy0 interface with an 802.1Q dummy0.42 sub-interface (VLAN 42), captured on the parent while pinging out the sub-interface. Both interfaces and the kernel modules they pulled in were torn down afterward.
2024-05-28Add ARP decoding and bring the TUI up to -c/-a paritysrdusr1-3/+17
ARP had zero treatment until now - its ethertype just fell through summarize_packet's "not IPv4/IPv6" branch, on traffic that appears on essentially every real LAN capture. Scoped to Ethernet/IPv4 addressing (the case that covers virtually all real ARP traffic), with tcpdump's own "who-has X tell Y" / "X is-at Y" phrasing rather than inventing new wording. Live-verified by flushing this machine's real gateway ARP entry and capturing the resulting request/reply on wlp1s0. TUI -c/-a were being parsed into RenderOptions but silently did nothing: run_tui()'s consumer thread had its own loop that never read them, unlike plain-text mode's render_packet(). Fixed to match, and caught a real bug while doing it - pushing up to two rows per packet (summary + reassembly line) against a single pop_front() would let the row deque grow past its cap under sustained -a activity; needed a while loop instead. Verified under tmux against the same split-segment HTTP scenario used to verify -a on the CLI and GUI.
2024-05-27Rename project from wireframe to packeteersrdusr1-13/+13
Decided on the name after weighing alternatives in NAMES.md: packeteer (packet + -eer, "one who wields packets") fit the project's actual scope better than the wire/frame pun once it had grown into full L2-L7 dissection, reassembly, checksums, privilege dropping, and dual TUI/GUI frontends. No existing packet-capture project uses the name; the one real-world collision (Packeteer, Inc., a networking company acquired and folded into Blue Coat/Symantec by 2008) is long defunct. Mechanical rename throughout: CMake project/target names, the wireframe:: namespace and include/wireframe/ directory (git mv, history preserved), every #include path, CLI/GUI help text, and the project's own working directory. NAMES.md rewritten to record the decision instead of leaving stale self-referential etymology behind from the blind rename pass. Verified after every step: full rebuild (all four targets, no warnings) and the full test suite (128/128 cases, 366/366 assertions) both from a fresh reconfigure and again after the directory move.
2024-05-14Initial commit: wireframe packet capture/analysis toolsrdusr1-0/+185
Terminal packet capture and analysis tool built to learn the C++ memory model (byte layout, alignment, endianness, std::span over unowned buffers) via a real capture pipeline. - Hand-rolled L2-L4 decoders (Ethernet, IPv4, IPv6 with extension header walking, TCP, UDP) over std::span, no struct-casting - L7 dissector interface with DNS, HTTP, and TLS SNI implementations - pcapng read/write for Wireshark-compatible capture files - Bounded capture queue: drop-on-backpressure for live capture, blocking push for faithful file replay - Kernel-level BPF filtering (-f) and a separate display-only search (-g / interactive) that doesn't touch what's captured - Replay mode (-r) reads a saved pcapng file back through the same pipeline as live capture, no root or live device needed - pcap_stats() surfaces kernel/interface drops invisible to the capture queue's own counter - Three frontends sharing one CaptureSession setup path: CLI, TUI (FTXUI, primary), GUI (Dear ImGui + SDL3, secondary) - 89 unit tests (doctest) plus 9 libFuzzer harnesses covering every hand-rolled parser; fuzzing found and fixed a real OOM in the pcapng reader (unbounded allocation from an untrusted length field)