RootWire: a decoded network traffic monitor for Linux
RootWire: A network traffic monitor for GNU/Linux — Live Capture, PCAP Replay, NDJSON Output. Formerly Packet-Sniffer.
At a glance
- What is it?
- RootWire captures frames from one or more interfaces with a raw socket, timestamps them in the kernel, decodes each protocol layer with the NETProtocols library, and renders them live, writes them to pcap or streams them as NDJSON. The project was formerly called Packet-Sniffer, and the release history shows the rename, the version jumps and the language change all in a single month.
- Who is it for?
- RootWire suits someone who needs to read their own traffic rather than just filter it, a Linux operator debugging a network problem who wants the decoded options and a verified checksum rather than a hex dump, and a pipeline that wants NDJSON on stdout instead of a pcap file. It is the wrong tool on a non-Linux host, since only the raw socket path is Linux specific, and the wrong choice for bulk capture where the kernel filter and pcap writing of a mature tool is enough.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the tool does and how it presents a frame
RootWire is a network traffic monitor for GNU/Linux, formerly known as Packet-Sniffer. The README describes the pipeline in one paragraph. Frames are captured from one or more network interfaces with a raw socket, timestamped by the kernel itself, decoded layer by layer with the NETProtocols library, and rendered live, written to nanosecond-precision pcap, or streamed as JSON.
The live rendering is the part that distinguishes it from a hex dump, and the README shows what a frame looks like.
[>] Frame #4 at 15:42:07 (wlan0, 74 bytes)
[+] Ethernet 3c:7c:3f:1a:be:22 -> 9c:1e:95:aa:01:5f
EtherType: IPv4
[+] IPv4 192.168.1.96 -> 142.250.79.78
TTL: 64 | Flags: Don't fragment (DF) | Total Length: 60 | ID: 39754
Protocol: TCP | Checksum: 0x2b51
[+] TCP 51888 -> 443
Flags: 0x002 (SYN) | Seq: 3598801521 | Ack: 0
Window: 64240 | Checksum: 0x2008
Options: Maximum Segment Size (1460), SACK Permitted, Timestamps (3644437524, 0), No-Operation, Window Scale (7)The TCP options line is the clearest illustration of what the decoder does. Maximum segment size, selective acknowledgement permitted, timestamps, no-operation and window scale are all named and given their values, which is the level of detail that makes a capture useful for diagnosing a performance problem rather than merely proving that traffic existed.
The licence field on the repository says AGPL-3.0, the primary language is Python, and the homepage points at the GitHub repository.
The decoder coverage and the checksum verification
The protocol coverage is listed precisely, and the detail level in the listing tells you how seriously the decoder is taken.
Ethernet with 802.1Q VLAN tags including nested QinQ tagging. ARP. IPv4 with decoded options and fragments. IPv6 including extension headers, where an MLD report renders its full Hop-by-Hop chain, and Neighbor Discovery, where a Router or Neighbor Solicitation or Advertisement shows its target address and link-layer options. ICMPv4 and v6. TCP with options-aware payload offsets and decoded options. And UDP.
The checksum behaviour is the feature that makes this more than a pretty printer. Every IPv4, ICMPv4, ICMPv6, TCP and UDP checksum is verified against a recomputation, and a mismatch is flagged inline.
The README explains why that matters, and it is a careful distinction. A mismatch is a real signal for corrupted or spoofed traffic, and it is silent for a non-reassembled fragment, where the wire checksum covers a datagram the tool never rebuilds. So the absence of a warning is not itself a guarantee, and the tool does not pretend otherwise.
The robustness story is the last part of that paragraph and it is the most reassuring. Malformed or truncated frames are diagnosed instead of crashing the capture, unknown protocols end the chain gracefully, and a 16-layer cap keeps crafted extension-header stacks from amplifying. The capture survives whatever the network delivers, which for a tool that sees hostile traffic by definition is the property that matters most.
Installing it and the command line
Installation is a single command, and the tool is packaged for pipx or uv.
pipx install rootwire # or: uv tool install rootwireFrom a clone it is uv as well.
git clone https://github.com/EONRaider/RootWire.git
cd RootWire
uv syncThe command line is short and every option does one thing.
rootwire [-h] [-i INTERFACE] [-r FILE] [-w FILE]
[--filter NAME_OR_EXPR] [--json] [-d] [--version]The -i option selects the interface and can be repeated to capture on several interfaces concurrently, with all interfaces the default. The -r option replays frames from a pcap or pcapng file instead of capturing live, needs no privileges, and is mutually exclusive with -i. The -w option additionally writes every captured frame to a classic pcap file. The --json option emits one NDJSON object per frame on stdout, with the banner and statistics staying on stderr so the stream can be piped straight into jq. The -d flag adds the raw payload of each frame and is ignored under --json.
The --filter option is the one with the most detail, because it attaches a kernel-side capture filter so that only matching frames reach userspace. It accepts a canned name such as arp, ip6, tcp or udp, or a filter expression. The expression grammar covers the protocols tcp, udp, icmp, arp, ip and ip6, host and port each optionally prefixed with src or dst, the operators and, or and not, and parentheses, with the example tcp and port 80.
Kernel-side filtering and the statistics output
The point of the filter option is that the work happens in the kernel, not in Python, and the README's example commands show the difference in behaviour.
sudo rootwire -i eth0 -w session.pcap # capture and keep the evidence
sudo rootwire -i eth0 --filter tcp # drop non-TCP in the kernel
sudo rootwire -i eth0 --filter "tcp and port 80" # kernel-side filter expression
sudo rootwire -i eth0 -i wlan0 # merge two interfaces into one stream
rootwire -r session.pcap # inspect it later, no root
rootwire -r session.pcap --json | jq . # machine-readable analysisThe last two lines are the ones that change the workflow. Capturing with -w keeps the evidence on disk, and then -r replays it later with no privileges at all, so the analysis happens on a machine or an account that has no root. A pipeline can capture once under privilege and then run as many analyses as needed over the same file.
The statistics are reported on stderr when the capture ends, and they cover frames, bytes, frames per second, malformed and truncated counts and per-protocol tallies. The README notes that the shutdown is the same in all three cases, whether that is Ctrl-C, SIGTERM or, for -r, the end of the file, and that all three trigger a clean shutdown. That is a small detail and a good one, since a monitor that dies on SIGTERM without reporting what it saw has lost the numbers you wanted.
The privacy and permission model is on the raw socket. Live capture needs root, or the interpreter can be granted the CAP_NET_RAW capability instead, and replaying from a file never needs privileges.
The architecture and why memory stays flat
The How it works section is a short architectural tour and the ARCHITECTURE.md file has the long version.
The capture function yields raw frames, merged from one AF_PACKET socket per interface, each timestamped by the kernel itself at arrival using SO_TIMESTAMPNS rather than a userspace clock read. That distinction matters more than it looks: a userspace timestamp is taken after the frame has been copied up and after the scheduling delay of the reading process, so it is only approximately when the frame arrived. The kernel timestamp is the arrival time.
Replaying from a file with -r adapts the pcap module's frames into the same shape before either source reaches the decoder, which walks each frame's protocol chain into an immutable DecodedFrame object. The outputs, the screen renderer, the NDJSON stream, the pcap writer and the statistics collector, all consume every frame through one small Output interface. ARCHITECTURE.md covers the full tour, including why memory stays flat during long captures and how to add an output.
The flat memory claim is the one worth interrogating, because a long capture is exactly where a naive implementation grows without bound. The answer implied by the architecture is that a frame is decoded, handed to the outputs and then discarded, and the outputs do not retain references to it.
The test suite is where the design pays off. Everything except the raw socket runs on any operating system, so the tests need neither root nor Linux, and they include a 65-frame corpus of real captured traffic replayed through the whole pipeline.
uv run pytestThat is a meaningful test design for a network tool, because it means the decoder and the outputs are testable on a laptop and on a CI runner.
Where RootWire is the wrong choice
The first limitation is the platform split. The project is for GNU/Linux, the classifier in the package metadata says POSIX Linux, and the raw socket path is Linux specific. The rest of the tool is portable, which is good for testing, but the capture itself is not.
The second is that this is a monitor, not a filter for bulk traffic. The kernel-side filter helps, and the pcap writer keeps the evidence, but for sustained high-volume capture a mature packet capture tool with hardware acceleration and disk-oriented design is the better instrument. RootWire is written for reading traffic, not for moving it to spinning disk at line rate.
The third is the rename history, which is worth understanding before you depend on it. The project was formerly known as Packet-Sniffer, and the release history shows it in the space of about two weeks: v4.1.0 was published as packet-sniffer 4.1.0 on 2026-08-29, v5.0.0 as RootWire 5.0.0 the same day, and v6.0.0 on 2026-09-09. The description also says formerly Packet-Sniffer. A project that renames itself and jumps a major version in a fortnight is a project in the middle of something, and any documentation, scripts or links referring to the old name will be stale.
The fourth is the Python performance floor. The decoder is pure Python, and a Python decoder on a busy interface will be the bottleneck before the network is.
The fifth is the legal and ethical surface, which the README addresses at length with a disclaimer stating that using the code against targets without prior mutual consent is illegal and that it is the end user's responsibility to obey all applicable local, state and federal laws, and that the developers assume no liability. A tool that reads other people's traffic has a legitimate use in defensive work and an illegitimate one, and the disclaimer does not change the capability.
How RootWire compares with tcpdump, Wireshark and tshark
The comparison with tcpdump is the reference point, and the difference in approach is what happens after the frame is captured. tcpdump matches a filter and prints a summary line; it does not decode the payload options or verify the checksum. RootWire does the full decode and the checksum recomputation, and flags a mismatch inline, so the same capture answers a different question.
The cost is that tcpdump is C and decades old, and it will keep up with a busy link in a way a pure Python decoder will not. The practical combination is to capture with one and read with the other, and RootWire supports that directly through the -w and -r options.
Wireshark is the comparison for the interactive case, and it is the more complete tool: a graphical analyser with a full dissection engine and a filter language, and a tshark command line counterpart. The difference in approach is that Wireshark is a desktop application built around a dissector engine in C and C++, and RootWire is a small Python program with a decoder built on the NETProtocols library, whose own README describes it as decoding layer by layer.
The fourth comparison is with a JSON-producing capture tool, since that is what --json is for. A pcap file is a closed format with a schema you have to know, and NDJSON is a stream you can pipe into jq or into a log pipeline. The README's example of piping into jq is the point, and the choice to keep the banner and statistics on stderr is what makes the stdout stream clean enough to consume.
The fifth is the closest in spirit to the tool itself, which is a network monitoring tool in the observability sense, a periodic sample of flows rather than a full capture. RootWire does not do that, and the difference is that a flow sample is a summary of who talked to whom while RootWire shows you the actual bytes and their decoded fields.
Licence, project state and what to check before you capture
The licence field on the repository says AGPL-3.0, and the package metadata records AGPL-3.0-or-later with the LICENSE file listed in license-files. AGPL is a strong copyleft licence with a network clause, so if you modify the tool and run it as a service for others, you owe them the source. For a network tool that people might be tempted to deploy as a service, that clause is the part to read carefully.
The package requires Python 3.12 or newer, with classifiers for 3.12, 3.13 and 3.14, and the development status is Production/Stable. The single runtime dependency is netprotocols at 2.2 or later and below 3, which is the author's own decoding library, and the console script is rootwire pointing at the CLI entry point.
The tooling is thorough for a project of this size. Ruff with a line length of 80 and a broad rule selection, mypy in strict mode over the src directory, pytest with coverage reporting that shows missing lines, and hatchling as the build backend. There is a uv.lock for reproducible environments, a CHANGELOG.md, a SECURITY.md, a CONTRIBUTING.md that covers the development setup and the checks CI runs, an ARCHITECTURE.md, and a benchmarks/ directory.
Four things to check before you point it at a network.
The privilege model. Live capture needs root or the CAP_NET_RAW capability on the interpreter, and granting the capability to a Python interpreter is worth understanding before you do it, since a Python process with that capability can open raw sockets.
The filter syntax, and whether the canned names cover your case, because the expression grammar is a subset of what a full BPF compiler accepts.
The fact that the checksum verification is a recomputation and not a validation against a reference, and that it is silent on fragments, so a clean capture is not the same as a clean network.
And the rename, so that any script or documentation you write refers to rootwire and the right version, since the project renamed itself and moved two major versions in August 2026.
Editorial conclusion
RootWire suits someone who needs to read their own traffic rather than just filter it, a Linux operator debugging a network problem who wants the decoded options and a verified checksum rather than a hex dump, and a pipeline that wants NDJSON on stdout instead of a pcap file. It is the wrong tool on a non-Linux host, since only the raw socket path is Linux specific, and the wrong choice for bulk capture where the kernel filter and pcap writing of a mature tool is enough. Before you rely on it, read ARCHITECTURE.md, since the README points there for why memory stays flat during long captures and how to add a new output.
Frequently asked questions
What is RootWire?
It is a network traffic monitor for GNU/Linux, formerly known as Packet-Sniffer. It captures frames from one or more interfaces with a raw socket, timestamps them by the kernel, decodes each protocol layer with the NETProtocols library, and renders them live, writes them to pcap or streams them as JSON.
How do I install RootWire?
Run `pipx install rootwire` or `uv tool install rootwire`. From a clone, use uv with `git clone`, `cd RootWire` and `uv sync`. The package requires Python 3.12 or newer and its only runtime dependency is netprotocols.
Which protocols does the RootWire decoder support?
Ethernet with 802.1Q and nested QinQ tags, ARP, IPv4 with decoded options and fragments, IPv6 with extension headers and Neighbor Discovery, ICMPv4 and v6, TCP with decoded options, and UDP. Every IPv4, ICMPv4, ICMPv6, TCP and UDP checksum is verified against a recomputation and mismatches are flagged inline.
Does RootWire need root to run?
Only for live capture, which needs a raw socket, so root or the CAP_NET_RAW capability granted to the interpreter. Replaying a pcap file with -r never needs privileges, and the test suite needs neither root nor Linux because everything except the raw socket runs on any OS.
How does the RootWire --filter option work?
It attaches a kernel-side capture filter so only matching frames reach userspace. It takes a canned name such as arp, ip6, tcp or udp, or an expression over protocols, host and port with optional src and dst prefixes, the operators and, or and not, and parentheses, for example tcp and port 80.
What licence is RootWire released under?
AGPL-3.0-or-later, with the terms in the LICENSE file at the root of the repository and the licence declared in the package metadata as AGPL-3.0-or-later.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/eonraider-rootwire)Was this useful?