Download Latest Version RootWire 6.0.0 source code.zip (137.1 kB) Google Add to Preferred Sources
Home / v6.0.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-09 5.4 kB
RootWire 6.0.0 source code.tar.gz 2026-09-09 117.1 kB
RootWire 6.0.0 source code.zip 2026-09-09 137.1 kB
Totals: 3 Items   259.7 kB 0

RootWire's own dependency, NETProtocols, is bumped to its latest release (2.2.1); no source changes were needed — the only breaking change since RootWire's 1.3 floor (removal of Packet.payload) is a name RootWire never called.

Changed

  • BREAKING: Capture timestamps are now kernel-sourced nanoseconds end-to-end instead of a userspace time.time() reading. Live capture enables SO_TIMESTAMPNS and reads the kernel's own arrival timestamp via recvmsg's ancillary data instead of a time.time() call after recv returns, which included scheduler and interpreter latency between the frame's arrival and Python observing it. DecodedFrame.timestamp is now an int (nanoseconds since epoch), not a float (seconds). This changes two on-the-wire contracts: the NDJSON timestamp field is now an integer nanosecond value rather than a float epoch-seconds value, and -w now writes nanosecond-precision classic pcap files (magic 0xA1B23C4D) instead of microsecond-precision (0xA1B2C3D4) — a long-established pcap variant every major tool (Wireshark, tcpdump, tshark) already reads, and the only way the improved capture precision survives to disk. Replay (-r) still reads both precisions losslessly (#59).
  • BREAKING (library API): -i/--interface is now repeatable — -i eth0 -i wlan0 captures on both interfaces concurrently, merged into one decoded stream, each frame tagged with the interface it actually arrived on. Existing single-use invocations (-i eth0) are unaffected. Live capture is now backed by an asyncio event loop internally (one raw socket per requested interface, multiplexed via add_reader); the public rootwire.capture.capture() sync generator is replaced by rootwire.capture.capture_async(), an async generator with a different signature — a break only for code embedding RootWire as a library and calling capture() directly, not for any CLI usage (#61).

Added

  • --filter now also accepts arbitrary filter expressions (tcp and port 80, host 1.2.3.4, not arp, ...), compiled to cBPF by a small hand-rolled compiler — no libpcap dependency, keeping RootWire's zero-dependency, from-scratch posture. Supported grammar: protocols tcp/udp/icmp/arp/ip/ip6; host/port, each optionally prefixed with src/dst; and/or/not; parentheses — anything outside that grammar is a clear compile-time error, never a best-effort guess. Correctness is validated by interpreting both this compiler's output and real tcpdump -dd bytecode against the project's captured-frame corpus and asserting they always agree on accept/reject for every frame — not by matching tcpdump's exact instruction sequence, which its own decades-old peephole optimizer makes impractical to reproduce by hand past a single bare primitive (#63).
  • --filter {tcp,udp,arp,ip6}: attach a kernel-side classic-BPF (cBPF) filter to the capture socket (SO_ATTACH_FILTER), the same mechanism tcpdump itself uses, so non-matching frames are dropped in the kernel and never copied to userspace. This release ships a small, canned set of pre-compiled programs, each verified byte-for-byte against tcpdump -dd <expression>. Mutually exclusive with -r — replay has no socket to attach a kernel filter to (#62).
  • Diagnose IPv4 frames whose total_length is smaller than the header itself — a length field that cannot be correct. The frame is flagged [!] Malformed on screen, carries a malformed_length field in NDJSON output, and counts toward the statistics malformed tally; upper layers are still decoded and shown. A total_length of 0 is exempt, being the large-send offload (TSO) sentinel found in locally captured frames rather than corruption (#56).
  • Handle SIGTERM as a clean shutdown, the same as Ctrl-C: flush every output, print the stats summary, and exit 0. Previously only SIGINT was handled — a service manager's stop (or plain kill) hit Python's default disposition, which terminates immediately and skips output flushing entirely, losing the tail of a -w capture and the run summary (#60).

Security

  • Payload display (-d) now neutralizes terminal control characters. Packet payloads are attacker-controlled, and the previous rendering passed ESC and other control bytes straight to the terminal, allowing a crafted frame to inject ANSI escape sequences. Non-printable characters (C0/C1 controls, DEL, and Unicode format characters such as the bidirectional overrides) are now shown as visible \xNN/\uXXXX escapes; printable text and newlines are unchanged (#53).

Fixed

  • Refuse -r FILE -w FILE when both refer to the same file. The writer truncated its target before the lazy replay reader had read a byte, so replaying and writing the same path destroyed the capture; it is now rejected up front, before anything is opened (#52).
  • A -w target that cannot be opened (bad directory, permission denied) now reports a clear write-specific error instead of a raw traceback, and no longer risks being misreported as a capture-privilege problem (#54).
  • The end-of-run statistics summary is no longer printed while an unexpected exception is propagating, where it made a crash look like a clean run (#54).
Source: README.md, updated 2026-09-09