From e7f4071c4bea0406773cb6bfa6501ba4a3a94501 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 3 Mar 2019 03:25:43 +0100 Subject: tunnel: simplify shutdown --- main.go | 12 +------ service/errors.go | 2 +- service/install.go | 9 ++--- service/service_tunnel.go | 84 ++++++++++++++++++++++------------------------- 4 files changed, 43 insertions(+), 64 deletions(-) diff --git a/main.go b/main.go index 2620b0ce..58526681 100644 --- a/main.go +++ b/main.go @@ -24,7 +24,6 @@ var flags = [...]string{ "/uninstalltunnelservice CONFIG_PATH", "/managerservice", "/tunnelservice CONFIG_PATH", - "/tunneldebug CONFIG_PATH", "/ui CMD_READ_HANDLE CMD_WRITE_HANDLE CMD_EVENT_HANDLE", } @@ -131,16 +130,7 @@ func main() { if len(os.Args) != 3 { usage() } - err := service.RunTunnel(os.Args[2], false) - if err != nil { - fatal(err) - } - return - case "/tunneldebug": - if len(os.Args) != 3 { - usage() - } - err := service.RunTunnel(os.Args[2], true) + err := service.RunTunnel(os.Args[2]) if err != nil { fatal(err) } diff --git a/service/errors.go b/service/errors.go index 133617ea..04cedb45 100644 --- a/service/errors.go +++ b/service/errors.go @@ -18,6 +18,6 @@ const ( ERROR_NETWORK_BUSY uint32 = 0x00000036 ERROR_NO_TRACKING_SERVICE uint32 = 0x00000494 ERROR_OBJECT_ALREADY_EXISTS uint32 = 0x00001392 - ERROR_SERVICE_DOES_NOT_EXIST uint32 = 0x00000424 + ERROR_SERVICE_DOES_NOT_EXIST uint32 = 0x00000424 ERROR_SERVICE_MARKED_FOR_DELETE uint32 = 0x00000430 ) diff --git a/service/install.go b/service/install.go index 95a419de..bb2fb046 100644 --- a/service/install.go +++ b/service/install.go @@ -9,7 +9,6 @@ import ( "errors" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" - svcdbg "golang.org/x/sys/windows/svc/debug" "golang.org/x/sys/windows/svc/mgr" "golang.zx2c4.com/wireguard/windows/conf" "os" @@ -184,14 +183,10 @@ func UninstallTunnel(name string) error { return err2 } -func RunTunnel(confPath string, debug bool) error { +func RunTunnel(confPath string) error { name, err := conf.NameFromPath(confPath) if err != nil { return err } - if debug { - return svcdbg.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, true}) - } else { - return svc.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, false}) - } + return svc.Run("WireGuard Tunnel: "+name, &tunnelService{confPath}) } diff --git a/service/service_tunnel.go b/service/service_tunnel.go index 6eff6fa5..b97bea17 100644 --- a/service/service_tunnel.go +++ b/service/service_tunnel.go @@ -8,11 +8,13 @@ package service import ( "bufio" "fmt" + "golang.zx2c4.com/winipcfg" "log" + "net" + "runtime/debug" "strings" "golang.org/x/sys/windows/svc" - "golang.org/x/sys/windows/svc/debug" "golang.org/x/sys/windows/svc/eventlog" "golang.zx2c4.com/wireguard/windows/conf" @@ -20,7 +22,7 @@ import ( ) type confElogger struct { - elog debug.Log + elog *eventlog.Log conf *conf.Config level int } @@ -38,31 +40,44 @@ func (elog confElogger) Write(p []byte) (n int, err error) { } type tunnelService struct { - path string - debug bool + path string } func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) { changes <- svc.Status{State: svc.StartPending} - var elog debug.Log - var err error - if service.debug { - elog = debug.New("WireGuard") - } else { - //TODO: remember to clean this up in the msi uninstaller - eventlog.InstallAsEventCreate("WireGuard", eventlog.Info|eventlog.Warning|eventlog.Error) - elog, err = eventlog.Open("WireGuard") - if err != nil { - changes <- svc.Status{State: svc.StopPending} - exitCode = ERROR_LOG_CONTAINER_OPEN_FAILED - return + var device *Device + var uapi net.Listener + var routeChangeCallback *winipcfg.RouteChangeCallback + var elog *eventlog.Log + + defer func() { + changes <- svc.Status{State: svc.StopPending} + if routeChangeCallback != nil { + routeChangeCallback.Unregister() + } + if uapi != nil { + uapi.Close() } + if device != nil { + device.Close() + } + if elog != nil { + elog.Info(1, "Shutting down") + } + }() + + //TODO: remember to clean this up in the msi uninstaller + eventlog.InstallAsEventCreate("WireGuard", eventlog.Info|eventlog.Warning|eventlog.Error) + elog, err := eventlog.Open("WireGuard") + if err != nil { + exitCode = ERROR_LOG_CONTAINER_OPEN_FAILED + return } log.SetOutput(elogger{elog}) defer func() { if x := recover(); x != nil { - elog.Error(1, fmt.Sprint(x)) + elog.Error(1, fmt.Sprintf("%v:\n%s", x, string(debug.Stack()))) panic(x) } }() @@ -70,7 +85,6 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, conf, err := conf.LoadFromPath(service.path) if err != nil { elog.Error(1, "Unable to load configuration file from path "+service.path+": "+err.Error()) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_OPEN_FAILED return } @@ -92,90 +106,70 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, } } else { logger.Error.Println("Failed to create TUN device:", err) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_ADAP_HDW_ERR return } - device := NewDevice(wintun, logger) + device = NewDevice(wintun, logger) device.Up() logger.Info.Println("Device started") - uapi, err := UAPIListen(conf.Name) + uapi, err = UAPIListen(conf.Name) if err != nil { logger.Error.Println("Failed to listen on uapi socket:", err) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_PIPE_LISTENING - device.Close() return } - errs := make(chan error) go func() { for { conn, err := uapi.Accept() if err != nil { - errs <- err - return + continue } go ipcHandle(device, conn) } }() logger.Info.Println("UAPI listener started") + uapiConf, err := conf.ToUAPI() if err != nil { logger.Error.Println("Failed to convert to UAPI serialization:", err) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_INVALID_PARAMETER - device.Close() return } ipcSetOperation(device, bufio.NewReader(strings.NewReader(uapiConf))) guid := wintun.(*tun.NativeTun).GUID() - routeMonitorCallback, err := monitorDefaultRoutes(device.net.bind.(*NativeBind), &guid) + routeChangeCallback, err = monitorDefaultRoutes(device.net.bind.(*NativeBind), &guid) if err != nil { logger.Error.Println("Unable to bind sockets to default route:", err) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_NETWORK_BUSY - device.Close() return } err = configureInterface(conf, &guid) if err != nil { logger.Error.Println("Unable to set interface addresses, routes, DNS, or IP settings:", err) - changes <- svc.Status{State: svc.StopPending} exitCode = ERROR_NETWORK_BUSY - device.Close() return } changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop} -loop: for { select { case c := <-r: switch c.Cmd { case svc.Stop: - break loop + return case svc.Interrogate: changes <- c.CurrentStatus default: logger.Error.Printf("Unexpected service control request #%d", c) } - case <-errs: - break loop case <-device.Wait(): - break loop + return } } - - changes <- svc.Status{State: svc.StopPending} - logger.Info.Println("Shutting down") - routeMonitorCallback.Unregister() - uapi.Close() - device.Close() - return } -- cgit v1.2.3-59-g8ed1b