- keepalived: pg_role='standby' hat Vorrang vor role für BACKUP-Bestimmung - keepalived-master.sh: gecrasht Dienste beim MASTER-Übergang starten (nicht nur reload) - confighash: ip_addresses per Interface-Name hashen statt per FK (Cross-Node-Drift-Fix) - TOTP/2FA: RFC 6238 — Setup-Flow, QR-Code, Admin-Disable; two-step Login - Firewall-UI: Enterprise-Design — auto-Beschreibung, icon-only Actions, zero-hit Indikator - fe80-Filter: Link-local IPv6 aus NTP/DNS Listen-Dropdowns entfernen - VIP-Dashboard, Dual-Path VRRP, GW-Tracking (Migrations 0033/0034) - Forward Proxy + DNS erweiterte Einstellungen (Migrations 0031/0032) - unbound-control: edgeguard in unbound-Gruppe via postinst Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
2.2 KiB
Go
64 lines
2.2 KiB
Go
package wireguard
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
)
|
|
|
|
// wg-quick is managed via systemd unit instances (wg-quick@<iface>).
|
|
// Reload-via-syncconf would be cheaper (no link flap) but needs more
|
|
// per-change diffing — for v1 we restart the unit, which takes ~1s
|
|
// and re-establishes peers cleanly. The sudoers entry shipped in
|
|
// postinst whitelists exactly these three commands.
|
|
|
|
func startWGQuick(iface string) error {
|
|
cmd := exec.Command("sudo", "-n", "/usr/bin/systemctl", "start", "wg-quick@"+iface+".service")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("systemctl start wg-quick@%s: %w: %s", iface, err, string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func restartWGQuick(iface string) error {
|
|
cmd := exec.Command("sudo", "-n", "/usr/bin/systemctl", "restart", "wg-quick@"+iface+".service")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("systemctl restart wg-quick@%s: %w: %s", iface, err, string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func stopWGQuick(iface string) error {
|
|
cmd := exec.Command("sudo", "-n", "/usr/bin/systemctl", "stop", "wg-quick@"+iface+".service")
|
|
// Ignore failures — unit may not exist.
|
|
_ = cmd.Run()
|
|
return nil
|
|
}
|
|
|
|
func enableWGQuick(iface string) error {
|
|
cmd := exec.Command("sudo", "-n", "/usr/bin/systemctl", "enable", "wg-quick@"+iface+".service")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("systemctl enable wg-quick@%s: %w: %s", iface, err, string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func disableWGQuick(iface string) error {
|
|
cmd := exec.Command("sudo", "-n", "/usr/bin/systemctl", "disable", "wg-quick@"+iface+".service")
|
|
// Ignore failures — unit may already be disabled.
|
|
_ = cmd.Run()
|
|
return nil
|
|
}
|
|
|
|
// symlinkWGQuickConf creates (or atomically replaces) the symlink
|
|
// /etc/wireguard/<iface>.conf → target via sudo. /etc/wireguard/ is
|
|
// owned root:root 700 so the edgeguard user cannot write to it directly;
|
|
// the sudoers entry in postinst whitelists exactly this ln command.
|
|
func symlinkWGQuickConf(iface, target string) error {
|
|
link := "/etc/wireguard/" + iface + ".conf"
|
|
cmd := exec.Command("sudo", "-n", "/bin/ln", "-sf", target, link)
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("ln -sf %s %s: %w: %s", target, link, err, string(out))
|
|
}
|
|
return nil
|
|
}
|