# IP Subnet Allocator A simple internal web application for tracking and automatically allocating IPv4 subnets. ## Purpose This application is intended solely for internal tracking and automatic allocation of IPv4 subnets. It is not a general IPAM, monitoring tool, device inventory, VLAN manager, or network topology viewer. It is designed to run only inside a LAN/VPN. **The application does not include authentication** and must be placed behind a firewall/reverse proxy in a trusted network. ## Features - Manage one or more IP pools manually through the web UI. - First-run setup wizard: create the first pool before allocating subnets. - Automatic subnet allocation using a **first-fit** algorithm for prefixes /20 through /30. - Atomic allocation writes using SQLite `BEGIN IMMEDIATE` transactions. - Retro TUI/terminal-style web UI, server-side rendered with Askama. - Dynamic preview of the next free subnet via HTMX. - Allocation history with filtering, search, and pagination. - Release subnets (status `released`) with a mandatory note, directly from the history table or detail page. - Released subnets free up address space and can be reused by the first-fit algorithm. - Audit log of all operations. - Markdown, CSV, and JSON exports. - SQLite migrations run automatically on startup. - Backup and restore scripts. ## Architecture - **Rust** edition 2024 - **Axum** + **Tokio** - **SQLx** with **SQLite** - **Askama** for HTML templates - **HTMX** from a local static file - Custom CSS without external frameworks - CIDR/IP calculations using `ipnet` ## Quick start ```bash cd sub-aligator cp .env.example .env docker compose up -d --build ``` Open a browser at: ``` http://SERVER_IP:8080 ``` On first launch you will be asked to create the first pool. The default port can be changed in `.env` via the `APP_PORT` variable. ## Persistent data Docker Compose creates local directories: - `./data` – SQLite database - `./exports` – generated exports (Markdown, CSV, JSON) - `./backups` – database backups These directories are bind-mounted into the container, so data persists even if the container is removed. ## Backup and restore ### Backup ```bash ./scripts/backup.sh ``` The script creates a consistent database backup using `sqlite3 .backup` with a UTC timestamp in the filename. Backups are stored in `./backups`. ### Restore ```bash ./scripts/restore.sh ./backups/subnet-allocator.db.20240930T120000Z.backup ``` **Warning:** restore overwrites the current database. Stop the container and back up the current state before restoring. ### Automating backups On the host you can use a systemd timer or cron. Example cron entry: ```cron 0 2 * * * /path/to/sub-aligator/scripts/backup.sh >> /var/log/subnet-allocator-backup.log 2>&1 ``` ## Exports After every successful allocation or release, read-only exports are regenerated: - `/app/exports/allocations.md` - `/app/exports/allocations.csv` - `/app/exports/allocations.json` They are also available for download via endpoints: - `GET /exports/allocations.md` - `GET /exports/allocations.csv` - `GET /exports/allocations.json` The Markdown export contains a separate section for each pool with a table of active and reserved allocations. CSV and JSON include all allocations, including released ones. ## Security notes - The application **has no authentication**. Use it only behind a VPN/LAN/firewall. - CSRF tokens are required for POST forms. - Security headers are set: `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, `Content-Security-Policy`. - The application has no default Internet exposure; port binding is handled by Docker Compose. - `/healthz` returns only `{"status":"ok"}`. ## Adding authentication later via Caddy + Authentik The application is prepared for authentication through a trusted reverse proxy. The function `get_actor_from_request()` in `src/audit.rs` currently returns `local`, but can be updated to read a header such as `X-Authentik-Username`. Example Caddy configuration with Authentik: ```caddy subnet.example.com { reverse_proxy /outpost.goauthentik.io/* http://authentik:9000 forward_auth http://authentik:9000 { uri /outpost.goauthentik.io/auth/caddy copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email } reverse_proxy subnet-allocator:8080 } ``` After updating `get_actor_from_request()`, the audit log will record the real user. ## First-fit allocation example 1. First request `/30` receives `10.91.0.0/30`. 2. Next request `/24` receives `10.91.1.0/24` (avoids the occupied `/30`). 3. Another request `/30` fills the gap and receives `10.91.0.4/30`. The algorithm always respects CIDR alignment and finds the first free space large enough. ## Endpoints - `GET /` – main page - `GET /healthz` – healthcheck - `GET /setup` – first-run pool setup - `GET /pools` – pool management - `POST /pools/new` – create a new pool - `GET /partials/pools/{slug}/preview?prefix_length=24` – HTMX preview - `POST /allocations` – create an allocation - `GET /allocations/{id}` – allocation detail - `POST /allocations/{id}/release` – release an allocation - `GET /exports/allocations.{md,csv,json}` – exports ## Troubleshooting ### Container does not start ```bash docker compose logs -f subnet-allocator ``` ### Database is locked If the process terminates unexpectedly, a `-wal` or `-shm` file may remain. Stop the container and check `./data`. ### Exports are not generated Check the permissions of the `./exports` directory and the `APP_EXPORTS_DIR` variable. ## Licence MIT. See the `LICENSE` file.