The goal of the project is to capture network traffic transparently (bridge mode, without modifying the existing infrastructure), anonymize sensitive packet information (IPv4, IPv6 and MAC addresses, and payload) and store/send the captures encrypted, in compliance with regulations such as the GDPR. This solution is designed to run on low-cost hardware (Raspberry Pi) with a plug-and-play design.
The repository contains two independent but complementary components:
src/network_capturer: the actual traffic capturer. Runs on the device placed inline in the network (e.g. a Raspberry Pi between a switch and a router or between a PC and a switch).src/control_application: a remote management/monitoring web application, able to administer one or several capturers from a single dashboard.
The tool is organized into three modules that run on each capturer, plus an optional control application:
- Capture module: intercepts packets from the configured network interface, applies a BPF filter and manages capture-file rotation/limits.
- Anonymization module: removes or transforms network identifiers (IPv4, IPv6, MAC) and, optionally, the packet payload.
- Secure storage and sending module: encrypts the resulting
.pcapfiles (GPG or AES) and sends them to one or more destinations (local disk, FTP, SCP, SFTP, S3, WebDAV, or the control application itself). - Control application (optional): remotely and centrally manages several capturers, receives real-time statistics and capture files, and allows decrypting them from the browser.
[Host] --packet--> [eth0] [Capture module] [Anonymization module] --pcap--> [Storage & sending module]
| (Raspberry Pi in bridge mode) |
[eth1] S3 / WebDAV / FTP / SCP / SFTP / WEB
|
[Router/Switch]
singlemode: the capturer works autonomously, with no connection to the control application. Files and statistics are stored locally (or sent directly via a configured protocol). Intended for one-off or portable scenarios, where the capturer is placed between a router and the switch that connects all the hosts of a network.distributedmode: master-agent architecture. The control application (master) manages and supervises several capturers (agents) over a WireGuard VPN tunnel, receiving their statistics and capture files in real time. Ideal for deploying several capturers across different networks and administering them from a single dashboard.
The mode is determined purely by configuration: simply pointing Send=WEB (with a [WEB] section containing the control application's IP/port) makes the capturer operate in distributed mode; if not set, it runs in single mode.
Path: src/network_capturer/
network_capturer/
├── setup.sh # Installation/deployment script for Raspberry Pi OS
├── zabbix_template.yaml # Zabbix monitoring template
└── sniffer/
├── main.c # Low-level capture (libpcap), compiled as a shared library
├── sniffer.py # Main orchestrator (capture, rotation, statistics threads)
├── Ip_modes.py # IPv4 address anonymization
├── IPv6_modes.py # IPv6 address anonymization
├── Mac_modes.py # MAC address anonymization
├── ciphers.py # Capture encryption (GPG / AES-ZIP)
├── send_pcap.py # Remote sending (WEB, FTP, S3, SFTP, WEBDAV, SCP)
├── config_search.py # Locates the configuration file (USB drive or local)
├── access_web.py # Automatic capturer registration on the VPN and control app
├── config.ini # Default configuration
└── help.txt # Documentation for every config.ini option
The capture core is written in C (main.c) and compiled as a shared library (liba.so) . It uses libpcap to capture in real time on the given interface, applying the BPF filter.
sniffer.py loads that library via ctypes and gets the packets from the C module and rebuilds them as Scapy objects and feeds them into the processing pipeline.
Also sniffer.py executes two more threads:
rotation: checks every 10 ms whether the current.pcapfile needs to be rotated, or whether execution should stop, based on the configured limits.stadistics: generates and publishes statistics every 0.1 s (locally, to the control application, or to Zabbix).
- BPF filter (
BPFinconfig.ini): compiled and applied directly on the interface, reducing the amount of traffic copied to user space. - Capture-file rotation, configurable through three combinable criteria: packet count (
PackagesPcap), time (RotateTime, e.g.4H,3M4H) or size (Size, e.g.4.5M). - Total execution limits, with the same syntax:
TotalPackages,TimeoutandTotalLenght. Once reached, the capturer flushes the pending.pcapfile and stops.
Before storing each packet, this tool applies anonymization (if Anonymize=True) to MAC, IPv4 and IPv6 independently, each with its own configurable method (MacMode, IPMode, IPv6Mode):
| Method | Behavior |
|---|---|
hash |
HMAC-SHA256 with a secret key (HashIpv4/HashMAC/HashIPv6), truncated to the length of each address |
first-seen |
Assigns an incremental fictitious address the first time each real address is seen (in-memory dictionary) |
zero |
Replaces the address with all zeros |
Additionally, Header allows removing the payload of specific protocols (ip, ipv6, tcp, udp, icmp, dns, the aggregates network/transport, or none). Any packet that does not belong to one of the recognized protocols (IPv4, IPv6, TCP, UDP, ICMP, DNS) is dropped from storage entirely, to avoid leaving sensitive data from unsupported protocols untreated.
During capture, a per-protocol packet counter, total bytes/average bandwidth, and a "sessions" dictionary (protocol/source IP-port/destination IP-port 5-tuple, bidirectional) with packet count and size are maintained. Statistics are generated after anonymization, so they never expose real addresses. They are published every 0.1 s, as JSON, to:
- WEB (
[WEB]): the control application's API (distributed mode). - Zabbix (
[ZABBIX]): viazabbix_utils.Sender/ItemValue, using the included template. - Or to the service's
stdout/logs if neither section is configured.
When each .pcap is closed (due to rotation or end of execution), ciphers.py encrypts it according to Cipher:
GPG: asymmetric encryption with the public key given inGPGKey.AES: packaged into a password-protected AES-256 ZIP (ZipKey).none: unencrypted.
Afterwards, the tool sends the (encrypted or plain) file to every destination listed in Send (comma-separated): WEB, FTP, S3, SFTP, WEBDAV, SCP. Each destination has its own section in config.ini with address and credentials (see help.txt for the full detail of every protocol). If Disk=False, the local file is deleted after sending.
The capturer's entire behavior is defined in a single .ini file, with no need to recompile or touch the code (plug-and-play design). First looks for a config.ini on any mounted USB drive (taking priority over the local one), allowing the device to be reconfigured without SSH access; if none is found, it falls back to /home/sniffer/config.ini.
Minimal example:
[General]
Interface=eth0
Header=transport
Send=WEB
[WEB]
Server=10.8.1.2
Port=8000See the full list of options (Anonymize, IPMode, MacMode, IPv6Mode, Header ... , and the [FTP], [S3], [WEBDAV], [SCP], [SFTP], [WEB], [ZABBIX], [VPN] sections) in help.txt.
The setup.sh script, designed for Raspberry Pi OS , automates the deployment:
- Installs dependencies (Scapy, pcapy, paramiko, boto3 ... ) and compiles the C files.
- Creates a dedicated
snifferuser. - Configures the two network interfaces (
eth0/eth1) into an bridge (br0), so traffic flows transparently through the device. - Registers
sniffer.pyas asystemdservice (sniffer.service). - Disables unnecessary Raspberry Pi services.
access_web.py additionally automates onboarding the capturer in distributed mode: using wg-easy and registers itself with the control application, appending the SSH public key it receives back to authorized_keys to allow remote management.
Path: src/control_application/
A web application for centrally managing and monitoring every capturer deployed in distributed mode, removing the need to log into each device by hand whenever it has to be reconfigured, restarted, or its captures collected.
- Device dashboard: capturers register themselves automatically and show up on a list.
- Live monitoring: real-time statistics from each capturer are streamed to the dashboard.
- Remote terminal: an interactive terminal to each capturer straight from the browser.
- Remote configuration: view and edit a capturer's configuration file, and start, stop or check its capture service.
- Capture file management: every capture file is uploaded to the application as soon as it's generated, automatically organized per device and by how it's protected (GPG-encrypted, AES-encrypted ZIP, or already decrypted), and made available for download.
- In-browser decryption: encrypted capture files (GPG or AES) can be decrypted directly from the dashboard by entering the corresponding password/passphrase.
- Encryption key management: generate or import GPG key pairs, and push a public key remotely to any capturer.
- User management: create and manage the accounts allowed to access the application.
Built with Django and Django Channels with PostgreSQL as its database and a WireGuard VPN (via wg-easy) keeping every connection to a capturer encrypted. The whole stack, application, database and VPN server, is shipped together via docker-compose.yml.
cd src/control_application
docker compose up -d --buildOn first start it creates an initial admin account (admin / sniffer). Before using it in production, review the Django settings (secret key, debug mode, database password) and the wg-easy password/public IP in docker-compose.yml.
When deployed in distributed mode, a capturer onboards itself automatically:
- It connects to the VPN and obtains a private network address.
- It registers itself with the control application, which adds it to the dashboard and generates a dedicated key for it.
- The capturer accepts that key, becoming remotely manageable from that point on.
From then on, the capturer keeps pushing data to the application on its own: live statistics and every finished capture file.
- Control application:
docker compose up -d --buildinsrc/control_application/. Configurewg-easy's password/host indocker-compose.yml. - Capturer(s): on each Raspberry Pi, copy
src/network_capturer/and runsudo bash setup.sh. Edit/home/sniffer/config.iniwith a[VPN]section pointing to the control server for distributed mode, and runaccess_web.pyto register it automatically. - Place the capturer inline in the network.
This project is distributed under the GNU GPLv3 license.
