aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/service
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-03-02 05:18:40 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2019-03-02 05:18:40 +0100
commit7d36922a3cb9d77e9c4ba4db3f70b34bc65b27dd (patch)
treee66ffb1e2b23aeba9f54c8f10eeaf02cdaa355cb /service
parentifaceconfig: allow for null defaults (diff)
downloadwireguard-windows-7d36922a3cb9d77e9c4ba4db3f70b34bc65b27dd.tar.xz
wireguard-windows-7d36922a3cb9d77e9c4ba4db3f70b34bc65b27dd.zip
ifaceconfig: monitor for changes to default interface
Diffstat (limited to 'service')
-rw-r--r--service/ifaceconfig.go85
-rw-r--r--service/service_tunnel.go6
2 files changed, 49 insertions, 42 deletions
diff --git a/service/ifaceconfig.go b/service/ifaceconfig.go
index 71cb7e5b..f8737128 100644
--- a/service/ifaceconfig.go
+++ b/service/ifaceconfig.go
@@ -21,20 +21,36 @@ const (
sockoptIPV6_UNICAST_IF = 31
)
-func htonl(val int) int {
+func htonl(val uint32) uint32 {
bytes := make([]byte, 4)
- binary.BigEndian.PutUint32(bytes, uint32(val))
- return int(*(*uint32)(unsafe.Pointer(&bytes[0])))
+ binary.BigEndian.PutUint32(bytes, val)
+ return *(*uint32)(unsafe.Pointer(&bytes[0]))
}
-func bindSocketRoutes(bind *NativeBind, index4 int, index6 int) error {
- if index4 != -1 {
+func bindSocketRoute(family winipcfg.AddressFamily, bind *NativeBind, ourLuid uint64) error {
+ routes, err := winipcfg.GetRoutes(family)
+ if err != nil {
+ return err
+ }
+ lowestMetric := ^uint32(0)
+ index := uint32(0) // Zero is "unspecified", which for IP_UNICAST_IF resets the value, which is what we want.
+ for _, route := range routes {
+ if route.DestinationPrefix.PrefixLength != 0 || route.InterfaceLuid == ourLuid {
+ continue
+ }
+ if route.Metric < lowestMetric {
+ lowestMetric = route.Metric
+ index = route.InterfaceIndex
+ }
+ }
+
+ if family == winipcfg.AF_INET {
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))
+ err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptIP_UNICAST_IF, int(htonl(index)))
})
if err2 != nil {
return err2
@@ -42,16 +58,15 @@ func bindSocketRoutes(bind *NativeBind, index4 int, index6 int) error {
if err != nil {
return err
}
- }
-
- if index6 != -1 {
+ return nil
+ } else if family == winipcfg.AF_INET6 {
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)
+ err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptIPV6_UNICAST_IF, int(index))
})
if err2 != nil {
return err2
@@ -60,46 +75,36 @@ func bindSocketRoutes(bind *NativeBind, index4 int, index6 int) error {
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)
+func monitorDefaultRoutes(bind *NativeBind, guid *windows.GUID) (*winipcfg.RouteChangeCallback, error) {
+ ourLuid, err := winipcfg.InterfaceGuidToLuid(guid)
if err != nil {
- return -1, -1, err
+ return nil, err
}
- if defaultIface != nil {
- index4 = int(defaultIface.Index)
- }
-
- defaultIface, err = winipcfg.DefaultInterface(winipcfg.AF_INET6)
- if err != nil {
- return -1, -1, err
- }
- if defaultIface != nil {
- index6 = int(defaultIface.Ipv6IfIndex)
+ doIt := func() error {
+ err = bindSocketRoute(winipcfg.AF_INET, bind, ourLuid)
+ if err != nil {
+ return err
+ }
+ err = bindSocketRoute(winipcfg.AF_INET6, bind, ourLuid)
+ if err != nil {
+ return err
+ }
+ return nil
}
- return
-}
-
-func monitorDefaultRoutes(bind *NativeBind) error {
- index4, index6, err := getDefaultInterfaces()
+ err = doIt()
if err != nil {
- return err
+ return nil, err
}
- err = bindSocketRoutes(bind, index4, index6)
+ cb, err := winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.Route) {
+ _ = doIt()
+ })
if err != nil {
- return err
+ return nil, err
}
-
- return nil
- //TODO: monitor for changes, and make sure we're using default modulo us
+ return cb, nil
}
func configureInterface(conf *conf.Config, guid *windows.GUID) error {
diff --git a/service/service_tunnel.go b/service/service_tunnel.go
index 750a4302..12a0d709 100644
--- a/service/service_tunnel.go
+++ b/service/service_tunnel.go
@@ -8,6 +8,7 @@ package service
import (
"bufio"
"fmt"
+ "golang.zx2c4.com/winipcfg"
"log"
"strings"
@@ -131,8 +132,9 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
return
}
ipcSetOperation(device, bufio.NewReader(strings.NewReader(uapiConf)))
+ guid := wintun.(*tun.NativeTun).GUID()
- err = monitorDefaultRoutes(device.net.bind.(*NativeBind))
+ routeMonitorCallback, 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}
@@ -141,7 +143,6 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
return
}
- guid := wintun.(*tun.NativeTun).GUID()
err = configureInterface(conf, &guid)
if err != nil {
logger.Error.Println("Unable to set interface addresses, routes, DNS, or IP settings:", err)
@@ -174,6 +175,7 @@ loop:
changes <- svc.Status{State: svc.StopPending}
logger.Info.Println("Shutting down")
+ winipcfg.UnregisterRouteChangeCallback(routeMonitorCallback)
uapi.Close()
device.Close()
return