package wireguard import ( "fmt" "os/exec" "strings" ) // Status of a WireGuard interface. type Status string const ( StatusUp Status = "UP" StatusDown Status = "DOWN" ) // Up brings up the given interface via wg-quick. func Up(iface string) error { return run("wg-quick", "up", iface) } // Down brings down the given interface via wg-quick. func Down(iface string) error { return run("wg-quick", "down", iface) } // Reload applies config changes to a running interface without a full restart, // using `wg syncconf` against a stripped config (wg-quick strip). func Reload(iface, confPath string) error { strip := exec.Command("wg-quick", "strip", confPath) stripped, err := strip.Output() if err != nil { return fmt.Errorf("wg-quick strip: %w", err) } sync := exec.Command("wg", "syncconf", iface, "/dev/stdin") sync.Stdin = strings.NewReader(string(stripped)) if out, err := sync.CombinedOutput(); err != nil { return fmt.Errorf("wg syncconf: %w: %s", err, out) } return nil } // IsUp checks whether the interface currently exists / is up. func IsUp(iface string) bool { cmd := exec.Command("wg", "show", iface) return cmd.Run() == nil } func GetStatus(iface string) Status { if IsUp(iface) { return StatusUp } return StatusDown } // EnableService enables and starts the systemd wg-quick@.service unit. func EnableService(iface string) error { if err := run("systemctl", "enable", "wg-quick@"+iface); err != nil { return err } return run("systemctl", "start", "wg-quick@"+iface) } // DisableService stops and disables the systemd wg-quick@.service unit. func DisableService(iface string) error { if err := run("systemctl", "stop", "wg-quick@"+iface); err != nil { return err } return run("systemctl", "disable", "wg-quick@"+iface) } func run(name string, args ...string) error { cmd := exec.Command(name, args...) if out, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("%s %s: %w: %s", name, strings.Join(args, " "), err, out) } return nil }