Skip to content

Tech stack: what NetMap is built with, and why

flowchart TB
    subgraph FE["Browser · plain JavaScript, no build step"]
        direction LR
        LF["Leaflet<br/>interactive map"] ~~~ CJ["Chart.js<br/>throughput chart"] ~~~ SIO["Socket.IO client<br/>live updates"]
    end
    subgraph BE["Python 3.9+ backend"]
        direction LR
        FL["Flask + Flask-SocketIO<br/>web server, REST API, push"] ~~~ JJ["Jinja2<br/>templates, offline report"]
        DP["dpkt<br/>decode pcap / pcapng"] ~~~ GEO["pygeoip / maxminddb<br/>IP → location"]
    end
    subgraph CAP["Packet capture"]
        direction LR
        SC["Scapy<br/>when NetMap already has rights"] ~~~ LP["ctypes + system libpcap<br/>root helper, standard library only"]
    end
    subgraph DATA["Data"]
        direction LR
        DB[("GeoLiteCity.dat<br/>or *city*.mmdb")] ~~~ PC[("sample-browsing.pcap<br/>demo-alerts.pcap")]
    end
    FE <-->|"HTTP + WebSocket"| BE
    CAP -->|packets| BE
    BE --> DATA

Backend (Python)

Technology Where Why this choice
Python 3.9+ everything Readable, pre-installed on most Macs and Linux, and has the best packet libraries.
Flask app.py The smallest web framework that does the job: a handful of routes and templates.
Flask-SocketIO + simple-websocket app.py Pushes a new snapshot to the browser every second, without polling. Uses threading mode, so there's no extra async server to install.
dpkt analyzer.py Fast, pure-Python packet decoding for .pcap and .pcapng. It reads the 13,000-packet sample in well under a second.
Scapy app.py Live sniffing when the process already has capture rights (root, or Windows with Npcap), plus listing network interfaces.
ctypes + system libpcap capture_helper.py The privileged helper must use only the standard library (it runs as root outside the virtualenv), so it calls libpcap directly through ctypes.
pygeoip analyzer.py Reads the legacy GeoLiteCity.dat that ships with the repo, so NetMap works offline out of the box.
maxminddb analyzer.py Reads modern .mmdb databases (DB-IP Lite, GeoLite2), which add IPv6 and current data. Optional.
Jinja2 templates, to_html_report Renders the dashboard, and builds the offline report by inlining the CSS, JS and data into one HTML file.
Standard library everywhere ipaddress (private/public checks), socket (reverse DNS), concurrent.futures (background lookups), csv/json/xml exporters, argparse CLIs.

Frontend (browser)

Technology Why
Plain JavaScript (no framework, no build step) One 670-line file, so nothing needs compiling. The same file is embedded in the offline report.
Leaflet 1.9 Lightweight, open-source interactive maps. Markers are grouped by location and sized by data, with curved "flight" lines from you.
Esri World Dark Gray tiles A dark basemap that makes coloured traffic stand out, with no API key needed.
Chart.js 4 Throughput chart (bytes per second).
Socket.IO client Receives status and snapshot events.
CSS custom properties One dark theme, responsive layout, and colours shared between the map, legend and lists.
Google Fonts: Inter, JetBrains Mono Readable UI and monospace IP addresses.

Data

File What
GeoLiteCity.dat MaxMind GeoLite Legacy city database (IPv4). CC BY-SA 4.0, see third-party notices.
*city*.mmdb (optional, not included) DB-IP City Lite or MaxMind GeoLite2 City, picked up automatically.
sample-browsing.pcap A synthetic 30-second capture of an imaginary home network (12,921 packets, 36 servers, 11 countries). Generator.
demo-alerts.pcap A synthetic capture that triggers every alert type (generator).

Tooling

Tool Use
pytest 19 tests in tests/: parsing, GeoIP, alert rules, exporters, every API route, and the root-helper protocol (replayed from a file, so no root is needed).
GitHub Actions Runs the tests and a CLI smoke test on Ubuntu, macOS and Windows with Python 3.9 and 3.13 (workflow).
Wireshark To record your own .pcapng captures to open in NetMap.
Google My Maps / Google Earth To view the KML export.

What it deliberately does not use

  • No database server: all state is in memory for the current session.
  • No cloud services or accounts: everything runs locally.
  • No JS build tools (npm, webpack, React): this keeps setup to "have Python".
  • No root for the web server: only the small capture helper is privileged.