From ab2518f77c565a93bfaa9f5c8179cad0408471cb Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 21 Oct 2019 13:32:13 +0200 Subject: tunnel: blackhole sockets when there's going to be a sure routing loop This prevents against common mishaps when changing from a wifi network that supports v6 to one that doesn't. Reported-by: Jonathan Tooker --- go.mod | 4 ++-- go.sum | 8 ++++---- tunnel/defaultroutemonitor.go | 17 +++++++++-------- tunnel/interfacewatcher.go | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 03a68009..7cfc0a00 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ require ( github.com/lxn/win v0.0.0-20190919090605-24c5960b03d8 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 - golang.org/x/sys v0.0.0-20191010194322-b09406accb47 + golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2 golang.org/x/text v0.3.2 - golang.zx2c4.com/wireguard v0.0.20191013-0.20191017134306-ae492d1b3599 + golang.zx2c4.com/wireguard v0.0.20191013-0.20191021112957-ffffbbcc8a33 ) replace ( diff --git a/go.sum b/go.sum index 677b6e3e..e86cb625 100644 --- a/go.sum +++ b/go.sum @@ -10,14 +10,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2 h1:nq114VpM8lsSlP+lyUbANecYHYiFcSNFtqcBlxRV+gA= +golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/wireguard v0.0.20191013-0.20191017134306-ae492d1b3599 h1:fHOjo1GyHRI2q/LcFB9NiFTqXB7WRiu2idShqqTwrZ4= -golang.zx2c4.com/wireguard v0.0.20191013-0.20191017134306-ae492d1b3599/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191021112957-ffffbbcc8a33 h1:uTdHRwI9oo7oVaoNfrl4kE4f4FU3ZlaN1Yv7IaJuMsI= +golang.zx2c4.com/wireguard v0.0.20191013-0.20191021112957-ffffbbcc8a33/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= golang.zx2c4.com/wireguard/windows v0.0.0-20190919090605-24c5960b03d8 h1:2CuUpdfLMlq7rEKdaFDmGBD3ZF/5tHuXyroxn7hI108= golang.zx2c4.com/wireguard/windows v0.0.0-20190919090605-24c5960b03d8/go.mod h1:ouWl4wViUNh8tPSIwxTVMuS014WakR1hqvBc2I0bMoA= golang.zx2c4.com/wireguard/windows v0.0.0-20191002091738-0f75593b0066 h1:UVT3IjRbQazaV5AU1LhIe7mnKx4GziE23kgjSWZE8UA= diff --git a/tunnel/defaultroutemonitor.go b/tunnel/defaultroutemonitor.go index 2d63e5db..72bab135 100644 --- a/tunnel/defaultroutemonitor.go +++ b/tunnel/defaultroutemonitor.go @@ -17,7 +17,7 @@ import ( "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" ) -func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLUID winipcfg.LUID, lastLUID *winipcfg.LUID, lastIndex *uint32) error { +func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLUID winipcfg.LUID, lastLUID *winipcfg.LUID, lastIndex *uint32, blackholeWhenLoop bool) error { r, err := winipcfg.GetIPForwardTable2(family) if err != nil { return err @@ -44,17 +44,18 @@ func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLU } *lastLUID = luid *lastIndex = index + blackhole := blackholeWhenLoop && index == 0 if family == windows.AF_INET { - log.Printf("Binding v4 socket to interface %d", index) - return device.BindSocketToInterface4(index) + log.Printf("Binding v4 socket to interface %d (blackhole=%v)", index, blackhole) + return device.BindSocketToInterface4(index, blackhole) } else if family == windows.AF_INET6 { - log.Printf("Binding v6 socket to interface %d", index) - return device.BindSocketToInterface6(index) + log.Printf("Binding v6 socket to interface %d (blackhole=%v)", index, blackhole) + return device.BindSocketToInterface6(index, blackhole) } return nil } -func monitorDefaultRoutes(family winipcfg.AddressFamily, device *device.Device, autoMTU bool, tun *tun.NativeTun) ([]winipcfg.ChangeCallback, error) { +func monitorDefaultRoutes(family winipcfg.AddressFamily, device *device.Device, autoMTU bool, blackholeWhenLoop bool, tun *tun.NativeTun) ([]winipcfg.ChangeCallback, error) { var minMTU uint32 if family == windows.AF_INET { minMTU = 576 @@ -63,10 +64,10 @@ func monitorDefaultRoutes(family winipcfg.AddressFamily, device *device.Device, } ourLUID := winipcfg.LUID(tun.LUID()) lastLUID := winipcfg.LUID(0) - lastIndex := uint32(0) + lastIndex := ^uint32(0) lastMTU := uint32(0) doIt := func() error { - err := bindSocketRoute(family, device, ourLUID, &lastLUID, &lastIndex) + err := bindSocketRoute(family, device, ourLUID, &lastLUID, &lastIndex, blackholeWhenLoop) if err != nil { return err } diff --git a/tunnel/interfacewatcher.go b/tunnel/interfacewatcher.go index 92d08e90..1f632725 100644 --- a/tunnel/interfacewatcher.go +++ b/tunnel/interfacewatcher.go @@ -10,6 +10,7 @@ import ( "sync" "golang.org/x/sys/windows" + "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun" @@ -41,6 +42,44 @@ type interfaceWatcher struct { storedEvents []interfaceWatcherEvent } +func hasDefaultRoute(family winipcfg.AddressFamily, peers []conf.Peer) bool { + var ( + foundV401 bool + foundV41281 bool + foundV600001 bool + foundV680001 bool + foundV400 bool + foundV600 bool + v40 = [4]byte{} + v60 = [16]byte{} + v48 = [4]byte{0x80} + v68 = [16]byte{0x80} + ) + for _, peer := range peers { + for _, allowedip := range peer.AllowedIPs { + if allowedip.Cidr == 1 && len(allowedip.IP) == 16 && allowedip.IP.Equal(v60[:]) { + foundV600001 = true + } else if allowedip.Cidr == 1 && len(allowedip.IP) == 16 && allowedip.IP.Equal(v68[:]) { + foundV680001 = true + } else if allowedip.Cidr == 1 && len(allowedip.IP) == 4 && allowedip.IP.Equal(v40[:]) { + foundV401 = true + } else if allowedip.Cidr == 1 && len(allowedip.IP) == 4 && allowedip.IP.Equal(v48[:]) { + foundV41281 = true + } else if allowedip.Cidr == 0 && len(allowedip.IP) == 16 && allowedip.IP.Equal(v60[:]) { + foundV600 = true + } else if allowedip.Cidr == 0 && len(allowedip.IP) == 4 && allowedip.IP.Equal(v40[:]) { + foundV400 = true + } + } + } + if family == windows.AF_INET { + return foundV400 || (foundV401 && foundV41281) + } else if family == windows.AF_INET6 { + return foundV600 || (foundV600001 && foundV680001) + } + return false +} + func (iw *interfaceWatcher) setup(family winipcfg.AddressFamily) { var changeCallbacks *[]winipcfg.ChangeCallback var ipversion string @@ -62,7 +101,7 @@ func (iw *interfaceWatcher) setup(family winipcfg.AddressFamily) { var err error log.Printf("Monitoring default %s routes", ipversion) - *changeCallbacks, err = monitorDefaultRoutes(family, iw.device, iw.conf.Interface.MTU == 0, iw.tun) + *changeCallbacks, err = monitorDefaultRoutes(family, iw.device, iw.conf.Interface.MTU == 0, hasDefaultRoute(family, iw.conf.Peers), iw.tun) if err != nil { iw.errors <- interfaceWatcherError{services.ErrorBindSocketsToDefaultRoutes, err} return -- cgit v1.2.3-59-g8ed1b