ipadm: Port-Forwarding hinzufügen (-pa/-pl/-pd) + nftables-Include verdrahten

- ipadm verwaltet jetzt auch WAN->LAN Port-Forwards, referenziert per
  Hostname aus der bestehenden Host-DB (folgt IP-Änderungen automatisch)
- ipadm -u generiert zusätzlich /etc/nftables.d/portforward.conf, validiert
  via 'nft -c -f' und reloadet nftables (Rollback bei ungültiger Config,
  wie beim dnsmasq-Teil)
- /etc/nftables.conf bindet dafür neu /etc/nftables.d/*.conf ein
- Host-Store-Locking-Logik in generischen LineStore[T] extrahiert, von
  Host- und PortForward-Store gemeinsam genutzt
This commit is contained in:
2026-08-18 11:43:29 +02:00
parent cfb184eebe
commit 8591223aca
8 changed files with 653 additions and 147 deletions
+62 -21
View File
@@ -1,10 +1,10 @@
# ipadm
Kleines Go-CLI-Tool zur Verwaltung statischer Hosts (DHCP-Reservierung +
DNS-Eintrag) für den dnsmasq-Router auf narcissus. Ersetzt/lehnt sich an das
Original-Tool `ipadm` (dhcp/bind management, mwx'2021) an, arbeitet aber
gegen unseren dnsmasq-Stack statt isc-dhcp-server/bind9 (siehe
[../../README.md](../../README.md)).
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`.
@@ -12,18 +12,34 @@ Installiert auf dem Server unter `/usr/local/bin/ipadm`.
- 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.
- `ipadm -u` generiert daraus `/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 die komplette dnsmasq-Konfiguration
(`dnsmasq --test`) und lädt dnsmasq bei Erfolg neu
(`systemctl reload dnsmasq`). Schlägt die Validierung fehl, wird die
vorherige `hosts.conf` automatisch wiederhergestellt und dnsmasq **nicht**
neu geladen.
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 reloadet die zugehörigen
Dienste:
- `/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 reload dnsmasq`.
- `/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`.
Schlägt die jeweilige Validierung fehl, wird die vorherige generierte
Datei automatisch wiederhergestellt und der betroffene Dienst **nicht**
neu geladen. 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 in
`10.0.0.0/24` liegen und **außerhalb** des dynamischen DHCP-Pools
`10.0.0.100–10.0.0.200` (verhindert Kollisionen mit dynamisch vergebenen
Adressen).
- 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
@@ -36,13 +52,32 @@ 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 -u update (dnsmasq-Config regenerieren + reload)
ipadm -pa [-f] <hostname> <wan-port> [lan-port] [tcp|udp|both]
add port-forward zu bekanntem Host
ipadm -pl list port-forwards
ipadm -pd <wan-port> [tcp|udp|both] delete port-forward
ipadm -u update (dnsmasq+nftables-Config regenerieren + reload)
ipadm -h this help
```
Nach jeder Änderung an der Host-DB (`-a`, `-c`, `-i`, `-m`, `-r`, `-d`,
interaktiv) muss `ipadm -u` ausgeführt werden, damit dnsmasq die Änderung
tatsächlich übernimmt — das Tool weist nach jeder Änderung selbst darauf hin.
Beispiel:
```sh
ipadm -a webserver 10.0.0.10 # Host anlegen (falls noch nicht vorhanden)
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)
```
`lan-port` und Protokoll bei `-pa` sind optional und 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
@@ -58,16 +93,22 @@ Alle Pfade 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_LAN_CIDR=10.0.0.0/24
export IPADM_POOL_START=10.0.0.100
export IPADM_POOL_END=10.0.0.200
export IPADM_WAN_IFACE=enp3s0
./ipadm -a testhost 10.0.0.50 aa:bb:cc:dd:ee:ff
./ipadm -l
```
Achtung: `ipadm -u` ruft trotzdem `dnsmasq --test` (prüft die echte
System-Konfiguration in `/etc/dnsmasq.conf` + `/etc/dnsmasq.d/`) und bei
Erfolg `systemctl reload dnsmasq` auf, auch im Testmodus — das ist
beabsichtigt (validiert, dass die generierte Datei mit der echten
Umgebung zusammenspielt), aber es reloadet den echten laufenden Dienst.
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 reload dnsmasq`/`systemctl reload nftables`, auch
im Testmodus — das ist beabsichtigt (validiert, dass die generierte Datei
mit der echten Umgebung zusammenspielt), aber es reloadet die echten
laufenden Dienste. `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.