diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-02-25 18:47:03 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-02-28 08:05:02 +0100 |
commit | 37b80faa2a933ada72c52bf189fce38c8770d21f (patch) | |
tree | 2184c0d2782f81ace9b2e78e4bbc554a534fc393 /service/service_tunnel.go | |
parent | conf: introduce configuration management (diff) | |
download | wireguard-windows-37b80faa2a933ada72c52bf189fce38c8770d21f.tar.xz wireguard-windows-37b80faa2a933ada72c52bf189fce38c8770d21f.zip |
service: introduce base of services
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to '')
-rw-r--r-- | service/service_tunnel.go | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/service/service_tunnel.go b/service/service_tunnel.go new file mode 100644 index 00000000..b1f1df60 --- /dev/null +++ b/service/service_tunnel.go @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package service + +import ( + "bufio" + "log" + "net" + "strings" + + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/debug" + "golang.org/x/sys/windows/svc/eventlog" + + "golang.zx2c4.com/winipcfg" + "golang.zx2c4.com/wireguard/windows/conf" + "golang.zx2c4.com/wireguard/windows/service/tun" +) + +type confElogger struct { + elog debug.Log + conf *conf.Config + level int +} + +func (elog confElogger) Write(p []byte) (n int, err error) { + msg := elog.conf.Name + ": " + string(p) + n = len(msg) + switch elog.level { + case 1: + err = elog.elog.Info(1, msg) + case 2: + err = elog.elog.Warning(1, msg) + case 3: + err = elog.elog.Error(1, msg) + } + return +} + +type tunnelService struct { + path string + debug bool +} + +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 + } + } + + 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 + } + + logger := &Logger{ + Debug: log.New(&confElogger{elog: elog, conf: conf, level: 1}, "", 0), + Info: log.New(&confElogger{elog: elog, conf: conf, level: 2}, "", 0), + Error: log.New(&confElogger{elog: elog, conf: conf, level: 3}, "", 0), + } + + logger.Info.Println("Starting wireguard-go version", WireGuardGoVersion) + logger.Debug.Println("Debug log enabled") + + tun, err := tun.CreateTUN(conf.Name) + if err == nil { + realInterfaceName, err2 := tun.Name() + if err2 == nil { + conf.Name = realInterfaceName + } + } else { + logger.Error.Println("Failed to create TUN device:", err) + changes <- svc.Status{State: svc.StopPending} + exitCode = ERROR_ADAP_HDW_ERR + return + } + + device := NewDevice(tun, logger) + device.Up() + logger.Info.Println("Device started") + + 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 + } + 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))) + + //TODO: configure addresses, routes, and DNS with winipcfg + iface, err := winipcfg.InterfaceFromFriendlyName(conf.Name) + if err == nil { + a := make([]*net.IPNet, len(conf.Interface.Addresses)) + for i, addr := range conf.Interface.Addresses { + a[i] = &net.IPNet{addr.IP, net.CIDRMask(int(addr.Cidr), len(addr.IP))} + } + err = iface.SetAddresses(a) + } + if err != nil { + logger.Error.Println("Unable to setup interface addresses:", 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 + 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 + } + } + + changes <- svc.Status{State: svc.StopPending} + logger.Info.Println("Shutting down") + uapi.Close() + device.Close() + return +} |