feat(network): VLAN/bridge/bond interface provisioner + IP-address apply

Fügt zwei neue systemd-oneshot-Services hinzu:
- edgeguard-interfaces.service: erstellt VLAN/bridge/bond-Interfaces
  (ip link add/del) wenn der Operator sie über die GUI anlegt/entfernt.
  Ethernet + WireGuard bleiben OS-managed.
- edgeguard-ipaddresses.service: bindet/entfernt IP-Adressen (ip addr
  add/del) nach jeder GUI-Mutation; läuft jetzt After=edgeguard-interfaces
  damit Interfaces immer vor den Adressen existieren.

Beide Services triggern per applyAsync() in den zugehörigen Handlern
(networks.go → Interfaces, ipaddresses.go → Adressen). Diff-Ansatz
über *-applied.conf verhindert dass manuell gebundene Adressen/
Interfaces angefasst werden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-30 13:25:26 +02:00
parent eaa6a04234
commit 0ee754e231
6 changed files with 408 additions and 11 deletions

View File

@@ -121,6 +121,12 @@ edgeguard ALL=(postgres) NOPASSWD: /usr/bin/pg_dump --clean --if-exists --no-own
# Static-Routes: API ruft `sudo systemctl restart edgeguard-routes.service`
# nach jedem Mutate, damit das apply-Skript die neue routes.conf anwendet.
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart edgeguard-routes.service
# Network-Interfaces: API ruft `sudo systemctl restart edgeguard-interfaces.service`
# nach jedem Mutate (Create/Update/Delete) von VLAN/bridge/bond-Interfaces.
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart edgeguard-interfaces.service
# IP-Addresses: API ruft `sudo systemctl restart edgeguard-ipaddresses.service`
# nach jedem Mutate (Create/Update/Delete).
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart edgeguard-ipaddresses.service
# Self-Upgrade-Pfad (handlers/system.go → /system/upgrade). Whitelist
# nur die exakte Unit-Form, damit edgeguard NICHT beliebige systemd-
# Units anlegen darf.
@@ -400,6 +406,167 @@ ROUTESUNIT
chown "$EG_USER":"$EG_USER" /etc/edgeguard/routes.conf
fi
# ── Network-Interfaces apply-script + systemd unit ───────────
# Verwaltet aus /etc/edgeguard/interfaces.conf. VLAN/bridge/bond-
# Interfaces die der Operator anlegt werden sofort via
# `systemctl restart edgeguard-interfaces.service` erstellt.
# Ethernet + WireGuard werden vom OS bzw. wg-quick verwaltet,
# nicht von diesem Skript. Diff-Ansatz analog ip-addresses.
cat > /usr/sbin/edgeguard-apply-interfaces <<'APPLYIFACES'
#!/bin/bash
# Managed by edgeguard — DO NOT EDIT.
CONF=/etc/edgeguard/interfaces.conf
APPLIED=/var/lib/edgeguard/interfaces-applied.conf
create_iface() {
local typ="$1" name="$2" parent="$3" vlan_id="$4" mtu="$5" members="$6"
case "$typ" in
vlan)
ip link add link "$parent" name "$name" type vlan id "$vlan_id" || return 1
;;
bridge)
ip link add "$name" type bridge || return 1
if [ -n "$members" ]; then
echo "$members" | tr ',' '\n' | while read -r m; do
[ -n "$m" ] && ip link set "$m" master "$name" 2>/dev/null || true
done
fi
;;
bond)
ip link add "$name" type bond || return 1
if [ -n "$members" ]; then
echo "$members" | tr ',' '\n' | while read -r m; do
[ -n "$m" ] && { ip link set "$m" down 2>/dev/null; ip link set "$m" master "$name" 2>/dev/null || true; }
done
fi
;;
*) return 0 ;;
esac
[ -n "$mtu" ] && ip link set "$name" mtu "$mtu" 2>/dev/null || true
ip link set "$name" up 2>/dev/null || true
}
# Entferne Interfaces die im letzten Apply waren, aber jetzt nicht mehr
if [ -f "$APPLIED" ]; then
while IFS='|' read -r typ name rest; do
[ -z "$typ" ] && continue
case "$typ" in '#'*) continue;; esac
if ! awk -F'|' -v n="$name" 'NR>2 && $2==n {found=1} END{exit !found}' "$CONF" 2>/dev/null; then
ip link set "$name" down 2>/dev/null || true
ip link del "$name" 2>/dev/null || true
fi
done < "$APPLIED"
fi
[ -f "$CONF" ] || { : > "$APPLIED"; exit 0; }
# Erstelle/aktualisiere Interfaces aus Config
while IFS='|' read -r typ name parent vlan_id mtu members; do
[ -z "$typ" ] && continue
case "$typ" in '#'*) continue;; esac
if ! ip link show "$name" >/dev/null 2>&1; then
if ! create_iface "$typ" "$name" "$parent" "$vlan_id" "$mtu" "$members"; then
echo "edgeguard-interfaces: failed to create $typ $name" >&2
fi
else
[ -n "$mtu" ] && ip link set "$name" mtu "$mtu" 2>/dev/null || true
ip link set "$name" up 2>/dev/null || true
fi
done < "$CONF"
cp "$CONF" "$APPLIED"
APPLYIFACES
chmod 0755 /usr/sbin/edgeguard-apply-interfaces
chown root:root /usr/sbin/edgeguard-apply-interfaces
cat > /etc/systemd/system/edgeguard-interfaces.service <<'IFACESUNIT'
[Unit]
Description=EdgeGuard managed network interfaces apply
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/edgeguard-apply-interfaces
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
IFACESUNIT
systemctl daemon-reload
systemctl enable edgeguard-interfaces.service >/dev/null 2>&1 || true
# Initialer Apply — leere /etc/edgeguard/interfaces.conf ist ok
systemctl start edgeguard-interfaces.service 2>/dev/null || true
if [ ! -f /etc/edgeguard/interfaces.conf ]; then
: > /etc/edgeguard/interfaces.conf
chown "$EG_USER":"$EG_USER" /etc/edgeguard/interfaces.conf
fi
# ── IP-Addresses apply-script + systemd unit ─────────────────
# Verwaltet aus /etc/edgeguard/ip-addresses.conf. Adressen die
# der Operator über die GUI hinzufügt/entfernt werden sofort via
# `systemctl restart edgeguard-ipaddresses.service` angewendet.
# Diff-Ansatz: /var/lib/edgeguard/ip-addresses-applied.conf hält
# den zuletzt angewendeten Stand; alte Adressen werden entfernt,
# neue hinzugefügt — manuell gebundene Adressen bleiben intakt.
cat > /usr/sbin/edgeguard-apply-ipaddresses <<'APPLYIP'
#!/bin/bash
# Managed by edgeguard — DO NOT EDIT.
set -e
CONF=/etc/edgeguard/ip-addresses.conf
APPLIED=/var/lib/edgeguard/ip-addresses-applied.conf
# Entferne Adressen die im letzten Apply-Lauf waren, aber jetzt nicht mehr
if [ -f "$APPLIED" ]; then
while IFS='|' read -r dev addrpfx; do
[ -z "$dev" ] && continue
case "$dev" in '#'*) continue;; esac
# Nur entfernen wenn nicht mehr in der neuen Config
if ! grep -qxF "${dev}|${addrpfx}" "$CONF" 2>/dev/null; then
ip addr del "$addrpfx" dev "$dev" 2>/dev/null || true
fi
done < "$APPLIED"
fi
[ -f "$CONF" ] || { : > "$APPLIED"; exit 0; }
# Füge neue Adressen hinzu
while IFS='|' read -r dev addrpfx; do
[ -z "$dev" ] && continue
case "$dev" in '#'*) continue;; esac
ip addr add "$addrpfx" dev "$dev" 2>/dev/null || true
done < "$CONF"
# Aktuelle Config als "applied" speichern
cp "$CONF" "$APPLIED"
APPLYIP
chmod 0755 /usr/sbin/edgeguard-apply-ipaddresses
chown root:root /usr/sbin/edgeguard-apply-ipaddresses
cat > /etc/systemd/system/edgeguard-ipaddresses.service <<'IPADDRUNIT'
[Unit]
Description=EdgeGuard managed IP addresses apply
After=network-online.target edgeguard-interfaces.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/edgeguard-apply-ipaddresses
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
IPADDRUNIT
systemctl daemon-reload
systemctl enable edgeguard-ipaddresses.service >/dev/null 2>&1 || true
systemctl start edgeguard-ipaddresses.service 2>/dev/null || true
if [ ! -f /etc/edgeguard/ip-addresses.conf ]; then
: > /etc/edgeguard/ip-addresses.conf
chown "$EG_USER":"$EG_USER" /etc/edgeguard/ip-addresses.conf
fi
# ── Keepalived notify-scripts installieren ───────────────────
# Die Skripte liegen im Package unter /usr/lib/edgeguard/ und
# werden von Keepalived als notify_master / notify_backup / check