NetworkInspector.CLI
0.17.0
dotnet tool install --global NetworkInspector.CLI --version 0.17.0
dotnet new tool-manifest
dotnet tool install --local NetworkInspector.CLI --version 0.17.0
#tool dotnet:?package=NetworkInspector.CLI&version=0.17.0
nuke :add-package NetworkInspector.CLI --version 0.17.0
NetworkInspector.CLI
ni converts and exports network and automotive captures from the command line: PCAP, PCAPNG, Vector BLF, and
Vector ASC in; PCAPNG, BLF, ASC, JSON, Text, PBF, Parquet, and DuckDB out. Filter with Wireshark-style
expressions, split large outputs, and script it with a stable exit-code contract.
Highlights
- Two commands for everything.
ni convertcopies frames between capture formats without parsing;ni exportparses every packet and writes analysis formats. - From capture to SQL in one line:
ni export capture.pcapng -o packets.duckdb. - Filters on both commands.
--filter "udp.dstport == 53"; a filter that matches nothing writes no file. - Large captures. Split by size or count, cap the record count, report progress, cancel with Ctrl+C and keep a readable partial output.
- Automotive ready. CAN, CAN FD, CAN XL, LIN, FlexRay, and automotive Ethernet between BLF, ASC, and PCAPNG.
- Script friendly. Exit codes 0–3, diagnostics on stderr, UTF-8 output, invariant culture.
Install
Requires the .NET 10 runtime.
dotnet tool install -g NetworkInspector.CLI
ni --help
As a local tool for one repository:
dotnet new tool-manifest
dotnet tool install NetworkInspector.CLI
dotnet ni --help
Quick Start
# Convert a Vector BLF log to PCAPNG for Wireshark
ni convert capture.blf -o capture.pcapng
# Export every packet as JSON
ni export capture.pcapng -o packets.json
# Query packets with SQL
ni export capture.pcapng -o packets.duckdb
duckdb packets.duckdb "SELECT count(*) FROM packets"
# Keep only DNS traffic, as a new capture
ni convert capture.pcapng -o dns.pcapng --filter "udp.port == 53"
# Read the protocol tree of the first 10 packets
ni export capture.pcapng -o first10.txt -f text:level=full -n 10
Commands
| Command | Parses packets | Use when |
|---|---|---|
convert |
only with --filter |
Frame-preserving conversion, merging, or splitting |
export |
always | Parsed packets as JSON, Text, PBF, Parquet, or DuckDB |
Run ni <command> --help for the built-in help.
Inputs
Both commands take one or more source specs. The reader is chosen by file extension (case-insensitive):
.pcap and .pcapng (PCAP or PCAPNG, detected by magic number), .blf, .asc. Typed specs work too:
pcap:path=…, blf:path=…, asc:path=…. random:count=N,seed=S,mode=M generates synthetic traffic
(count default 1000, 0 = unlimited; seed default 42; modes udp4 (default), udp6, ipv4, ipv6,
ethernet, can, canfd, random).
Several inputs are interleaved one frame at a time (round-robin), not concatenated and not merged by timestamp.
Source specs must not contain shell metacharacters (| & > < ; \ ( ) { }`); rename such files first.
ni convert
Frame-level conversion. Without --filter no protocol stack is built and no frame is parsed.
ni convert <input> [<input2> ...] --output <path> [options]
| Option | Meaning |
|---|---|
-o, --output <path> |
Output file (required; - for stdout is not supported) |
-f, --format, --output-format <spec> |
Output format; overrides the extension |
-n, --max-frames <N> |
Maximum frames to write |
--split-size <MiB> / --split-count <N> |
Split the output by size or frame count |
--filter <expr> |
Keep frames whose packet matches (parses each frame) |
--progress <N> |
Report progress every N frames on stderr |
--tolerant |
Skip unreadable records instead of aborting |
--blf-cache-size <MiB> |
BLF container cache budget (max 2047) |
--profile <name>, --settings-path <dir> |
Protocol settings profile and storage (used with --filter) |
--settings-max-config-file-bytes <bytes> |
Max settings/config JSON size (default 1073741824; <= 0 disables) |
--settings-max-json-depth <n> |
Max settings/config JSON depth (default 1024; <= 0 disables) |
Output formats:
| Spec | Output | Inferred from |
|---|---|---|
pcapng (alias pcap) |
PCAPNG | .pcapng, .pcap, no or unknown extension |
blf, blf:compression=off\|fast\|default\|best |
BLF (default compression default) |
.blf |
asc |
ASC | .asc |
There is no classic PCAP writer: pcap and -o x.pcap write PCAPNG.
# Split a large file into 100 MiB parts: split/part_00001.pcapng, split/part_00002.pcapng, ...
ni convert big.pcapng -o split/part.pcapng --split-size 100
# Interleave two BLF logs into one capture
ni convert a.blf b.blf -o merged.pcapng
# Uncompressed BLF for fast tooling
ni convert capture.pcapng -o capture.blf -f blf:compression=off
ni export
Parse every frame through the standard protocol stack and write one record per packet.
ni export <input> [<input2> ...] --output <path> [--format <spec>] [options]
| Option | Meaning |
|---|---|
-o, --output <path> |
Output file or directory (required) |
-f, --format <spec> |
Export format (see below) |
-n, --max-packets <N> |
Maximum packets to write |
--split-size <MiB> |
Split when the live output estimate reaches this size |
--split-count <N> |
Split every N packets |
--filter <expr> |
Export only matching packets |
--progress <N>, --tolerant, --blf-cache-size <MiB> |
As for convert |
--profile <name>, --settings-path <dir>, --settings-max-* |
Protocol settings |
Export formats:
| Spec | Variants | Inferred from |
|---|---|---|
json |
json:style=compact (default), pretty, array |
.json |
text |
text:level=summary\|standard\|full, text:truncate=<N> (default 256, 0 = no limit) |
.txt |
pbf |
pbf:format=standard\|columnar, compressed (default) or nocompress |
.pbf |
parquet |
directory dataset; splits become base_00001, … |
— (use -f parquet) |
duckdb |
one file; splits become base_00001.duckdb, … |
.duckdb |
Parameters combine with commas: text:level=full,truncate=0, pbf:format=columnar,nocompress. Any other
extension needs -f. CSV is available in the library (NetworkInspector.Exporters), not in the CLI.
Known issue in 0.16.0:
textwith the default levelstandard(andsummary) omits the protocol containers and prints little more than the packet header. Usetext:level=full.
# Pretty JSON
ni export capture.pcapng -o capture.json -f json:style=pretty
# Columnar PBF without compression
ni export capture.pcapng -o capture.pbf -f pbf:format=columnar,nocompress
# Parquet dataset, a new directory every 50 000 packets
ni export capture.pcapng -o out_parquet -f parquet --split-count 50000
# Only port 443, tolerant of damaged records, progress every 50 000 packets
ni export unknown.blf -o tls.json --filter "tcp.port == 443" --tolerant --progress 50000
Filtering
Both commands accept the expression language of NetworkInspector.Filter
(full guide).
- A packet is judged before any output is opened, so a filter that matches nothing writes no file and no dataset directory.
- An expression that does not compile exits with code
1and names the offending token or field on stderr, including a "did you mean" suggestion for misspelled fields. - An expression that fails to evaluate aborts with code
3instead of writing a partially filtered output. --max-frames/--max-packetscount written records, so they cap matching records.
Splitting
Split files are named {base}_{index:D5}{extension}: -o split/part.json --split-count 10000 writes
split/part_00001.json, split/part_00002.json, … The parent directory must exist (Parquet creates its own
dataset directory). Existing files are overwritten.
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success, also after Ctrl+C (the partial output is finalized) |
1 |
Usage or validation error: missing or unknown option, unknown input extension, bad format spec, filter that does not compile |
2 |
Source cannot be opened or read: missing file, invalid file header |
3 |
Runtime failure during conversion or export, including a packet that fails to parse and a filter that fails to evaluate |
Operational Notes
--tolerantskips records the reader cannot read. A packet that the parser rejects still stopsexportwith code3.- Progress, warnings, and the completion summary go to stderr; the console uses UTF-8.
- Ctrl+C cancels cooperatively and finalizes what was written.
- Commands and options are case-insensitive.
-h,--help,-?work as the first argument after the command.
Safe Usage (STRIDE)
- Spoofing: Prefer captures from trusted, attributable sources.
- Tampering: Use
--tolerantfor unknown files and inspect the warnings on stderr. - Repudiation: Keep inputs, outputs, and the command line together for reproducibility.
- Information disclosure: JSON, Text, and columnar outputs can contain payload secrets; protect them.
- Denial of service: Use
--max-frames,--max-packets, split options, and the settings size limits on untrusted input. - Elevation of privilege: Run
niwith least-required file-system permissions.
Learn More
- Exporters (formats in detail) · Sources (readers) · Filter · Root overview
- The
niexecutable is a thin host over theNetworkInspector.CLI.Corelibrary (CliEntry.Run). - GitHub repository · Issue tracker
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.17.0 | 54 | 10/17/2026 |
| 0.16.0 | 58 | 10/17/2026 |
| 0.15.0 | 100 | 10/9/2026 |
| 0.14.0 | 85 | 10/8/2026 |
| 0.13.0 | 114 | 9/27/2026 |
| 0.12.0 | 111 | 9/17/2026 |
| 0.11.0 | 126 | 9/10/2026 |
| 0.10.0 | 122 | 9/8/2026 |
| 0.9.0 | 142 | 9/2/2026 |
| 0.8.0 | 155 | 8/28/2026 |
| 0.7.0 | 150 | 8/27/2026 |
| 0.6.0 | 142 | 8/21/2026 |
| 0.5.0 | 144 | 7/11/2026 |
| 0.4.0 | 146 | 6/2/2026 |
| 0.3.0 | 147 | 5/21/2026 |
| 0.2.0 | 145 | 5/19/2026 |