From af78c5d86cc584100eb71da9d8ce19800de25d60 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 1 Mar 2019 17:17:32 +0100 Subject: ifaceconfig: allow for null defaults --- service/ifaceconfig.go | 88 ++++++++++++++++++++++++++++++++++------------- service/service_tunnel.go | 10 +----- 2 files changed, 66 insertions(+), 32 deletions(-) (limited to 'service') diff --git a/service/ifaceconfig.go b/service/ifaceconfig.go index c405939c..71cb7e5b 100644 --- a/service/ifaceconfig.go +++ b/service/ifaceconfig.go @@ -6,12 +6,14 @@ package service import ( + "encoding/binary" "errors" "golang.org/x/sys/windows" "golang.zx2c4.com/winipcfg" "golang.zx2c4.com/wireguard/windows/conf" "net" "os" + "unsafe" ) const ( @@ -19,44 +21,84 @@ const ( sockoptIPV6_UNICAST_IF = 31 ) -func bindSocketToMonitoredDefault(bind *NativeBind) error { - defaultIface, err := winipcfg.DefaultInterface(winipcfg.AF_INET) - if err != nil { - return err - } - sysconn, err := bind.ipv4.SyscallConn() - if err != nil { - return err +func htonl(val int) int { + bytes := make([]byte, 4) + binary.BigEndian.PutUint32(bytes, uint32(val)) + return int(*(*uint32)(unsafe.Pointer(&bytes[0]))) +} + +func bindSocketRoutes(bind *NativeBind, index4 int, index6 int) error { + if index4 != -1 { + sysconn, err := bind.ipv4.SyscallConn() + if err != nil { + return err + } + err2 := sysconn.Control(func(fd uintptr) { + err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptIP_UNICAST_IF, htonl(index4)) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } } - err2 := sysconn.Control(func(fd uintptr) { - err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptIP_UNICAST_IF, int(htonl(defaultIface.Index))) - }) - if err2 != nil { - return err2 + + if index6 != -1 { + sysconn, err := bind.ipv6.SyscallConn() + if err != nil { + return err + } + err2 := sysconn.Control(func(fd uintptr) { + // The lack of htonl here is not a bug. MSDN actually specifies big endian for one and little endian for the other. + err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptIPV6_UNICAST_IF, index6) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } } + + return nil + +} + +func getDefaultInterfaces() (index4 int, index6 int, err error) { + //TODO: this should be expanded to be able to exclude our current interface index + + index4 = -1 + index6 = -1 + defaultIface, err := winipcfg.DefaultInterface(winipcfg.AF_INET) if err != nil { - return err + return -1, -1, err + } + if defaultIface != nil { + index4 = int(defaultIface.Index) } + defaultIface, err = winipcfg.DefaultInterface(winipcfg.AF_INET6) if err != nil { - return err + return -1, -1, err + } + if defaultIface != nil { + index6 = int(defaultIface.Ipv6IfIndex) } - sysconn, err = bind.ipv6.SyscallConn() + return +} + +func monitorDefaultRoutes(bind *NativeBind) error { + index4, index6, err := getDefaultInterfaces() if err != nil { return err } - err2 = sysconn.Control(func(fd uintptr) { - err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptIPV6_UNICAST_IF, int(defaultIface.Ipv6IfIndex)) - }) - if err2 != nil { - return err2 - } + err = bindSocketRoutes(bind, index4, index6) if err != nil { return err } return nil - //TODO: monitor for changes, and make sure we're using default modulo us } diff --git a/service/service_tunnel.go b/service/service_tunnel.go index 02be70aa..750a4302 100644 --- a/service/service_tunnel.go +++ b/service/service_tunnel.go @@ -7,11 +7,9 @@ package service import ( "bufio" - "encoding/binary" "fmt" "log" "strings" - "unsafe" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/debug" @@ -44,12 +42,6 @@ type tunnelService struct { debug bool } -func htonl(val uint32) uint32 { - bytes := make([]byte, 4) - binary.BigEndian.PutUint32(bytes, val) - return *(*uint32)(unsafe.Pointer(&bytes[0])) -} - func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) { changes <- svc.Status{State: svc.StartPending} @@ -140,7 +132,7 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, } ipcSetOperation(device, bufio.NewReader(strings.NewReader(uapiConf))) - err = bindSocketToMonitoredDefault(device.net.bind.(*NativeBind)) + err = monitorDefaultRoutes(device.net.bind.(*NativeBind)) if err != nil { logger.Error.Println("Unable to bind sockets to default route:", err) changes <- svc.Status{State: svc.StopPending} -- cgit v1.2.3-59-g8ed1b