A Telegram bot + CLI for IP inventory lookup across a multi-site campus network. Given an IP, returns which site / VLAN / subnet owns it via longest-prefix match. Backed by SQLite — no external services, runs in <30 MB RAM.
Originally built for a multi-site deployment with hundreds of sites and thousands of subnets; the engine is generic, the importer and the VLAN-purpose map are deployment-specific (see Customizing below).
- Longest-prefix match — most specific subnet wins; nested blocks shown as broader matches.
- Subnet calculator —
/calcreturns network/broadcast/mask/range plus the inventory owner (exact / inside / contains). - Free-IP finder —
/freereturns the next available IPs in a VLAN or CIDR, excluding hosts and the gateway. - Utilization —
/usageflags subnets at 80%+ capacity. - Status tracking —
/statussets a host active/down (admin-gated);/historyshows the change audit log. - Access control — allowlist for read access, separate admin set for writes.
| Command | Action |
|---|---|
/ip <addr> |
site / VLAN / subnet for an IP |
/subnet <cidr> |
list hosts inside a CIDR |
/site <name|code> |
full inventory for a site |
/search <text> |
search sites + hosts |
/calc <cidr> |
subnet calculator + owner |
/free <vlan|cidr> [code] |
next available IPs in a VLAN/subnet |
/usage [vlan] |
subnets at 80%+ utilization |
/status <ip> [active|down] |
show or set a host's status (admin only) |
/history <ip> |
status-change audit log for a host |
/stats |
inventory summary |
/help |
command list |
Lookups are read-only. /status is the only write command (admin-gated).
Bulk inventory edits go through the CLI admin tools.
sudo apt update && sudo apt install -y python3 python3-venv gitsudo mkdir -p /opt/ipfinder
sudo chown $USER:$USER /opt/ipfinder
git clone https://github.com/<you>/ipfinder.git /opt/ipfinder
cd /opt/ipfinderpython3 -m venv .venv
.venv/bin/pip install -r requirements.txtcp ipfinder.env.example ipfinder.env
chmod 600 ipfinder.envEdit ipfinder.env and paste your @BotFather token after
IPFINDER_BOT_TOKEN=. Optionally set IPFINDER_ALLOWED_USERS and
IPFINDER_ADMIN_USERS (see Access control).
Either start from an empty schema (then add data via the CLI):
.venv/bin/python -c "import sqlite3; \
sqlite3.connect('ipfinder.db').executescript(open('bot/schema.sql').read())"Or import from your own spreadsheet by adapting bot/import_xlsx.py
(see Customizing).
.venv/bin/python bot/cli.py stats
.venv/bin/python bot/cli.py ip 192.0.2.50Foreground (for testing):
.venv/bin/python bot/bot.pyAs a systemd service:
# Edit ipfinder.service — replace __USER__ and __INSTALL__ placeholders
# with your service user and the absolute install path (e.g. /opt/ipfinder).
sudo cp ipfinder.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ipfinder
sudo systemctl status ipfinder
journalctl -u ipfinder -fSet these in ipfinder.env:
| Variable | Effect |
|---|---|
IPFINDER_ALLOWED_USERS |
comma-separated Telegram user IDs allowed to use the bot. Empty = open to everyone. |
IPFINDER_ADMIN_USERS |
comma-separated Telegram user IDs allowed to run /status writes. Empty = all writes denied (bot stays read-only). |
Get a user's numeric ID from the bot log — every command logs
cmd=... user_id=... username=... name=....
The SQLite DB is the source of truth. Manage it via:
# Sites (called "sites" in the schema)
.venv/bin/python bot/cli.py admin add-site S001P "EXAMPLE SITE" --kind normal --zone NORTH
.venv/bin/python bot/cli.py admin list-sites [--kind normal] [--zone NORTH] [--search example]
.venv/bin/python bot/cli.py admin edit-site S001P --name "RENAMED SITE"
.venv/bin/python bot/cli.py admin rm-site S001P # cascades to subnets + hosts
# Subnets
.venv/bin/python bot/cli.py admin add-subnet S001P 192.0.2.0/25 VLAN11 "Server"
.venv/bin/python bot/cli.py admin list-subnets [SITE_CODE] [--vlan VLAN11]
.venv/bin/python bot/cli.py admin rm-subnet <rowid>
# Hosts
.venv/bin/python bot/cli.py admin add-host S001P 192.0.2.1 "Core SW"
.venv/bin/python bot/cli.py admin list-hosts [SITE_CODE] [--role Router] [--ip 192.0.2.1]
.venv/bin/python bot/cli.py admin rm-host <rowid>
# Validation
.venv/bin/python bot/cli.py admin audit # duplicates, bad CIDRs, overlaps
.venv/bin/python bot/cli.py admin export backup.xlsx # snapshot to xlsx (not re-importable)Two files encode deployment-specific assumptions; everything else is generic. Edit these to match your environment:
Parses a specific source spreadsheet layout. The VLAN_COLS,
BLOCK_COLS, SHEETS, and SECTIONS constants at the top describe
which columns hold which subnets and how sites are categorized. You
will almost certainly replace this file with your own importer for a
different source. The schema it writes into (bot/schema.sql) is
generic.
A keyword → VLAN-number map used to recover a VLAN number from a
purpose string when a row is labelled by sheet name instead of
VLANnn. The shipped map is one example; adapt it for your
network's VLAN scheme.
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest # 38 tests, 90% coverage on lookup.pyTests live in tests/. The fixture in tests/conftest.py builds a
fresh seeded SQLite DB per test from bot/schema.sql.
ipfinder/
├── bot/
│ ├── bot.py Telegram bot handlers
│ ├── lookup.py longest-prefix-match engine (cached in memory)
│ ├── cli.py offline CLI: lookups + admin
│ ├── db_admin.py DB CRUD with validation
│ ├── import_xlsx.py xlsx -> SQLite importer (deployment-specific)
│ └── schema.sql single authoritative schema
├── scripts/
│ └── bulk_import.py parse a host-inventory text file into the DB
├── tests/ pytest suite (90% coverage on lookup.py)
├── ipfinder.service systemd unit template
├── ipfinder.env.example env-file template (token + access-control)
├── requirements.txt runtime deps
├── requirements-dev.txt test deps
└── README.md
MIT — see LICENSE.