This document explains the Rust version of the original C++ Packet_analyzer project.
Like the original project, this is not only a command-line tool. It is also a learning project. After reading this README, you should understand what the tool does, how a packet moves through the system, how DPI classification works, how blocking rules are applied, how to run it, and where to look in the code.
The Rust project keeps the original project's two main user-facing features:
- A packet analyzer that prints packet details from a PCAP file.
- A DPI engine that filters traffic and writes a new output PCAP.
It also adds Rust-native modules for offline replay, live capture, filters, session tracking, statistics, and scan detection.
- What is DPI?
- Networking Background
- Project Overview
- Feature Parity With the C++ Project
- File Structure
- Command Overview
- The Journey of a Packet: Analyzer Mode
- The Journey of a Packet: DPI Mode
- Deep Dive: Each Rust Component
- How TLS SNI Extraction Works
- How HTTP Host Extraction Works
- How DNS Query Extraction Works
- How Application Classification Works
- How Blocking Works
- Load Balancer and Fast Path Model
- Building and Running
- Testing
- Understanding the Output
- Common Problems
- Extending the Project
- Related Docs
- Summary
Deep Packet Inspection, usually called DPI, is a technique for inspecting network packets beyond the basic address and port fields.
A simple packet filter might ask:
- What is the source IP?
- What is the destination IP?
- What is the destination port?
- Is this TCP or UDP?
A DPI engine can also ask:
- Does this TLS ClientHello reveal a Server Name Indication value?
- Does this HTTP request contain a
Hostheader? - Does this DNS packet contain a domain query?
- Can the visible domain be mapped to an application such as YouTube or GitHub?
- Should this flow be dropped based on policy?
This project focuses on visible metadata and early protocol handshakes. It does not decrypt HTTPS traffic. That is an important distinction.
DPI-style systems are used for:
- enterprise traffic policy
- parental controls
- malware and intrusion detection
- traffic classification
- network research
- ISP analytics and throttling
- lab exercises for protocol learning
User Traffic PCAP
|
v
Rust DPI Engine
|
+-- parse Ethernet/IP/TCP/UDP
+-- inspect TLS/HTTP/DNS evidence
+-- classify app type
+-- apply block rules
+-- write allowed packets
v
Filtered Output PCAP
The input is a .pcap file. The output is another .pcap file containing only packets that were forwarded by the DPI logic.
Network packets are layered. Each layer adds its own header around the data from the layer above it.
+-------------------------------------------------------+
| Ethernet Header |
| +-------------------------------------------------+ |
| | IP Header | |
| | +-------------------------------------------+ | |
| | | TCP or UDP Header | | |
| | | +-------------------------------------+ | | |
| | | | Application Payload | | | |
| | | | TLS, HTTP, DNS, etc. | | | |
| | | +-------------------------------------+ | | |
| | +-------------------------------------------+ | |
| +-------------------------------------------------+ |
+-------------------------------------------------------+
In this project, the main layers are:
| Layer | Examples | What We Extract |
|---|---|---|
| Link | Ethernet | source MAC, destination MAC, EtherType |
| Network | IPv4, IPv6 | source IP, destination IP, TTL, protocol |
| Transport | TCP, UDP, ICMP | ports, TCP flags, payload offset |
| Application | TLS, HTTP, DNS | SNI, Host header, DNS query name |
Common minimum sizes:
| Header | Minimum Size |
|---|---|
| Ethernet | 14 bytes |
| IPv4 | 20 bytes |
| TCP | 20 bytes |
| UDP | 8 bytes |
| DNS | 12 bytes |
| TLS record | 5 bytes |
Headers can be longer. IPv4 and TCP both have header length fields. A parser must respect those fields instead of assuming a fixed layout.
A flow is usually identified by five values:
| Field | Example |
|---|---|
| Source IP | 192.168.1.100 |
| Destination IP | 142.250.185.206 |
| Source Port | 54552 |
| Destination Port | 443 |
| Protocol | TCP |
This is called the five-tuple.
Why it matters:
- all packets in the same conversation usually share the same five-tuple
- once a flow is identified as blocked, later packets can be dropped quickly
- flow hashing lets us distribute traffic across worker shards
- reports can count traffic by connection rather than only by packet
SNI means Server Name Indication.
When a browser opens https://www.youtube.com, the first TLS handshake message may include the domain name in plaintext:
TLS ClientHello
Extensions
server_name: www.youtube.com
The rest of the HTTPS session becomes encrypted, but this early handshake value is often visible. This makes SNI useful for educational DPI classification.
Modern privacy features can hide or avoid this information in some cases. This project only classifies what is actually visible in the packet bytes.
The Rust project has five top-level commands:
analyze print packet details from a PCAP
dpi filter a PCAP using DPI rules and write output PCAP
read Rust-native offline replay with filters/stats/sessions/alerts
capture optional live capture from an interface
interfaces optional live interface listing
The two commands most similar to the original C++ project are:
analyzedpi
PCAP file
|
v
PcapReader
|
v
Ethernet decoder
|
v
IP decoder
|
v
TCP/UDP decoder
|
v
Application parsers
|
+--> analyzer output
|
+--> DPI rules
|
+--> forwarded -> output PCAP
|
+--> dropped -> report only
The project has two layers:
| Layer | Purpose |
|---|---|
| Compatibility layer | Match the original C++ commands and behavior |
| Rust-native layer | Clean modular replay, filters, sessions, stats, and detection |
The compatibility layer lives mainly in:
src/compat.rs
The modular Rust engine lives across:
src/capture/
src/decoder/
src/parser/
src/session/
src/stats/
src/detection/
src/output/
The original project has a packet analyzer and a DPI engine. The Rust project mirrors those surfaces.
| Original C++ Behavior | Rust Equivalent |
|---|---|
packet_analyzer <pcap_file> [max_packets] |
cargo run -- analyze <pcap_file> [max_packets] |
dpi_engine <input.pcap> <output.pcap> |
cargo run -- dpi <input.pcap> <output.pcap> |
--block-ip <ip> |
--block-ip <ip> |
--block-app <app> |
--block-app <app> |
--block-domain <domain> |
--block-domain <domain> |
--rules <file> |
--rules <file> |
--lbs <n> |
--lbs <n> |
--fps <n> |
--fps <n> |
| app classification from domains | implemented |
| TLS SNI extraction | implemented |
| HTTP Host extraction | implemented |
| DNS query extraction | implemented |
| PCAP output writing | implemented |
| final reports | implemented |
The Rust dpi compatibility command currently preserves the load-balancer and fast-path sharding model for reporting, but the command itself runs synchronously.
That means:
--lbsand--fpsaffect shard distribution statistics- flow hashing is implemented
- per-LB and per-FP counts are reported
- the full threaded DPI LB/FP pipeline is not yet implemented in
dpi
The Rust-native read --concurrent path already contains a bounded worker pipeline for offline replay.
Packet_analyzer_rust/
|-- Cargo.toml
|-- Cargo.lock
|-- README.md
|-- build.rs
|-- src/
| |-- main.rs
| |-- lib.rs
| |-- cli.rs
| |-- compat.rs
| |-- error.rs
| |-- capture/
| | |-- mod.rs
| | |-- pcap_file.rs
| | |-- offline.rs
| | |-- replay_pipeline.rs
| | |-- filter.rs
| | |-- live.rs
| | `-- device.rs
| |-- decoder/
| | |-- mod.rs
| | |-- ethernet.rs
| | |-- ipv4.rs
| | |-- ipv6.rs
| | |-- transport.rs
| | |-- icmp.rs
| | |-- event.rs
| | |-- summary.rs
| | |-- error.rs
| | `-- util.rs
| |-- parser/
| | |-- mod.rs
| | |-- tls.rs
| | |-- http.rs
| | `-- dns.rs
| |-- session/
| | |-- mod.rs
| | |-- table.rs
| | |-- tcp.rs
| | `-- timeout.rs
| |-- stats/
| | |-- mod.rs
| | |-- engine.rs
| | |-- counters.rs
| | |-- summary.rs
| | `-- topk.rs
| |-- detection/
| | |-- mod.rs
| | |-- alert.rs
| | |-- rules.rs
| | `-- scans.rs
| |-- output/
| | |-- mod.rs
| | |-- console.rs
| | |-- json.rs
| | `-- pcap.rs
| |-- models/
| | |-- mod.rs
| | |-- address.rs
| | |-- flow.rs
| | |-- packet.rs
| | `-- protocol.rs
| `-- utils/
| |-- mod.rs
| |-- format.rs
| |-- telemetry.rs
| `-- time.rs
|-- tests/
|-- benches/
`-- docs/
|-- architecture.md
|-- setup.md
|-- packet-flow.md
|-- dpi-design.md
|-- concurrency-model.md
|-- protocol-notes.md
|-- testing.md
`-- roadmap.md
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap 10Git Bash:
cargo run -- analyze ../Packet_analyzer/test_dpi.pcap
cargo run -- analyze ../Packet_analyzer/test_dpi.pcap 10Use this when you want to inspect packets and learn what is inside them.
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcapWith blocking:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --block-app YouTube
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --block-domain facebook
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --block-ip 192.168.1.50With load-balancer and fast-path shard reporting:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --lbs 4 --fps 4cargo run -- read ..\Packet_analyzer\test_dpi.pcap --count 20
cargo run -- read ..\Packet_analyzer\test_dpi.pcap --tcp --port 443 --count 20
cargo run -- read ..\Packet_analyzer\test_dpi.pcap --concurrent --workers 4 --queue-size 1024Live capture requires the live-capture feature and platform packet capture dependencies.
cargo run --features live-capture -- interfaces
cargo run --features live-capture -- capture --interface "<interface>" --count 10Analyzer mode is the simplest path.
PCAP file
|
v
PcapReader
|
v
ParsedCompatPacket
|
v
print_packet_summary
The PCAP reader opens the file in binary mode and reads the global header.
The global header contains:
- magic number
- byte order
- timestamp resolution
- version
- snaplen
- link type
Only Ethernet/linktype 1 is supported for the compatibility commands.
Each PCAP packet record contains:
packet timestamp seconds
packet timestamp fraction
captured length
original length
packet bytes
The reader returns one packet at a time.
The first 14 bytes are interpreted as an Ethernet header:
bytes 0..5 destination MAC
bytes 6..11 source MAC
bytes 12..13 EtherType
If EtherType is 0x0800, the payload is IPv4.
The IPv4 parser reads:
- version
- header length
- TTL
- protocol
- source IP
- destination IP
The protocol field determines the next parser:
| Protocol Number | Meaning |
|---|---|
1 |
ICMP |
6 |
TCP |
17 |
UDP |
For TCP, the analyzer reads:
- source port
- destination port
- sequence number
- acknowledgment number
- header length
- flags
For UDP, it reads:
- source port
- destination port
- UDP payload offset
Example:
========== Packet #1 ==========
Time: SystemTime { ... }
[Ethernet]
Source MAC: 00:11:22:33:44:55
Destination MAC: aa:bb:cc:dd:ee:ff
EtherType: 0x0800 (IPv4)
[IPv4]
Source IP: 192.168.1.100
Destination IP: 142.250.185.206
Protocol: TCP
TTL: 64
[TCP]
Source Port: 54552
Destination Port: 443
Sequence Number: 1000
Ack Number: 0
Flags: SYN
This mirrors the original packet analyzer output while using Rust data structures.
DPI mode is more involved because it decides whether to forward or drop each packet.
input.pcap
|
v
read packet
|
v
decode Ethernet/IP/TCP/UDP
|
v
build flow key
|
v
hash to LB/FP shard
|
v
extract app evidence
|
v
classify application
|
v
check blocking rules
|
+-- forward -> write packet to output.pcap
|
+-- drop -> skip packet
Rules come from command-line options and optionally from a rules file.
Command-line examples:
--block-ip 192.168.1.50
--block-app YouTube
--block-domain facebookRules file example:
ip 192.168.1.50
app YouTube
domain facebook
The input PCAP is read packet by packet.
The output PCAP is created with a compatible global header. Forwarded packets are written to this file. Dropped packets are not written.
The decoder builds a DecodedPacket containing:
- packet summary
- optional TCP flags
- application insights
Application insights can include:
[TLS] SNI www.youtube.com[HTTP] GET host example.com[DNS] query github.com
For DPI compatibility, a flow key is built from:
source address
destination address
source port
destination port
transport protocol
This is the Rust version of the original five-tuple.
The flow key is hashed:
hash(flow) % lbs
hash(flow) % (lbs * fps)
This produces load-balancer and fast-path shard counts for the final report.
If a packet reveals a domain, the DPI command maps it to an application label.
Example:
www.youtube.com -> YouTube
github.com -> GitHub
zoom.us -> Zoom
If the port is known but no app-specific domain is visible:
TCP 80 -> HTTP
TCP 443 -> HTTPS
UDP 53 -> DNS
UDP 443 -> QUIC
The packet is dropped if:
- its source IP is blocked
- its flow has an app type that is blocked
- its visible domain matches a blocked domain rule
- the flow was already marked blocked earlier
The report tracks:
- total packets
- total bytes
- TCP packets
- UDP packets
- forwarded packets
- dropped packets
- app counts
- detected domains
- LB/FP distribution
The program entry point.
It:
- parses CLI arguments
- initializes logging/telemetry
- dispatches to the selected command
Simplified:
match cli.command {
Command::Analyze(args) => compat::run_analyze(args),
Command::Dpi(args) => compat::run_dpi(args),
Command::Read(args) => capture::run_offline_read(args),
Command::Capture(args) => capture::run_live_capture(args),
Command::Interfaces => capture::list_interfaces(),
}Defines all user-facing commands and flags with clap.
Important structs:
CliCommandAnalyzeArgsDpiArgsReadArgsCaptureArgsFilterArgs
This is the C++-compatible behavior module.
It implements:
run_analyzerun_dpi- PCAP writing
- rule loading
- domain normalization
- app classification
- packet summary printing
- LB/FP shard reporting
This file is the best place to start if your goal is to compare the Rust project to the original C++ implementation.
Reads PCAP files without needing live capture dependencies.
It supports:
- little-endian PCAP
- big-endian PCAP
- microsecond timestamps
- nanosecond timestamps
- snaplen validation
This folder decodes lower-level protocols.
Important files:
| File | Purpose |
|---|---|
ethernet.rs |
Ethernet header decoding |
ipv4.rs |
IPv4 decoding and validation |
ipv6.rs |
IPv6 decoding |
transport.rs |
TCP and UDP decoding |
icmp.rs |
ICMP decoding |
event.rs |
combines decoders into one decoded packet |
summary.rs |
printable packet summary types |
This folder decodes application-level evidence.
| File | Purpose |
|---|---|
tls.rs |
TLS ClientHello and SNI parsing |
http.rs |
HTTP request and Host parsing |
dns.rs |
DNS query parsing |
Tracks long-lived flow/session state for Rust-native replay.
The compatibility DPI path uses its own lightweight flow map in compat.rs, while the Rust-native replay path uses the session table module.
Builds aggregate traffic summaries:
- packet count
- displayed packet count
- byte count
- protocol count
- top talkers
Detects simple network behavior patterns from session state:
- SYN scans
- port scans
Contains output helpers for console, JSON, and PCAP-oriented output.
Shared data structures:
- packet models
- address models
- flow keys
- transport protocol enums
Small utilities for:
- formatting
- telemetry/logging
- time helpers
TLS traffic on port 443 often begins with a ClientHello.
The parser in src/parser/tls.rs follows this shape:
TLS Record Header
byte 0 content type
bytes 1-2 TLS version
bytes 3-4 record length
Handshake Header
byte 5 handshake type
bytes 6-8 handshake length
ClientHello Body
version
random
session id
cipher suites
compression methods
extensions
The SNI extension has type 0x0000.
Inside it:
server name list length
name type
name length
name bytes
If the parser finds a hostname, it returns:
TlsClientHello {
server_name: Some("www.youtube.com".to_owned()),
}That becomes an application insight:
[TLS] SNI www.youtube.com
Important limitations:
- only visible ClientHello data can be parsed
- encrypted ClientHello is not decoded
- application data after the handshake is not decrypted
- fragmented handshakes may not be fully reconstructed
Plain HTTP requests often begin with a method:
GET / HTTP/1.1
Host: example.com
User-Agent: ...
The parser in src/parser/http.rs checks for HTTP request methods and then searches headers for Host.
It can produce:
[HTTP] GET host example.com
HTTP is much easier to inspect than HTTPS because the payload is plaintext. But much modern web traffic uses HTTPS, so HTTP Host extraction is mainly useful for test captures, old services, or controlled lab traffic.
DNS queries usually use UDP port 53.
The parser checks:
- the DNS header is present
- the packet is a query, not a response
- at least one question exists
- the query name labels are valid
DNS names are encoded as length-prefixed labels:
06 github 03 com 00
This becomes:
github.com
The insight looks like:
[DNS] query github.com
Limitations:
- compressed names in some positions are not the focus of the simple parser
- DNS-over-HTTPS is HTTPS traffic and will not expose normal UDP DNS queries
- DNS-over-TLS is encrypted
Application classification is intentionally simple and readable.
The DPI command takes visible domains and maps them to app labels.
Examples:
| Domain Pattern | App |
|---|---|
youtube, ytimg, youtu.be |
YouTube |
google, gstatic, googleapis |
|
facebook, fbcdn, meta.com |
|
instagram, cdninstagram |
|
whatsapp, wa.me |
|
twitter, twimg, x.com, t.co |
Twitter/X |
netflix, nflxvideo, nflximg |
Netflix |
amazon, amazonaws, cloudfront |
Amazon |
microsoft, office, azure, outlook |
Microsoft |
apple, icloud, itunes |
Apple |
telegram, t.me |
Telegram |
tiktok, bytedance |
TikTok |
spotify, scdn.co |
Spotify |
zoom |
Zoom |
discord, discordapp |
Discord |
github, githubusercontent |
GitHub |
cloudflare, cf- |
Cloudflare |
If a packet has no app-specific evidence, the port may still provide a generic type:
| Traffic | Generic Type |
|---|---|
| TCP port 80 | HTTP |
| TCP port 443 | HTTPS |
| UDP port 53 | DNS |
| UDP port 443 | QUIC |
If no supported evidence exists, the app remains:
Unknown
This is not a commercial-grade classifier. It is a transparent educational classifier that is easy to modify.
The DPI command supports three blocking rule types:
| Rule Type | Example | Meaning |
|---|---|---|
| IP | --block-ip 192.168.1.50 |
drop packets from this source IP |
| App | --block-app YouTube |
drop flows classified as YouTube |
| Domain | --block-domain facebook |
drop flows whose visible domain contains facebook |
Packet arrives
|
v
Build flow key
|
v
Find or create flow state
|
v
Extract visible evidence
|
v
Update flow app/domain
|
v
Check rules
|
+-- matched -> mark flow blocked -> drop packet
|
+-- not matched -> write packet to output PCAP
The first few packets in a TCP connection may not reveal the app.
Example:
Packet 1: SYN
Packet 2: SYN ACK
Packet 3: ACK
Packet 4: TLS ClientHello with SNI www.youtube.com
The app is not known until packet 4. Once the flow is identified as YouTube, the flow can be marked blocked and later packets can be dropped.
Rules can also be loaded from a file:
# blocking_rules.txt
ip 192.168.1.50
app YouTube
domain facebook
Run:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --rules blocking_rules.txtThe original C++ project has a multi-threaded structure:
PCAP Reader
|
v
Load Balancer threads
|
v
Fast Path worker threads
|
v
Output Writer
The Rust compatibility DPI command currently runs synchronously, but it keeps the sharding model:
LB shard = hash(flow) % lbs
FP shard = hash(flow) % (lbs * fps)
This means:
- packets from the same flow map consistently to the same shard
- the final report can show LB/FP distribution
- the architecture is ready for a real worker-thread implementation later
Example command:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --lbs 2 --fps 2Example report:
THREAD STATISTICS
LB0 dispatched: 33
LB1 dispatched: 44
FP0 processed: 18
FP1 processed: 23
FP2 processed: 15
FP3 processed: 21
The Rust-native offline replay path already has a bounded worker pipeline:
cargo run -- read ..\Packet_analyzer\test_dpi.pcap --concurrent --workers 4 --queue-size 1024See docs/concurrency-model.md for more detail.
Required:
- Rust stable
- Cargo
Optional:
- Wireshark for viewing PCAP files
- Npcap/libpcap for live capture
cargo buildRelease build:
cargo build --releasePowerShell:
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap 10Git Bash:
cargo run -- analyze ../Packet_analyzer/test_dpi.pcap
cargo run -- analyze ../Packet_analyzer/test_dpi.pcap 10PowerShell:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcapGit Bash:
cargo run -- dpi ../Packet_analyzer/test_dpi.pcap output.pcapWith blocking:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output_youtube_blocked.pcap --block-app YouTube
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output_facebook_blocked.pcap --block-domain facebook
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output_ip_blocked.pcap --block-ip 192.168.1.50With multiple rules:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output_filtered.pcap --block-app YouTube --block-domain facebook --lbs 2 --fps 2cargo run -- read ..\Packet_analyzer\test_dpi.pcap --count 20
cargo run -- read ..\Packet_analyzer\test_dpi.pcap --tcp --port 443 --count 20
cargo run -- read ..\Packet_analyzer\test_dpi.pcap --udp --port 53 --count 20cargo run -- read ..\Packet_analyzer\test_dpi.pcap --concurrent --workers 4 --queue-size 1024Live capture requires extra setup and the Cargo feature:
cargo run --features live-capture -- interfaces
cargo run --features live-capture -- capture --interface "<interface>" --count 10On Windows, install Npcap and configure the Npcap SDK as described in docs/setup.md.
Run the full test suite:
cargo testRun formatting:
cargo fmtThe tests cover:
| Area | What is Tested |
|---|---|
| CLI | command parsing |
| PCAP | global header and packet reading |
| Decoder | Ethernet, IPv4, IPv6, TCP, UDP, ICMP |
| Parser | TLS SNI, HTTP Host, DNS query |
| Filter | protocol, port, and host filters |
| Session | bidirectional flow tracking |
| Stats | counters and top talkers |
| Detection | SYN scan and port scan heuristics |
Useful smoke test:
cargo build
cargo test
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap 2
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output_check.pcap --block-app YouTube --lbs 2 --fps 2Analyzer mode prints packet-by-packet details.
Sections:
| Section | Meaning |
|---|---|
| Ethernet | MAC addresses and EtherType |
| IPv4 | IP addresses, protocol, TTL |
| TCP | ports, sequence numbers, flags |
| UDP | ports |
| Payload | payload length and hex preview |
DPI mode prints a report after processing.
Example:
PROCESSING REPORT
Total Packets: 77
Total Bytes: 5738
TCP Packets: 73
UDP Packets: 4
Other Packets: 0
Forwarded: 73
Dropped: 4
Drop Rate: 5.19%
Thread shard stats:
THREAD STATISTICS
LB0 dispatched: 33
LB1 dispatched: 44
FP0 processed: 18
FP1 processed: 23
FP2 processed: 15
FP3 processed: 21
Application breakdown:
APPLICATION BREAKDOWN
HTTP 4
HTTPS 53
Google 2
Facebook 2
YouTube 2 (BLOCKED)
GitHub 1
Detected domains:
[Detected Domains/SNIs]
- www.youtube.com -> YouTube
- www.facebook.com -> Facebook
- github.com -> GitHub
| Field | Meaning |
|---|---|
| Total Packets | packets decoded for DPI processing |
| Total Bytes | bytes in processed packets |
| TCP Packets | TCP packet count |
| UDP Packets | UDP packet count |
| Forwarded | packets written to output PCAP |
| Dropped | packets omitted from output PCAP |
| Drop Rate | dropped / total |
| LB dispatched | packets mapped to each LB shard |
| FP processed | packets mapped to each FP shard |
If dropped is zero, your rule did not match visible traffic.
If an app is HTTPS, a domain was visible but no app-specific signature matched.
If an app is Unknown, the tool did not see supported evidence for that packet.
Wrong in Git Bash:
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcapGit Bash treats backslashes as escape characters, so the program receives a broken path like:
..Packet_analyzertest_dpi.pcap
Correct:
cargo run -- analyze ../Packet_analyzer/test_dpi.pcapPowerShell:
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcapGit Bash:
cargo run -- analyze ../Packet_analyzer/test_dpi.pcapCheck:
- Does the PCAP contain that app/domain/IP?
- Is the domain visible as TLS SNI, HTTP Host, or DNS?
- Did you spell the app name correctly?
- Are you blocking source IP, not destination IP?
That is expected. The project does not decrypt HTTPS. It only sees visible metadata such as TLS SNI when present.
Live capture requires Npcap and the Npcap SDK. Offline PCAP analysis does not.
See docs/setup.md.
You may see:
warn: could not canonicalize path: 'C:\Users\KIIT0001'
In this workspace, that warning is harmless if the command still builds and runs.
Edit the domain classification logic in src/compat.rs.
Example idea:
if contains_any(&domain, &["twitch", "ttvnw"]) {
Some(AppType::Twitch)
}You would also add the enum variant and display name.
Add a parser under:
src/parser/
Then call it from:
src/decoder/event.rs
Possible improvements:
- destination IP blocking
- port blocking
- allowlists
- exact domain matching
- regular expression matching
- JSON/YAML rules
- rule priorities
- rule hit counters
The compatibility DPI command already computes LB/FP shards. A future implementation could replace the synchronous loop with:
reader thread
-> LB queues
-> FP worker queues
-> output writer queue
The Rust-native replay pipeline is a good reference for bounded queues and worker structure.
Flow state can grow forever on huge captures. A production system would expire old flows using timestamps and idle timeouts.
UDP port 443 is labeled QUIC, but full QUIC ClientHello extraction is more complex than TLS over TCP. It would need QUIC packet parsing and crypto-frame handling.
Use the docs folder when you want more detail:
| Document | Purpose |
|---|---|
| docs/setup.md | installation, commands, platform setup |
| docs/architecture.md | module layout and ownership model |
| docs/packet-flow.md | packet lifecycle through the system |
| docs/dpi-design.md | DPI evidence, classification, blocking |
| docs/concurrency-model.md | worker and queue design |
| docs/protocol-notes.md | protocol parser assumptions |
| docs/testing.md | test strategy |
| docs/roadmap.md | future work |
This Rust project demonstrates:
- PCAP file reading and writing
- Ethernet, IPv4, IPv6, TCP, UDP, and ICMP decoding
- TLS ClientHello SNI extraction
- HTTP Host extraction
- DNS query extraction
- application classification
- flow-level blocking
- output PCAP generation
- load-balancer and fast-path style sharding
- session tracking, statistics, and scan detection
Start here:
cargo run -- analyze ..\Packet_analyzer\test_dpi.pcap 10Then try:
cargo run -- dpi ..\Packet_analyzer\test_dpi.pcap output.pcap --block-app YouTube --lbs 2 --fps 2The best way to understand the project is to run those commands, inspect the output, then read src/compat.rs, src/decoder/event.rs, and the parsers in src/parser/.