Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tillo

Python Scapy C Django License

Tillo

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.

General architecture

The tool is organized into three modules that run on each capturer, plus an optional control application:

  1. Capture module: intercepts packets from the configured network interface, applies a BPF filter and manages capture-file rotation/limits.
  2. Anonymization module: removes or transforms network identifiers (IPv4, IPv6, MAC) and, optionally, the packet payload.
  3. Secure storage and sending module: encrypts the resulting .pcap files (GPG or AES) and sends them to one or more destinations (local disk, FTP, SCP, SFTP, S3, WebDAV, or the control application itself).
  4. 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]

Operation modes

  • single mode: 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.
  • distributed mode: 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.

network_capturer

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

Traffic capture

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 .pcap file 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).

Filtering, rotation and execution limits

  • BPF filter (BPF in config.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, Timeout and TotalLenght. Once reached, the capturer flushes the pending .pcap file and stops.

Anonymization

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.

Statistics

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]): via zabbix_utils.Sender/ItemValue, using the included template.
  • Or to the service's stdout/logs if neither section is configured.

Encryption and sending

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 in GPGKey.
  • 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.

Configuration (config.ini)

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=8000

See the full list of options (Anonymize, IPMode, MacMode, IPv6Mode, Header ... , and the [FTP], [S3], [WEBDAV], [SCP], [SFTP], [WEB], [ZABBIX], [VPN] sections) in help.txt.

Deployment

The setup.sh script, designed for Raspberry Pi OS , automates the deployment:

  1. Installs dependencies (Scapy, pcapy, paramiko, boto3 ... ) and compiles the C files.
  2. Creates a dedicated sniffer user.
  3. Configures the two network interfaces (eth0/eth1) into an bridge (br0), so traffic flows transparently through the device.
  4. Registers sniffer.py as a systemd service (sniffer.service).
  5. 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.

control_application

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.

What it lets you do

  • 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.

Stack

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.

Deployment

cd src/control_application
docker compose up -d --build

On 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.

Communication flow: capturer ↔ VPN ↔ control application

When deployed in distributed mode, a capturer onboards itself automatically:

  1. It connects to the VPN and obtains a private network address.
  2. It registers itself with the control application, which adds it to the dashboard and generates a dedicated key for it.
  3. 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.

Quick deployment

  1. Control application: docker compose up -d --build in src/control_application/. Configure wg-easy's password/host in docker-compose.yml.
  2. Capturer(s): on each Raspberry Pi, copy src/network_capturer/ and run sudo bash setup.sh. Edit /home/sniffer/config.ini with a [VPN] section pointing to the control server for distributed mode, and run access_web.py to register it automatically.
  3. Place the capturer inline in the network.

License

This project is distributed under the GNU GPLv3 license.

About

A network traffic capture tool focused on data protection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages