Network Topology Scanner
Scans a network range, discovers active hosts, their open ports/services, vendor (via MAC) and device type, and generates an interactive HTML topology graph with icons per category (router, PC, NAS, printer, etc). Flags hosts with sensitive open ports in red (Telnet, SMB, RDP, FTP, VNC), stores every scan in SQLite to diff against the previous one (new/dropped hosts, ports that changed), and can export the inventory to CSV. Optionally queries your routers/switches over SNMP to draw the real topology (which host hangs from which switch port or access point) instead of an approximate star. Available as a CLI or as a local web interface (Streamlit, optional).
Screenshots use fictional demo data — no real network is exposed here.
⚠️ Legal notice
Only use this tool on networks you own or have explicit authorization to scan (your homelab, or your workplace's network if you have permission). Scanning networks without consent is illegal in most countries.
Project structure
network-topology-scanner/
├── src/topology_scanner/
│ ├── scanner.py # nmap scanning (discovery + ports)
│ ├── classifier.py # Device classification by MAC/vendor
│ ├── graph.py # Graph construction (networkx)
│ ├── export.py # HTML export (pyvis), text and CSV
│ ├── history.py # Scan history in SQLite (diff vs. the previous scan)
│ ├── snmp.py # Real topology via SNMP (ARP, routes, MAC table, neighbors)
│ ├── cli.py # Command-line interface
│ └── webapp.py # Web interface (Streamlit, optional)
├── scripts/demo_arbol.py # Fictional SNMP tree for the README screenshot
├── tests/ # pytest, with nmap mocks (no real network needed)
└── pyproject.toml # single source of dependencies (pip install -e ".[dev,web,snmp]")
Installation
Requires Python 3.10+.
# System dependency
sudo apt install nmap # Linux
# On Windows: download the installer from nmap.org
# Virtual environment
python3 -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\Activate.ps1 # Windows PowerShell
# From PyPI
pip install topology-scanner
pip install "topology-scanner[web,snmp]" # optional: web interface and real topology via SNMP
For development, from a clone of the repo:
pip install -e ".[dev,web,snmp]"
Usage
sudo topology-scanner 192.168.1.0/24
sudo topology-scanner 192.168.1.0/24 --rapido
sudo topology-scanner 192.168.1.0/24 --con-so --output my_network.html
# Several ranges at once (e.g. your LAN and a homelab subnet behind another router)
sudo topology-scanner 192.168.1.0/24 10.0.10.0/24
# Real topology: query the router(s) over SNMP (see below)
export TOPOLOGY_SNMP_COMMUNITY='your-read-only-community'
sudo -E topology-scanner 192.168.1.0/24 --snmp 192.168.1.1
# Alternative without the installed entry point:
sudo python3 -m topology_scanner 192.168.1.0/24
| Flag | Description | Default |
|---|---|---|
range |
CIDR range(s) to scan, space-separated; history is kept per range | (required) |
--ports |
Ports to scan (nmap format) | common ports |
--nmap-args |
Extra arguments passed to nmap | -sV -T4 |
--output |
Output HTML file name | topologia_red.html |
--con-so |
Enables OS detection (-O), the slowest option | disabled |
--sin-2-fases |
Disables the preliminary ping scan, scans the full range directly | disabled |
--rapido |
Max-speed preset, ports only (incompatible with --con-so/--nmap-args) |
disabled |
--csv |
Also exports a CSV inventory to the given path | disabled |
--history-db |
SQLite file where scan history is stored | historial.db |
--sin-historial |
Skips saving the scan to history / diffing against the previous one | disabled |
--snmp |
Routers/switches to query over SNMP v2c (comma-separated IPs) | disabled (star layout) |
Web interface
Requires the [web] extra (see Installation). Form with automatic detection
of your local network, real cancellable scanning (kills the actual nmap
process, not just the UI), results table, CSV download and the embedded
graph. Several ranges can be scanned at once by separating them with
spaces in the range field. The "Real topology via SNMP" switch in the sidebar draws the tree
described below, over SNMP v2c or v3 (community and keys are password
inputs; leave them empty to use the TOPOLOGY_SNMP_* environment variables).
topology-scanner-web
# or, without the installed entry point:
streamlit run src/topology_scanner/webapp.py
Real topology via SNMP
By default the graph is an approximate star: nmap knows which hosts are
alive, not how they are connected. With --snmp, the scanner reads a few
standard tables from your routers/switches and builds a tree instead:
| SNMP table | What it tells | Used for |
|---|---|---|
Routes (ipCidrRouteTable) |
"10.0.10.0/24 is behind 192.168.1.44" | Upstream gateway, downstream routers and their subnets |
Neighbors (MikroTik mtxrNeighborTable, MNDP/LLDP/CDP) |
"Access point X is on my ether2" | Links between network devices |
Neighbors (standard LLDP-MIB, any vendor) |
"Switch Y sees me on its port3" | Links, with the port on both ends (ether2 ↔ port3) |
MAC table (BRIDGE-MIB) |
"MAC aa:bb:… is on port wlan1" | Which port each host is on |
ARP (ipNetToMediaTable) |
"192.168.1.20 is aa:bb:…" | Matching MACs to the IPs nmap found |
Hosts seen on a port that leads to another network device hang from that device; hosts that only SNMP sees (not detected by nmap) are shown too — an unknown device on a switch port is exactly what you want to notice. If no device answers, the scan still finishes with the star layout.
Fictional demo data, generated with python scripts/demo_arbol.py (no scan involved).
Setup (MikroTik RouterOS example — read-only, restricted to the scanning machine):
/snmp community add name=<long-random-string> addresses=<scanner-ip>/32 read-access=yes write-access=no
/snmp community set [find name=public] disabled=yes
/snmp set enabled=yes
The community is read from the TOPOLOGY_SNMP_COMMUNITY environment
variable, never from a command-line argument (arguments show up in ps and
in your shell history). On Windows PowerShell:
$env:TOPOLOGY_SNMP_COMMUNITY = "...".
SNMPv3 (recommended: v2c sends the community in clear text). In RouterOS
v6 the community name is the v3 user, and security=private means
authentication + encryption:
/snmp community add name=<user> addresses=<scanner-ip>/32 security=private \
authentication-protocol=SHA1 authentication-password=<8+ chars> \
encryption-protocol=AES encryption-password=<8+ chars> read-access=yes write-access=no
| Variable | Meaning | Default |
|---|---|---|
TOPOLOGY_SNMP_USER |
v3 user (if set, v3 is used and the community is ignored) | — |
TOPOLOGY_SNMP_AUTH_KEY |
Authentication key (8+ characters) | required |
TOPOLOGY_SNMP_PRIV_KEY |
Encryption key (8+ characters); empty = authenticate without encryption | — |
TOPOLOGY_SNMP_AUTH_PROTO |
MD5, SHA, SHA224, SHA256, SHA384, SHA512 |
SHA |
TOPOLOGY_SNMP_PRIV_PROTO |
DES, AES, AES192, AES256 |
AES |
Current limitations: links between network devices come from MikroTik's neighbor table and from the standard LLDP-MIB, so devices that don't run LLDP (or don't expose it over SNMP) are only placed by routes, ARP and the MAC table.
Device classification
Each host's MAC address is used to look up its vendor (via nmap's built-in database), which is then heuristically mapped to a category with its own icon: router, firewall, VM, NAS, printer, camera, IoT, mobile, Apple, PC.
Limitation: MAC resolution only works if the scanning machine is on the same L2 segment as the target host (ARP doesn't cross routers/VLANs). Hosts on other subnets will show up as category "unknown".
Tests
pytest tests/ -v
pytest tests/ --cov=topology_scanner # with coverage
scanner.py tests use unittest.mock to simulate nmap's responses, so they
run without a real network or the nmap binary installed.
Roadmap
- Visual alerts for sensitive open ports (RDP, Telnet, SMB, FTP, VNC)
- Scan history in SQLite (new/dropped hosts, ports that change)
- CSV export for audits/inventory
- Visual icon/color legend in the HTML
- Web interface with Streamlit
- CI: run tests + ruff on every push
- Real topology via SNMP against routers/switches, CLI (instead of the approximate star layout)
- SNMP in the web interface
- Standard LLDP-MIB (links between devices from any vendor, with the port on both ends)
- SNMPv3 (authentication and encryption)
- v1.0 on PyPI, published by GitHub Actions from a tag (trusted publishing, no tokens)
See CHANGELOG.md for release notes.
Metadata
Release files for topology-scanner 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| topology_scanner-1.0.0.tar.gz | 102.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| topology_scanner-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 166.8 kB
Release files / topology_scanner-1.0.0.tar.gz
| Download URL | topology_scanner-1.0.0.tar.gz |
|---|---|
| Size | 102.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cb7a8017342bf042b715f2eb10b52a4fd72f33041ef1fbce8c4640d148458085
|
|
BLAKE2b-256 checksum How to use checksums |
ab90d43e34ace6e416bea22222e380a77fb18a671324f73b022fd7f116197c2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / topology_scanner-1.0.0-py3-none-any.whl
| Download URL | topology_scanner-1.0.0-py3-none-any.whl |
|---|---|
| Size | 64.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
86e6961fd435ae9ce33885e1a6c5dc7a362716db06767cec6cb9dabe8ba533e7
|
|
BLAKE2b-256 checksum How to use checksums |
98a6171587f7f6a36d8fd4895956f4ba32c14f28bab7d0a1494dfb3be4523c39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for topology-scanner 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for topology_scanner-1.0.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.