A passive network analysis tool built with Python and Scapy, developed for the RC-TP2 university computer networks project. The tool captures live traffic, extracts rich metadata (the 5-tuple and more), classifies protocol behaviour (TCP handshakes, ICMP types, ARP, DHCP), and logs everything to CSV, JSON, or plain text.
packet_sniffer/
├── main.py # CLI entry point (argparse)
├── requirements.txt
├── README.md
└── sniffer/
├── __init__.py
├── capture.py # Core sniff() loop & orchestration
├── parser.py # Metadata extraction (5-tuple, timestamps, …)
├── classifier.py # Protocol characterisation (TCP FSM, ICMP, …)
├── display.py # Colour-coded live console output
└── logger.py # CSV / JSON / TXT file logging
| Module | Role |
|---|---|
main.py |
Parses CLI args, checks root, wires modules together |
capture.py |
Wraps sniff(), calls parser → classifier → display → logger per packet |
parser.py |
Pure extraction: MAC, IP, ports, TTL, timestamps, one-line summary |
classifier.py |
Stateful protocol analysis: TCP FSM, ICMP types/codes, ARP, DHCP |
display.py |
ANSI colour output; compact table row + detail line per packet |
logger.py |
Append-only file writer for CSV, JSON-Lines, or TXT formats |
# 1. Clone / copy the project
cd packet_sniffer
# 2. Create a virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txtNote: Scapy requires
libpcapon Linux/macOS. On Debian/Ubuntu:sudo apt install libpcap-dev
All capture commands require root/sudo to open raw sockets.
sudo python3 main.py -i eth0sudo python3 main.py -i eth0 -b "tcp port 80"sudo python3 main.py -i wlan0 -c 200 -f json -o my_capturesudo python3 main.py -i eth0 --no-logsudo python3 main.py -i eth0 -f csv -o traffic --quietsudo python3 main.py --list-interfacesusage: rc-sniffer [-h] [-i IFACE] [-b FILTER] [-c N] [-f FMT] [-o BASENAME]
[--no-log] [--quiet] [--list-interfaces]
options:
-i, --interface IFACE Network interface (e.g. eth0, wlan0)
-b, --bpf FILTER BPF filter (e.g. "tcp", "host 10.0.0.1")
-c, --count N Stop after N packets (0 = unlimited)
-f, --format FMT Log format: csv | json | txt (default: csv)
-o, --output BASENAME Log file base name (default: capture)
--no-log Disable file logging
--quiet Suppress console output, log only
--list-interfaces Print available interfaces and exit
| Goal | BPF expression |
|---|---|
| TCP only | tcp |
| UDP only | udp |
| ICMP only | icmp |
| Specific host | host 192.168.1.10 |
| Source host | src host 192.168.1.1 |
| Specific port | tcp port 443 |
| Port range | portrange 8000-9000 |
| Exclude ARP | not arp |
| HTTP or HTTPS | tcp port 80 or tcp port 443 |
| Subnet | net 192.168.1.0/24 |
| MAC address | ether host aa:bb:cc:dd:ee:ff |
Each packet is one row. Columns: pkt_index, abs_timestamp,
rel_timestamp, src_mac, dst_mac, l2_proto, src_ip, dst_ip,
l3_proto, ip_ttl, src_port, dst_port, pkt_len, summary, detail.
One JSON object per line — easy to stream, import into pandas, or ingest into ELK / Splunk.
Human-readable blocks, one per packet, similar to Wireshark's plain-text export.
The classifier tracks each TCP flow (4-tuple) through a finite state machine:
Client Server
|--- SYN ------------------>| "Handshake step 1/3"
|<-- SYN-ACK ---------------| "Handshake step 2/3"
|--- ACK ------------------>| "Handshake step 3/3 (ESTABLISHED)"
|<----- data ------------->| "TCP PSH-ACK — Data segment"
|--- FIN ------------------>| "Connection teardown initiated"
|<-- ACK -------------------| "Connection teardown acknowledged (CLOSED)"
RST packets are detected immediately and annotate the flow as reset.
| Type | Code | Label |
|---|---|---|
| 8 | 0 | Echo Request (ping sent) |
| 0 | 0 | Echo Reply (ping received) |
| 3 | 0–4 | Destination Unreachable (various) |
| 11 | 0 | TTL Expired in Transit (used by traceroute) |
| 11 | 1 | Fragment Reassembly Timeout |
| 5 | 0/1 | Redirect |
The op field is decoded:
op=1→ Request: "Who has <IP>? Tell <IP>"op=2→ Reply: "<IP> is at <MAC>"
Client Server
|--- Discover -->| step 1/4
|<-- Offer ------| step 2/4
|--- Request --->| step 3/4
|<-- ACK --------| step 4/4 (lease confirmed)
This tool is strictly passive:
- Uses
store=Falseinsniff()— packets are never buffered. - No packet crafting, injection, ARP spoofing, or deauthentication code.
- No network interfaces are put into monitor mode programmatically.
- Raw socket access is required (root) but only for reading.
Scapy can read .pcap files offline — useful for testing on a laptop
without root. Add this snippet to main.py or a separate script:
from scapy.utils import rdpcap
from sniffer.parser import PacketParser
from sniffer.classifier import Classifier
pkts = rdpcap("sample.pcap")
parser = PacketParser()
clf = Classifier()
for pkt in pkts:
rec = parser.parse(pkt)
clf.classify(pkt, rec)
print(f"[{rec.pkt_index}] {rec.detail}")Free PCAP samples: https://www.netresec.com/?page=PcapFiles
| Package | Version | Purpose |
|---|---|---|
scapy |
≥ 2.5.0 | Packet capture, dissection, BPF |
Standard library only otherwise (argparse, csv, json, time,
collections, dataclasses).