aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/service/service_tunnel.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-02-25 18:47:03 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2019-02-28 08:05:02 +0100
commit37b80faa2a933ada72c52bf189fce38c8770d21f (patch)
tree2184c0d2782f81ace9b2e78e4bbc554a534fc393 /service/service_tunnel.go
parentconf: introduce configuration management (diff)
downloadwireguard-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 'service/service_tunnel.go')
-rw-r--r--service/service_tunnel.go174
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
+}