Splits the LAN into four /24 zones: 10.0.0.0/24 static (no DHCP, DNS only), 10.0.1.0/24 fixed DHCP reservations by MAC, 10.0.2.0/24 dynamic DHCP pool, 10.0.3.0/24 spare/unused. ipadm now derives the required subnet from whether a host has a MAC, auto-assigns free IPs, and auto-migrates a host's IP when its MAC is added/removed. Migrated the existing archerc80 reservation from 10.0.0.2 to 10.0.1.2. Also fixes a latent bug found while doing this: dnsmasq's SIGHUP (`systemctl reload`) only re-reads /etc/hosts, not the conf-dir files ipadm writes to, so config changes were silently not applied on reload. ipadm now restarts dnsmasq instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
162 lines
7.9 KiB
Markdown
162 lines
7.9 KiB
Markdown
# ipadm
|
|
|
|
Kleines Go-CLI-Tool zur Verwaltung statischer Hosts (DHCP-Reservierung +
|
|
DNS-Eintrag) und WAN→LAN-Port-Forwards für den dnsmasq/nftables-Router auf
|
|
narcissus. Ersetzt/lehnt sich an das Original-Tool `ipadm` (dhcp/bind
|
|
management, mwx'2021) an, arbeitet aber gegen unseren dnsmasq/nftables-Stack
|
|
statt isc-dhcp-server/bind9 (siehe [../../README.md](../../README.md)).
|
|
|
|
Installiert auf dem Server unter `/usr/local/bin/ipadm`.
|
|
|
|
## IP-Adressschema
|
|
|
|
Das LAN ist ein `10.0.0.0/22`, aufgeteilt in vier `/24`-Zonen (Details siehe
|
|
[../../README.md#ip-adressschema](../../README.md#ip-adressschema)):
|
|
|
|
- `10.0.0.0/24` — statische Adressen (kein DHCP, nur DNS), für Hosts **ohne**
|
|
MAC-Adresse in der ipadm-Datenbank.
|
|
- `10.0.1.0/24` — feste DHCP-Reservierungen (per MAC), für Hosts **mit**
|
|
MAC-Adresse in der ipadm-Datenbank.
|
|
- `10.0.2.0/24` — dynamischer DHCP-Pool (nicht von ipadm verwaltet).
|
|
- `10.0.3.0/24` — Reserve, unbenutzt.
|
|
|
|
`ipadm` wendet diese Regel bei jeder IP-Zuweisung automatisch an: welches
|
|
Subnetz erlaubt ist, entscheidet allein, ob der Host eine MAC-Adresse hat
|
|
oder nicht — nicht der Nutzer. Details siehe unten.
|
|
|
|
## Funktionsweise
|
|
|
|
- Pflegt eine flache Textdatei `/etc/ipadm/hosts` (eine Zeile pro Host:
|
|
`name<TAB>ip<TAB>mac<TAB>comment`, `mac` ist `-` wenn nicht gesetzt) als
|
|
Datenbank für statische Hosts, und `/etc/ipadm/portforwards`
|
|
(`wanport<TAB>proto<TAB>host<TAB>lanport`) für Port-Forwards. Ein
|
|
Port-Forward referenziert einen Hostnamen aus der Host-Datenbank statt
|
|
einer festen IP, damit er automatisch der aktuellen IP des Hosts folgt.
|
|
- `ipadm -u` generiert daraus zwei Dateien und wendet die zugehörigen
|
|
Dienste neu an:
|
|
- `/etc/dnsmasq.d/hosts.conf` (pro Host ein `host-record=` für DNS, plus
|
|
`dhcp-host=` für Hosts mit MAC-Adresse für die DHCP-Reservierung),
|
|
validiert mit `dnsmasq --test`, danach `systemctl restart dnsmasq`.
|
|
**Bewusst `restart`, nicht `reload`**: dnsmasqs SIGHUP-Handler liest nur
|
|
`/etc/hosts` neu, nicht die `conf-dir`-Dateien, in denen `hosts.conf`
|
|
liegt — ein reines `reload` würde die Änderung nicht anwenden.
|
|
- `/etc/nftables.d/portforward.conf` (eine eigene `table inet portforward`
|
|
mit einer `dnat`-Regel pro Port-Forward, referenzierte Host-IP wird zum
|
|
Generierungszeitpunkt aus der Host-DB aufgelöst), validiert mit
|
|
`nft -c -f /etc/nftables.conf` (dafür bindet `/etc/nftables.conf` bereits
|
|
`include "/etc/nftables.d/*.conf"` ein), danach
|
|
`systemctl reload nftables` (dessen `reload` liest die komplette Config
|
|
neu ein, das ist hier unproblematisch).
|
|
|
|
Schlägt die jeweilige Validierung fehl, wird die vorherige generierte
|
|
Datei automatisch wiederhergestellt und der betroffene Dienst **nicht**
|
|
neu angewendet. Referenziert ein Port-Forward einen mittlerweile gelöschten
|
|
Host, wird er beim Generieren übersprungen und als Warnung ausgegeben,
|
|
statt den ganzen Lauf abzubrechen.
|
|
- IP-Adressen werden bei `-a`/`-i`/im interaktiven Modus geprüft: müssen im
|
|
zur MAC-Adresse passenden Subnetz liegen (`10.0.0.0/24` ohne MAC,
|
|
`10.0.1.0/24` mit MAC) und dürfen weder die Netz-/Broadcast-Adresse noch
|
|
die Gateway-Adresse `10.0.0.1` sein.
|
|
- Wird bei `-a` keine IP angegeben, vergibt `ipadm` automatisch die nächste
|
|
freie IP im passenden Subnetz.
|
|
- Wird bei `-m` eine MAC-Adresse hinzugefügt oder entfernt und der Host
|
|
liegt dadurch im falschen Subnetz, verschiebt `ipadm` ihn automatisch auf
|
|
eine freie IP im jetzt passenden Subnetz (mit Hinweis in der Ausgabe).
|
|
`-i` dagegen validiert nur — eine manuell angegebene IP muss bereits zum
|
|
(unveränderten) MAC-Status des Hosts passen.
|
|
- Port-Forwards werden über `(wan-port, protokoll)` eindeutig identifiziert;
|
|
`both` (= tcp+udp in einer Regel via `meta l4proto { tcp, udp }`) kollidiert
|
|
dabei mit einem einzelnen `tcp`- oder `udp`-Eintrag auf demselben Port.
|
|
|
|
## Usage
|
|
|
|
```
|
|
ipadm <hostname> add/edit host (interactive)
|
|
ipadm -l list hosts
|
|
ipadm -a [-f] <hostname> [ip address] [mac address] add host (IP auto-assigned if omitted)
|
|
ipadm -c <hostname> <comment> set comment
|
|
ipadm -i <hostname> <ip address> change ip address
|
|
ipadm -m <hostname> <mac address> change mac address
|
|
ipadm -r <old hostname> <new hostname> rename host
|
|
ipadm -d <hostname> delete host
|
|
ipadm -pa [-f] <hostname> <wan-port> [lan-port] [tcp|udp|both]
|
|
add port-forward to a known host
|
|
ipadm -pl list port-forwards
|
|
ipadm -pd <wan-port> [tcp|udp|both] delete port-forward
|
|
ipadm -u update (regenerate dnsmasq+nftables config, reload)
|
|
ipadm -h this help
|
|
```
|
|
|
|
(Output/messages of the tool itself are English; this README stays German like the rest of the repo.)
|
|
|
|
Beispiele:
|
|
|
|
```sh
|
|
ipadm -a webserver # Host ohne MAC anlegen, IP aus 10.0.0.0/24 auto-vergeben
|
|
ipadm -a heizung aa:bb:cc:dd:ee:ff # Host mit MAC anlegen, IP aus 10.0.1.0/24 auto-vergeben
|
|
ipadm -a fixip 10.0.0.42 # Host mit expliziter IP (muss zum Subnetz passen)
|
|
ipadm -pa webserver 443 tcp # WAN-Port 443/tcp -> webserver:443
|
|
ipadm -pa webserver 8080 80 tcp # WAN-Port 8080/tcp -> webserver:80
|
|
ipadm -u # anwenden (dnsmasq + nftables)
|
|
```
|
|
|
|
Bei `-a` sind IP-Adresse und MAC-Adresse optional und in beliebiger
|
|
Reihenfolge angebbar — das Tool erkennt selbst, welches Token eine IP und
|
|
welches eine MAC ist. Fehlt die IP, wird automatisch die nächste freie IP im
|
|
zur MAC passenden Subnetz vergeben.
|
|
|
|
`lan-port` und Protokoll bei `-pa` sind optional und ebenfalls in beliebiger
|
|
Reihenfolge angebbar (Default `lan-port` = `wan-port`, Default Protokoll
|
|
`tcp`) — das Tool erkennt selbst, ob ein Token eine Portnummer oder
|
|
`tcp`/`udp`/`both` ist.
|
|
|
|
Nach jeder Änderung an der Host- oder Port-Forward-DB (`-a`, `-c`, `-i`,
|
|
`-m`, `-r`, `-d`, `-pa`, `-pd`, interaktiv) muss `ipadm -u` ausgeführt
|
|
werden, damit dnsmasq/nftables die Änderung tatsächlich übernehmen — das
|
|
Tool weist nach jeder Änderung selbst darauf hin.
|
|
|
|
## Bauen / Installieren
|
|
|
|
```sh
|
|
cd tools/ipadm
|
|
go build -o ipadm .
|
|
install -m 0755 -o root -g root ipadm /usr/local/bin/ipadm
|
|
```
|
|
|
|
## Testen ohne die echte Server-Konfiguration anzufassen
|
|
|
|
Alle Pfade und das IP-Adressschema sind über Umgebungsvariablen
|
|
überschreibbar:
|
|
|
|
```sh
|
|
export IPADM_DB=/tmp/test-hosts
|
|
export IPADM_PORTFWD_DB=/tmp/test-portforwards
|
|
export IPADM_DNSMASQ_HOSTS=/tmp/test-hosts.conf
|
|
export IPADM_NFT_PORTFWD=/tmp/test-portforward.conf
|
|
export IPADM_STATIC_CIDR=10.0.0.0/24
|
|
export IPADM_RESERVED_CIDR=10.0.1.0/24
|
|
export IPADM_GATEWAY_IP=10.0.0.1
|
|
export IPADM_WAN_IFACE=enp3s0
|
|
./ipadm -a testhost aa:bb:cc:dd:ee:ff
|
|
./ipadm -l
|
|
```
|
|
|
|
Achtung: `ipadm -u` ruft trotzdem `dnsmasq --test` bzw.
|
|
`nft -c -f /etc/nftables.conf` auf (prüft die echte System-Konfiguration)
|
|
und bei Erfolg `systemctl restart dnsmasq`/`systemctl reload nftables`, auch
|
|
im Testmodus — das ist beabsichtigt (validiert, dass die generierte Datei
|
|
mit der echten Umgebung zusammenspielt), aber es wendet die echten
|
|
laufenden Dienste an (inkl. eines kurzen dnsmasq-Neustarts). `IPADM_NFT_PORTFWD`
|
|
nur auf einen Pfad außerhalb von `/etc/nftables.d/` zeigen lassen, sonst
|
|
landet die Testdatei im echten Include und wird real aktiv.
|
|
|
|
## Änderungshistorie (Kurzfassung)
|
|
|
|
- **v1.2.0** (2026-08-21): LAN auf `10.0.0.0/22` erweitert, Subnetz-Zonen
|
|
eingeführt (`IPADM_STATIC_CIDR`/`IPADM_RESERVED_CIDR` statt
|
|
`IPADM_LAN_CIDR`/`IPADM_POOL_START`/`IPADM_POOL_END`), automatische
|
|
IP-Vergabe bei `-a`, automatisches Umziehen bei MAC-Änderung (`-m`),
|
|
dnsmasq-Anwendung von `reload` auf `restart` korrigiert (siehe oben).
|
|
- **v1.1.0**: Port-Forwarding-Verwaltung (`-pa`/`-pl`/`-pd`) ergänzt,
|
|
komplett auf Englisch übersetzt, Hilfetext-Ausrichtung korrigiert.
|