NetworkInspector.Filter
0.17.0
dotnet add package NetworkInspector.Filter --version 0.17.0
NuGet\Install-Package NetworkInspector.Filter -Version 0.17.0
<PackageReference Include="NetworkInspector.Filter" Version="0.17.0" />
<PackageVersion Include="NetworkInspector.Filter" Version="0.17.0" />
<PackageReference Include="NetworkInspector.Filter" />
paket add NetworkInspector.Filter --version 0.17.0
#r "nuget: NetworkInspector.Filter, 0.17.0"
#:package NetworkInspector.Filter@0.17.0
#addin nuget:?package=NetworkInspector.Filter&version=0.17.0
#tool nuget:?package=NetworkInspector.Filter&version=0.17.0
NetworkInspector.Filter
Wireshark-style display filters for NetworkInspector packets: udp.dstport == 53, ip.src in {10.0.0.1, 10.0.0.2},
tcp && !tls. Expressions are compiled once to native code and checked against the protocol stack, so a typo is a
compile error with a "did you mean" hint, not a silent non-match.
Highlights
- Familiar syntax. Protocol presence, comparisons,
and/or/not, sets, ranges,contains,matches, byte slices,len(), IPv4/IPv6/MAC literals, field aliases (eth.addr). - Compiled. Expressions become .NET expression trees compiled by the JIT; evaluation short-circuits.
- Fast over large captures. With a
PacketIndex, a filter prunes the candidate packets with presence bitmaps before it evaluates a single packet. - Beyond Wireshark. Subtree scopes (
$udp { udp.dstport == 53 }) bind conditions to one protocol instance;flank(...)detects value edges across packets within a time or packet window. - Works without a field tree. A
FilterObserverevaluates during a skip parse, for high-throughput pipelines. - Editor support.
Filter.GetCompletionsreturns completions at the caret; errors carry position, length, and a suggestion. - Safe on untrusted expressions. Bounded nesting (64) and term count (1024), linear-time regex where possible and a timeout otherwise, errors as values instead of exceptions.
- Used everywhere. Session listeners and both
niCLI commands (--filter) use this language.
Install
dotnet add package NetworkInspector.Filter
dotnet add package NetworkInspector.Protocols
Quick Start
using NetworkInspector.Core;
using NetworkInspector.Core.Ids;
using NetworkInspector.Core.Settings;
using NetworkInspector.Filter;
using NetworkInspector.Filter.Errors;
using NetworkInspector.Protocols;
using NetworkInspector.Values;
StackBuilder builder = new(new SettingsManager(), new FrameInterfaceRegistry());
builder.RegisterStandardProtocols();
using Stack stack = builder.Build();
// Compile once against the stack: unknown names fail here, with a suggestion.
if (!Filter.TryCompile("udp.dstport == 53 && ip.ttl > 32", stack, out Filter? filter, out FilterError? error))
{
Console.Error.WriteLine(error); // [Kind] at position (length n): message
return;
}
// Ethernet / IPv4 192.168.1.1 -> 192.168.1.2 / UDP 12345 -> 53
byte[] raw = Convert.FromHexString(
"001122334455" + "66778899AABB" + "0800" +
"4500001C" + "12344000" + "4011A549" + "C0A80101" + "C0A80102" +
"30390035" + "00080000");
Frame frame = Frame.Create(new FrameId(0), Timestamp.FromSecs(0), raw,
LinkType.Ethernet, FrameInterfaceId.Invalid, stack.FrameInterfaceRegistry).Value;
ParseOptions options = new(); // filters evaluate the field tree
if (!Packet.TryParse(new PacketId(0), stack, frame, in options, out Packet? packet, out ParseFailure failure)
|| packet is null)
{
throw new InvalidOperationException(failure.ToString());
}
// false = no verdict (for example a runtime error), not "no match".
if (!filter.TryIsMatch(packet, out bool matched, out FilterError? evalError))
{
throw new InvalidOperationException(evalError.ToString());
}
Console.WriteLine(matched); // True
Inside a namespace that starts with NetworkInspector, the name Filter refers to the namespace; use an alias
such as using PacketFilter = NetworkInspector.Filter.Filter;.
Language At A Glance
| Expression | Meaning |
|---|---|
tcp, !dns |
Protocol present / absent |
ip.src == 10.0.0.1 |
Comparison (==, !=, <, <=, >, >=) |
tcp.port in {80, 443}, udp.port in 1024..65535 |
Set and range membership |
http.host contains "example" |
Ordinal substring |
http.user_agent matches "(?i)curl" |
.NET regular expression |
udp.payload[0:2] == 00:2a, len(udp.payload) > 100 |
Byte slices and lengths |
eth.addr == FF:FF:FF:FF:FF:FF |
Alias: any member field matches |
$udp { udp.dstport == 53 } |
Subtree scope: one UDP instance satisfies all conditions |
flank(can.id, changed, within: 10ms) |
Stateful edge detection across packets |
A repeated field matches if any occurrence matches. Keywords are case-insensitive; and, or, not work as well
as &&, ||, !. Full grammar and semantics: FILTER_GUIDE.md.
Common Tasks
Filter Many Packets With The Presence Index
Record a PacketIndex during parsing and pass it to the filter; packets that cannot match are rejected from the
index without evaluating the tree:
using NetworkInspector.Core.Index;
PacketIndex index = new(stack);
ParseOptions indexed = new(index: index);
// ... Packet.TryParse(..., in indexed, ...) for every frame ...
filter.TryIsMatch(packet, index, out bool matched, out FilterError? evalError);
TryBuildCandidates(index, out RoaringBitmap? candidates) returns the whole candidate set at once.
Offer Completions In An Editor
FilterCompletions completions = Filter.GetCompletions("udp.dst", caretPosition: 7, stack);
foreach (FilterCompletionItem item in completions.Items)
{
Console.WriteLine($"{item.Text} ({item.Kind})"); // udp.dstport (Field)
}
ReplaceStart and ReplaceLength give the span to replace. Completion is thread-safe and caches one name catalog
per stack.
Evaluate During A Skip Parse
Filter.Compile(expression, stack, in FilterObserverOptions options) returns a FilterObserver. Pass it as a
parse observer with FieldTreeMode.Skip and read IsMatch after the parse (TryReadMatch for flank). Observers
reject subtree scopes and protocol presence without a container field (NeedsFieldTree).
Errors
FilterError has Kind (FilterErrorKind), Message, Position, Length, and Suggestion. ToString()
prints [Kind] at P (length L): Message.
- Compile errors:
LexerError,SyntaxError,UnknownField(with a suggestion),TypeMismatch,InvalidValue,UnsupportedFeature,StackRequired,NeedsFieldTree. - Evaluation errors poison the filter (fail closed) until
ResetState()orTryDerive(newStack, …). - An empty expression compiles to
Filter.AlwaysMatchand needs no stack.
Limits And Thread-Safety Notes
- A
Filterinstance is single-threaded; compile one per thread or derive copies withTryDerive.Filter.AlwaysMatchis immutable and shared. - Results are cached per
PacketIdby default. Turn the cache off withFilterCompileOptions.EnableMatchCache = falsefor forward-only pipelines that never revisit a packet. - Stateful filters (
flank) require ascending packet ids and do not use index pruning. - Expressions nest at most 64 levels and hold at most 1024 terms;
matchespatterns that need backtracking run withRegexTimeout(default 1 s). - Runtime code generation: not compatible with NativeAOT or trimming.
Learn More
- Filter guide: grammar, types, aliases, scopes,
flank, observers, completion, errors - Sessions (per-listener filters) · CLI
(
--filter) · Core · Root overview - 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. |
-
net10.0
- NetworkInspector.Core (>= 0.17.0)
- ZeroAlloc (>= 0.6.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NetworkInspector.Filter:
| Package | Downloads |
|---|---|
|
NetworkInspector.Sessions
Session orchestration for NetworkInspector. Coordinates frame sources, protocol stack parsing, pull-based listeners, and background jobs. |
GitHub repositories
This package is not used by any popular GitHub repositories.