diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-07-12 15:53:10 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2021-08-02 19:10:58 +0200 |
commit | 5409c45a10dc7a045197bc4105c6a7bd5d29283f (patch) | |
tree | e64f9e7e09a4f3d965659413487781f452800256 /manager | |
parent | version: bump (diff) | |
download | wireguard-windows-5409c45a10dc7a045197bc4105c6a7bd5d29283f.tar.xz wireguard-windows-5409c45a10dc7a045197bc4105c6a7bd5d29283f.zip |
driver: introduce new module for talking with kernel driver
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'manager')
-rw-r--r-- | manager/interfacecleanup.go | 51 | ||||
-rw-r--r-- | manager/ipc_driver.go | 59 | ||||
-rw-r--r-- | manager/ipc_server.go | 83 | ||||
-rw-r--r-- | manager/service.go | 2 |
4 files changed, 155 insertions, 40 deletions
diff --git a/manager/interfacecleanup.go b/manager/interfacecleanup.go index c270f4ab..32976b79 100644 --- a/manager/interfacecleanup.go +++ b/manager/interfacecleanup.go @@ -11,33 +11,66 @@ import ( "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/mgr" - "golang.zx2c4.com/wireguard/tun/wintun" - "golang.zx2c4.com/wireguard/tun" + "golang.zx2c4.com/wireguard/tun/wintun" + "golang.zx2c4.com/wireguard/windows/conf" + "golang.zx2c4.com/wireguard/windows/driver" "golang.zx2c4.com/wireguard/windows/services" ) -func cleanupStaleWintunInterfaces() { +func cleanupStaleNetworkInterfaces() { m, err := mgr.Connect() if err != nil { return } defer m.Disconnect() - tun.WintunPool.DeleteMatchingAdapters(func(wintun *wintun.Adapter) bool { - interfaceName, err := wintun.Name() + if conf.AdminBool("ExperimentalKernelDriver") { + driver.DefaultPool.DeleteMatchingAdapters(func(wintun *driver.Adapter) bool { + interfaceName, err := wintun.Name() + if err != nil { + log.Printf("Removing network adapter because determining interface name failed: %v", err) + return true + } + serviceName, err := services.ServiceNameOfTunnel(interfaceName) + if err != nil { + log.Printf("Removing network adapter ‘%s’ because determining tunnel service name failed: %v", interfaceName, err) + return true + } + service, err := m.OpenService(serviceName) + if err == windows.ERROR_SERVICE_DOES_NOT_EXIST { + log.Printf("Removing network adapter ‘%s’ because no service for it exists", interfaceName) + return true + } else if err != nil { + return false + } + defer service.Close() + status, err := service.Query() + if err != nil { + return false + } + if status.State == svc.Stopped { + log.Printf("Removing network adapter ‘%s’ because its service is stopped", interfaceName) + return true + } + return false + }) + } + + tun.WintunPool.DeleteMatchingAdapters(func(adapter *wintun.Adapter) bool { + interfaceName, err := adapter.Name() if err != nil { - log.Printf("Removing Wintun interface because determining interface name failed: %v", err) + log.Printf("Removing network adapter because determining interface name failed: %v", err) return true } serviceName, err := services.ServiceNameOfTunnel(interfaceName) if err != nil { - log.Printf("Removing Wintun interface ‘%s’ because determining tunnel service name failed: %v", interfaceName, err) + log.Printf("Removing network adapter ‘%s’ because determining tunnel service name failed: %v", interfaceName, err) return true } service, err := m.OpenService(serviceName) if err == windows.ERROR_SERVICE_DOES_NOT_EXIST { - log.Printf("Removing Wintun interface ‘%s’ because no service for it exists", interfaceName) + log.Printf("Removing network adapter ‘%s’ because no service for it exists", interfaceName) return true } else if err != nil { return false @@ -48,7 +81,7 @@ func cleanupStaleWintunInterfaces() { return false } if status.State == svc.Stopped { - log.Printf("Removing Wintun interface ‘%s’ because its service is stopped", interfaceName) + log.Printf("Removing network adapter ‘%s’ because its service is stopped", interfaceName) return true } return false diff --git a/manager/ipc_driver.go b/manager/ipc_driver.go new file mode 100644 index 00000000..dae213de --- /dev/null +++ b/manager/ipc_driver.go @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. + */ + +package manager + +import ( + "sync" + + "golang.zx2c4.com/wireguard/windows/driver" +) + +type lockedDriverAdapter struct { + *driver.Adapter + sync.Mutex +} + +var driverAdapters = make(map[string]*lockedDriverAdapter) +var driverAdaptersLock sync.RWMutex + +func findDriverAdapter(tunnelName string) (*lockedDriverAdapter, error) { + driverAdaptersLock.RLock() + driverAdapter, ok := driverAdapters[tunnelName] + if ok { + driverAdapter.Lock() + driverAdaptersLock.RUnlock() + return driverAdapter, nil + } + driverAdaptersLock.RUnlock() + driverAdaptersLock.Lock() + defer driverAdaptersLock.Unlock() + driverAdapter, ok = driverAdapters[tunnelName] + if ok { + driverAdapter.Lock() + return driverAdapter, nil + } + driverAdapter = &lockedDriverAdapter{} + var err error + driverAdapter.Adapter, err = driver.DefaultPool.OpenAdapter(tunnelName) + if err != nil { + return nil, err + } + driverAdapters[tunnelName] = driverAdapter + driverAdapter.Lock() + return driverAdapter, nil +} + +func releaseDriverAdapter(tunnelName string) { + driverAdaptersLock.Lock() + defer driverAdaptersLock.Unlock() + driverAdapter, ok := driverAdapters[tunnelName] + if !ok { + return + } + driverAdapter.Lock() + delete(driverAdapters, tunnelName) + driverAdapter.Unlock() +} diff --git a/manager/ipc_server.go b/manager/ipc_server.go index 9a36e60f..b9b1eb8c 100644 --- a/manager/ipc_server.go +++ b/manager/ipc_server.go @@ -47,41 +47,64 @@ func (s *ManagerService) StoredConfig(tunnelName string) (*conf.Config, error) { } func (s *ManagerService) RuntimeConfig(tunnelName string) (*conf.Config, error) { - storedConfig, err := conf.LoadFromName(tunnelName) - if err != nil { - return nil, err - } - pipe, err := connectTunnelServicePipe(tunnelName) - if err != nil { - return nil, err - } - pipe.SetDeadline(time.Now().Add(time.Second * 2)) - _, err = pipe.Write([]byte("get=1\n\n")) - if err == windows.ERROR_NO_DATA { - log.Println("IPC pipe closed unexpectedly, so reopening") - pipe.Unlock() - disconnectTunnelServicePipe(tunnelName) - pipe, err = connectTunnelServicePipe(tunnelName) + if conf.AdminBool("ExperimentalKernelDriver") { + storedConfig, err := conf.LoadFromName(tunnelName) + if err != nil { + return nil, err + } + driverAdapter, err := findDriverAdapter(tunnelName) + if err != nil { + return nil, err + } + runtimeConfig, err := driverAdapter.Configuration() + if err != nil { + driverAdapter.Unlock() + releaseDriverAdapter(tunnelName) + return nil, err + } + conf := conf.FromDriverConfiguration(runtimeConfig, storedConfig) + driverAdapter.Unlock() + if s.elevatedToken == 0 { + conf.Redact() + } + return conf, nil + } else { + storedConfig, err := conf.LoadFromName(tunnelName) + if err != nil { + return nil, err + } + pipe, err := connectTunnelServicePipe(tunnelName) if err != nil { return nil, err } pipe.SetDeadline(time.Now().Add(time.Second * 2)) _, err = pipe.Write([]byte("get=1\n\n")) - } - if err != nil { + if err == windows.ERROR_NO_DATA { + log.Println("IPC pipe closed unexpectedly, so reopening") + pipe.Unlock() + disconnectTunnelServicePipe(tunnelName) + pipe, err = connectTunnelServicePipe(tunnelName) + if err != nil { + return nil, err + } + pipe.SetDeadline(time.Now().Add(time.Second * 2)) + _, err = pipe.Write([]byte("get=1\n\n")) + } + if err != nil { + pipe.Unlock() + disconnectTunnelServicePipe(tunnelName) + return nil, err + } + conf, err := conf.FromUAPI(pipe, storedConfig) pipe.Unlock() - disconnectTunnelServicePipe(tunnelName) - return nil, err - } - conf, err := conf.FromUAPI(pipe, storedConfig) - pipe.Unlock() - if err != nil { - return nil, err - } - if s.elevatedToken == 0 { - conf.Redact() + if err != nil { + return nil, err + } + if s.elevatedToken == 0 { + conf.Redact() + } + return conf, nil } - return conf, nil } func (s *ManagerService) Start(tunnelName string) error { @@ -116,7 +139,7 @@ func (s *ManagerService) Start(tunnelName string) error { } }() } - time.AfterFunc(time.Second*10, cleanupStaleWintunInterfaces) + time.AfterFunc(time.Second*10, cleanupStaleNetworkInterfaces) // After that process is started -- it's somewhat asynchronous -- we install the new one. c, err := conf.LoadFromName(tunnelName) @@ -131,7 +154,7 @@ func (s *ManagerService) Start(tunnelName string) error { } func (s *ManagerService) Stop(tunnelName string) error { - time.AfterFunc(time.Second*10, cleanupStaleWintunInterfaces) + time.AfterFunc(time.Second*10, cleanupStaleNetworkInterfaces) err := UninstallTunnel(tunnelName) if err == windows.ERROR_SERVICE_DOES_NOT_EXIST { diff --git a/manager/service.go b/manager/service.go index da6ff497..9555d386 100644 --- a/manager/service.go +++ b/manager/service.go @@ -254,7 +254,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest }() } - time.AfterFunc(time.Second*10, cleanupStaleWintunInterfaces) + time.AfterFunc(time.Second*10, cleanupStaleNetworkInterfaces) go checkForUpdates() var sessionsPointer *windows.WTS_SESSION_INFO |