PcapFileEx.PreFilter (pcap_file_ex v0.5.5)
View SourceBPF-style pre-filtering in the Rust layer for high-performance packet filtering.
This module provides filters that are applied in the Rust layer before packets are deserialized to Elixir terms, resulting in 10-100x performance improvements for selective filtering on large files.
Important Notes
File Format Auto-Detection:
If you get an error like "Invalid field value: PcapHeader: wrong magic number",
your file might be PCAPNG format despite having a .pcap extension. Use
PcapFileEx.open/1 for auto-detection instead of Pcap.open/1 or PcapNg.open/1.
# ✓ RECOMMENDED: Auto-detect format
{:ok, reader} = PcapFileEx.open("capture.pcap")
# ✗ AVOID: Manual format selection (unless you're sure)
{:ok, reader} = PcapFileEx.Pcap.open("capture.pcap") # Fails if actually PCAPNGFilter Types
IP Filters
ip_source/1- Match source IP addressip_dest/1- Match destination IP addressip_source_cidr/1- Match source IP in CIDR rangeip_dest_cidr/1- Match destination IP in CIDR range
Port Filters
port_source/1- Match source portport_dest/1- Match destination portport_source_range/2- Match source port in rangeport_dest_range/2- Match destination port in range
Protocol Filters
protocol/1- Match protocol (tcp, udp, icmp, ipv4, ipv6, etc.)
Size Filters
size_min/1- Match minimum packet sizesize_max/1- Match maximum packet sizesize_range/2- Match packet size in range
Timestamp Filters
timestamp_min/1- Match packets after timestamp (Unix seconds)timestamp_max/1- Match packets before timestamp (Unix seconds)
Logical Operators
all/1- All filters must match (AND)any/1- Any filter can match (OR)not_filter/1- Invert filter (NOT)
Examples
# Filter TCP packets on port 80
filters = [
PcapFileEx.PreFilter.protocol("tcp"),
PcapFileEx.PreFilter.port_dest(80)
]
{:ok, reader} = PcapFileEx.Pcap.open("capture.pcap")
:ok = PcapFileEx.Pcap.set_filter(reader, filters)
# Now reading will only return matching packets
PcapFileEx.Stream.from_reader(reader)
|> Enum.take(10)
# Filter by IP range
filters = [
PcapFileEx.PreFilter.ip_source_cidr("192.168.1.0/24"),
PcapFileEx.PreFilter.size_range(100, 1500)
]
# Combine filters with logical operators
filters = [
PcapFileEx.PreFilter.any([
PcapFileEx.PreFilter.port_dest(80),
PcapFileEx.PreFilter.port_dest(443)
])
]Performance
Pre-filters are significantly faster than post-processing filters because:
- Packets are filtered in Rust before creating Elixir terms
- No memory allocation for filtered-out packets
- Reduced garbage collection pressure
- Lower CPU usage (no unnecessary protocol parsing)
For large files with selective filtering (e.g., "show me 10 packets on port 80 from a 10GB capture"), pre-filters can be 10-100x faster than post-processing.
Summary
Functions
All filters must match (AND).
Any filter can match (OR).
Match destination IP address.
Match destination IP in CIDR range.
Match source IP address.
Match source IP in CIDR range.
Invert filter (NOT).
Match destination port.
Match destination port in range.
Match source port.
Match source port in range.
Match protocol.
Match maximum packet size (original length).
Match minimum packet size (original length).
Match packet size in range (original length).
Match packets before timestamp (Unix seconds).
Match packets after timestamp (Unix seconds).
Types
@type filter() :: {:ip_source, String.t()} | {:ip_dest, String.t()} | {:ip_source_cidr, String.t()} | {:ip_dest_cidr, String.t()} | {:port_source, 0..65535} | {:port_dest, 0..65535} | {:port_source_range, 0..65535, 0..65535} | {:port_dest_range, 0..65535, 0..65535} | {:protocol, String.t()} | {:size_min, non_neg_integer()} | {:size_max, non_neg_integer()} | {:size_range, non_neg_integer(), non_neg_integer()} | {:timestamp_min, non_neg_integer()} | {:timestamp_max, non_neg_integer()} | {:and, [filter()]} | {:or, [filter()]} | {:not, filter()}
Functions
All filters must match (AND).
Examples
PreFilter.all([
PreFilter.protocol("tcp"),
PreFilter.port_dest(80)
])
Any filter can match (OR).
Examples
PreFilter.any([
PreFilter.port_dest(80),
PreFilter.port_dest(443)
])
Match destination IP address.
Examples
PreFilter.ip_dest("8.8.8.8")
Match destination IP in CIDR range.
Examples
PreFilter.ip_dest_cidr("10.0.0.0/8")
Match source IP address.
Examples
PreFilter.ip_source("192.168.1.1")
Match source IP in CIDR range.
Examples
PreFilter.ip_source_cidr("192.168.1.0/24")
PreFilter.ip_source_cidr("2001:db8::/32")
Invert filter (NOT).
Examples
PreFilter.not_filter(PreFilter.protocol("tcp"))
@spec port_dest(0..65535) :: filter()
Match destination port.
Examples
PreFilter.port_dest(80)
PreFilter.port_dest(443)
@spec port_dest_range(0..65535, 0..65535) :: filter()
Match destination port in range.
Examples
PreFilter.port_dest_range(1024, 65535)
@spec port_source(0..65535) :: filter()
Match source port.
Examples
PreFilter.port_source(8080)
@spec port_source_range(0..65535, 0..65535) :: filter()
Match source port in range.
Examples
PreFilter.port_source_range(8000, 9000)
Match protocol.
Supported protocols: tcp, udp, icmp, icmpv6, ipv4, ipv6
Examples
PreFilter.protocol("tcp")
PreFilter.protocol("udp")
PreFilter.protocol("icmp")
@spec size_max(non_neg_integer()) :: filter()
Match maximum packet size (original length).
Examples
PreFilter.size_max(1500)
@spec size_min(non_neg_integer()) :: filter()
Match minimum packet size (original length).
Examples
PreFilter.size_min(100)
@spec size_range(non_neg_integer(), non_neg_integer()) :: filter()
Match packet size in range (original length).
Examples
PreFilter.size_range(100, 1500)
@spec timestamp_max(non_neg_integer()) :: filter()
Match packets before timestamp (Unix seconds).
Examples
PreFilter.timestamp_max(1730818800)
@spec timestamp_min(non_neg_integer()) :: filter()
Match packets after timestamp (Unix seconds).
Examples
PreFilter.timestamp_min(1730732400)