aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-03-01 02:05:13 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2019-03-01 02:05:13 +0100
commite9178b2e6e10100cc26751e8240d8e1cdd936fe5 (patch)
tree40328a4922042d951aca3a7643860b9896c6c7b2
parenttunnel: make winipcfg sort of work (diff)
downloadwireguard-windows-e9178b2e6e10100cc26751e8240d8e1cdd936fe5.tar.xz
wireguard-windows-e9178b2e6e10100cc26751e8240d8e1cdd936fe5.zip
tunnel: solve "the tunnel routing problem" on windows
This incredible trick lets roaming work and also keeps our routing rules significantly simpler.
-rw-r--r--service/service_tunnel.go34
1 files changed, 34 insertions, 0 deletions
diff --git a/service/service_tunnel.go b/service/service_tunnel.go
index f600aa36..c3ddf9e4 100644
--- a/service/service_tunnel.go
+++ b/service/service_tunnel.go
@@ -7,12 +7,14 @@ package service
import (
"bufio"
+ "encoding/binary"
"golang.org/x/sys/windows"
"golang.zx2c4.com/winipcfg"
"log"
"net"
"os"
"strings"
+ "unsafe"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/debug"
@@ -45,6 +47,12 @@ 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}
@@ -129,6 +137,32 @@ func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest,
}
ipcSetOperation(device, bufio.NewReader(strings.NewReader(uapiConf)))
+ //TODO: This needs more error checking and to be done in a notifier whenever the default route changes.
+ defaultV4, err := winipcfg.DefaultInterface(winipcfg.AF_INET)
+ if err == nil {
+ sysconn, _ := device.net.bind.(*NativeBind).ipv4.SyscallConn()
+ sysconn.Control(func(fd uintptr) {
+ err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, 31 /* IP_UNICAST_IF */, int(htonl(defaultV4.Index)))
+ if err != nil {
+ logger.Error.Println("Failed to set IPv4 default interface on socket:", err)
+ }
+ })
+ } else {
+ logger.Error.Println("Unable to determine default IPv4 interface:", err)
+ }
+ defaultV6, err := winipcfg.DefaultInterface(winipcfg.AF_INET6)
+ if err == nil {
+ sysconn, _ := device.net.bind.(*NativeBind).ipv6.SyscallConn()
+ sysconn.Control(func(fd uintptr) {
+ err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, 31 /* IPV6_UNICAST_IF */, int(defaultV6.Ipv6IfIndex))
+ if err != nil {
+ logger.Error.Println("Failed to set IPv6 default interface on socket:", err)
+ }
+ })
+ } else {
+ logger.Error.Println("Unable to determine default IPv6 interface:", err)
+ }
+
guid := wintun.(*tun.NativeTun).GUID()
iface, err := winipcfg.InterfaceFromGUID(&guid)
if err != nil {