mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
net/netns: add windows support.
Also remove rebinding logic from the windows router. Magicsock will instead rebind based on link change signals. Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
3f4d93feb2
commit
8f5b52e571
@ -15,7 +15,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
L 💣 github.com/mdlayher/netlink/nlenc from github.com/jsimonetti/rtnetlink+
|
L 💣 github.com/mdlayher/netlink/nlenc from github.com/jsimonetti/rtnetlink+
|
||||||
github.com/peterbourgon/ff/v2 from github.com/peterbourgon/ff/v2/ffcli
|
github.com/peterbourgon/ff/v2 from github.com/peterbourgon/ff/v2/ffcli
|
||||||
github.com/peterbourgon/ff/v2/ffcli from tailscale.com/cmd/tailscale/cli
|
github.com/peterbourgon/ff/v2/ffcli from tailscale.com/cmd/tailscale/cli
|
||||||
W 💣 github.com/tailscale/winipcfg-go from tailscale.com/wgengine/router
|
W 💣 github.com/tailscale/winipcfg-go from tailscale.com/net/interfaces+
|
||||||
💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+
|
💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+
|
||||||
💣 github.com/tailscale/wireguard-go/device from tailscale.com/wgengine+
|
💣 github.com/tailscale/wireguard-go/device from tailscale.com/wgengine+
|
||||||
github.com/tailscale/wireguard-go/device/tokenbucket from github.com/tailscale/wireguard-go/device
|
github.com/tailscale/wireguard-go/device/tokenbucket from github.com/tailscale/wireguard-go/device
|
||||||
@ -55,7 +55,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
tailscale.com/net/dnscache from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/net/dnscache from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/net/interfaces from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/net/interfaces from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/net/netns from tailscale.com/control/controlclient+
|
💣 tailscale.com/net/netns from tailscale.com/control/controlclient+
|
||||||
tailscale.com/net/stun from tailscale.com/net/netcheck+
|
tailscale.com/net/stun from tailscale.com/net/netcheck+
|
||||||
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
||||||
tailscale.com/net/tsaddr from tailscale.com/ipn+
|
tailscale.com/net/tsaddr from tailscale.com/ipn+
|
||||||
@ -66,6 +66,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
💣 tailscale.com/syncs from tailscale.com/net/interfaces+
|
💣 tailscale.com/syncs from tailscale.com/net/interfaces+
|
||||||
tailscale.com/tailcfg from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/tailcfg from tailscale.com/cmd/tailscale/cli+
|
||||||
DW tailscale.com/tempfork/osexec from tailscale.com/portlist
|
DW tailscale.com/tempfork/osexec from tailscale.com/portlist
|
||||||
|
W tailscale.com/tsconst from tailscale.com/net/interfaces
|
||||||
tailscale.com/types/empty from tailscale.com/control/controlclient+
|
tailscale.com/types/empty from tailscale.com/control/controlclient+
|
||||||
tailscale.com/types/key from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/types/key from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
|
||||||
@ -81,7 +82,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
tailscale.com/wgengine/magicsock from tailscale.com/wgengine
|
tailscale.com/wgengine/magicsock from tailscale.com/wgengine
|
||||||
💣 tailscale.com/wgengine/monitor from tailscale.com/cmd/tailscale/cli+
|
💣 tailscale.com/wgengine/monitor from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/wgengine/packet from tailscale.com/wgengine+
|
tailscale.com/wgengine/packet from tailscale.com/wgengine+
|
||||||
💣 tailscale.com/wgengine/router from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/wgengine/router from tailscale.com/cmd/tailscale/cli+
|
||||||
💣 tailscale.com/wgengine/router/dns from tailscale.com/ipn+
|
💣 tailscale.com/wgengine/router/dns from tailscale.com/ipn+
|
||||||
tailscale.com/wgengine/tsdns from tailscale.com/ipn+
|
tailscale.com/wgengine/tsdns from tailscale.com/ipn+
|
||||||
tailscale.com/wgengine/tstun from tailscale.com/wgengine
|
tailscale.com/wgengine/tstun from tailscale.com/wgengine
|
||||||
|
@ -19,7 +19,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
L 💣 github.com/mdlayher/netlink from github.com/jsimonetti/rtnetlink+
|
L 💣 github.com/mdlayher/netlink from github.com/jsimonetti/rtnetlink+
|
||||||
L 💣 github.com/mdlayher/netlink/nlenc from github.com/jsimonetti/rtnetlink+
|
L 💣 github.com/mdlayher/netlink/nlenc from github.com/jsimonetti/rtnetlink+
|
||||||
github.com/pborman/getopt/v2 from tailscale.com/cmd/tailscaled
|
github.com/pborman/getopt/v2 from tailscale.com/cmd/tailscaled
|
||||||
W 💣 github.com/tailscale/winipcfg-go from tailscale.com/wgengine/router
|
W 💣 github.com/tailscale/winipcfg-go from tailscale.com/net/interfaces+
|
||||||
💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+
|
💣 github.com/tailscale/wireguard-go/conn from github.com/tailscale/wireguard-go/device+
|
||||||
💣 github.com/tailscale/wireguard-go/device from tailscale.com/wgengine+
|
💣 github.com/tailscale/wireguard-go/device from tailscale.com/wgengine+
|
||||||
github.com/tailscale/wireguard-go/device/tokenbucket from github.com/tailscale/wireguard-go/device
|
github.com/tailscale/wireguard-go/device/tokenbucket from github.com/tailscale/wireguard-go/device
|
||||||
@ -60,7 +60,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/net/dnscache from tailscale.com/derp/derphttp+
|
tailscale.com/net/dnscache from tailscale.com/derp/derphttp+
|
||||||
tailscale.com/net/interfaces from tailscale.com/ipn+
|
tailscale.com/net/interfaces from tailscale.com/ipn+
|
||||||
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
|
tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock
|
||||||
tailscale.com/net/netns from tailscale.com/control/controlclient+
|
💣 tailscale.com/net/netns from tailscale.com/control/controlclient+
|
||||||
💣 tailscale.com/net/netstat from tailscale.com/ipn/ipnserver
|
💣 tailscale.com/net/netstat from tailscale.com/ipn/ipnserver
|
||||||
tailscale.com/net/stun from tailscale.com/net/netcheck+
|
tailscale.com/net/stun from tailscale.com/net/netcheck+
|
||||||
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
tailscale.com/net/tlsdial from tailscale.com/control/controlclient+
|
||||||
@ -73,6 +73,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
💣 tailscale.com/syncs from tailscale.com/net/interfaces+
|
💣 tailscale.com/syncs from tailscale.com/net/interfaces+
|
||||||
tailscale.com/tailcfg from tailscale.com/control/controlclient+
|
tailscale.com/tailcfg from tailscale.com/control/controlclient+
|
||||||
DW tailscale.com/tempfork/osexec from tailscale.com/portlist
|
DW tailscale.com/tempfork/osexec from tailscale.com/portlist
|
||||||
|
W tailscale.com/tsconst from tailscale.com/net/interfaces
|
||||||
tailscale.com/types/empty from tailscale.com/control/controlclient+
|
tailscale.com/types/empty from tailscale.com/control/controlclient+
|
||||||
tailscale.com/types/key from tailscale.com/derp+
|
tailscale.com/types/key from tailscale.com/derp+
|
||||||
tailscale.com/types/logger from tailscale.com/cmd/tailscaled+
|
tailscale.com/types/logger from tailscale.com/cmd/tailscaled+
|
||||||
@ -89,7 +90,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/wgengine/magicsock from tailscale.com/cmd/tailscaled+
|
tailscale.com/wgengine/magicsock from tailscale.com/cmd/tailscaled+
|
||||||
💣 tailscale.com/wgengine/monitor from tailscale.com/wgengine
|
💣 tailscale.com/wgengine/monitor from tailscale.com/wgengine
|
||||||
tailscale.com/wgengine/packet from tailscale.com/wgengine+
|
tailscale.com/wgengine/packet from tailscale.com/wgengine+
|
||||||
💣 tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
||||||
💣 tailscale.com/wgengine/router/dns from tailscale.com/ipn+
|
💣 tailscale.com/wgengine/router/dns from tailscale.com/ipn+
|
||||||
tailscale.com/wgengine/tsdns from tailscale.com/ipn+
|
tailscale.com/wgengine/tsdns from tailscale.com/ipn+
|
||||||
tailscale.com/wgengine/tstun from tailscale.com/wgengine
|
tailscale.com/wgengine/tstun from tailscale.com/wgengine
|
||||||
|
@ -219,7 +219,6 @@ func (nm *NetworkMap) JSON() string {
|
|||||||
AllowSingleHosts WGConfigFlags = 1 << iota
|
AllowSingleHosts WGConfigFlags = 1 << iota
|
||||||
AllowSubnetRoutes
|
AllowSubnetRoutes
|
||||||
AllowDefaultRoute
|
AllowDefaultRoute
|
||||||
HackDefaultRoute
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// EndpointDiscoSuffix is appended to the hex representation of a peer's discovery key
|
// EndpointDiscoSuffix is appended to the hex representation of a peer's discovery key
|
||||||
@ -274,10 +273,6 @@ func (nm *NetworkMap) WGCfg(logf logger.Logf, flags WGConfigFlags) (*wgcfg.Confi
|
|||||||
logf("wgcfg: %v skipping default route", peer.Key.ShortString())
|
logf("wgcfg: %v skipping default route", peer.Key.ShortString())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (flags & HackDefaultRoute) != 0 {
|
|
||||||
allowedIP = wgcfg.CIDR{IP: wgcfg.IPv4(10, 0, 0, 0), Mask: 8}
|
|
||||||
logf("wgcfg: %v converting default route => %v", peer.Key.ShortString(), allowedIP.String())
|
|
||||||
}
|
|
||||||
} else if allowedIP.Mask < 32 {
|
} else if allowedIP.Mask < 32 {
|
||||||
if (flags & AllowSubnetRoutes) == 0 {
|
if (flags & AllowSubnetRoutes) == 0 {
|
||||||
logf("wgcfg: %v skipping subnet route", peer.Key.ShortString())
|
logf("wgcfg: %v skipping subnet route", peer.Key.ShortString())
|
||||||
|
@ -953,12 +953,6 @@ func (b *LocalBackend) authReconfig() {
|
|||||||
flags |= controlclient.AllowDefaultRoute
|
flags |= controlclient.AllowDefaultRoute
|
||||||
// TODO(apenwarr): Make subnet routes a different pref?
|
// TODO(apenwarr): Make subnet routes a different pref?
|
||||||
flags |= controlclient.AllowSubnetRoutes
|
flags |= controlclient.AllowSubnetRoutes
|
||||||
// TODO(apenwarr): Remove this once we sort out subnet routes.
|
|
||||||
// Right now default routes are broken in Windows, but
|
|
||||||
// controlclient doesn't properly send subnet routes. So
|
|
||||||
// let's convert a default route into a subnet route in order
|
|
||||||
// to allow experimentation.
|
|
||||||
flags |= controlclient.HackDefaultRoute
|
|
||||||
}
|
}
|
||||||
if uc.AllowSingleHosts {
|
if uc.AllowSingleHosts {
|
||||||
flags |= controlclient.AllowSingleHosts
|
flags |= controlclient.AllowSingleHosts
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/tailscale/winipcfg-go"
|
||||||
"go4.org/mem"
|
"go4.org/mem"
|
||||||
"inet.af/netaddr"
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/tsconst"
|
||||||
"tailscale.com/util/lineread"
|
"tailscale.com/util/lineread"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,3 +73,22 @@ func likelyHomeRouterIPWindows() (ret netaddr.IP, ok bool) {
|
|||||||
})
|
})
|
||||||
return ret, !ret.IsZero()
|
return ret, !ret.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NonTailscaleMTUs returns a map of interface LUID to interface MTU,
|
||||||
|
// for all interfaces except Tailscale tunnels.
|
||||||
|
func NonTailscaleMTUs() (map[uint64]uint32, error) {
|
||||||
|
ifs, err := winipcfg.GetInterfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := map[uint64]uint32{}
|
||||||
|
for _, iface := range ifs {
|
||||||
|
if iface.Description == tsconst.WintunInterfaceDesc {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret[iface.Luid] = iface.Mtu
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !linux
|
// +build !linux,!windows
|
||||||
|
|
||||||
package netns
|
package netns
|
||||||
|
|
||||||
|
123
net/netns/netns_windows.go
Normal file
123
net/netns/netns_windows.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package netns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/tailscale/winipcfg-go"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
"tailscale.com/net/interfaces"
|
||||||
|
)
|
||||||
|
|
||||||
|
// control binds c to the Windows interface that holds a default
|
||||||
|
// route, and is not the Tailscale WinTun interface.
|
||||||
|
func control(network, address string, c syscall.RawConn) error {
|
||||||
|
canV4, canV6 := false, false
|
||||||
|
switch network {
|
||||||
|
case "tcp", "udp":
|
||||||
|
canV4, canV6 = true, true
|
||||||
|
case "tcp4", "udp4":
|
||||||
|
canV4 = true
|
||||||
|
case "tcp6", "udp6":
|
||||||
|
canV6 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if canV4 {
|
||||||
|
if4, err := getDefaultInterface(winipcfg.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := bindSocket4(c, if4); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if canV6 {
|
||||||
|
if6, err := getDefaultInterface(winipcfg.AF_INET6)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := bindSocket6(c, if6); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDefaultInterface returns the index of the interface that has the
|
||||||
|
// non-Tailscale default route for the given address family.
|
||||||
|
func getDefaultInterface(family winipcfg.AddressFamily) (ifidx uint32, err error) {
|
||||||
|
ifs, err := interfaces.NonTailscaleMTUs()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err := winipcfg.GetRoutes(family)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bestMetric := ^uint32(0)
|
||||||
|
// The zero index means "unspecified". If we end up passing zero
|
||||||
|
// to bindSocket*(), it unsets the binding and lets the socket
|
||||||
|
// behave as normal again, which is what we want if there's no
|
||||||
|
// default route we can use.
|
||||||
|
var index uint32
|
||||||
|
for _, route := range routes {
|
||||||
|
if route.DestinationPrefix.PrefixLength != 0 || ifs[route.InterfaceLuid] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if route.Metric < bestMetric {
|
||||||
|
bestMetric = route.Metric
|
||||||
|
index = route.InterfaceIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const sockoptBoundInterface = 31
|
||||||
|
|
||||||
|
// bindSocket4 binds the given RawConn to the network interface with
|
||||||
|
// index ifidx, for IPv4 traffic only.
|
||||||
|
func bindSocket4(c syscall.RawConn, ifidx uint32) error {
|
||||||
|
// For v4 the interface index must be passed as a big-endian
|
||||||
|
// integer, regardless of platform endianness.
|
||||||
|
index := nativeToBigEndian(ifidx)
|
||||||
|
var controlErr error
|
||||||
|
err := c.Control(func(fd uintptr) {
|
||||||
|
controlErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptBoundInterface, int(index))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return controlErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindSocket6 binds the given RawConn to the network interface with
|
||||||
|
// index ifidx, for IPv6 traffic only.
|
||||||
|
func bindSocket6(c syscall.RawConn, ifidx uint32) error {
|
||||||
|
var controlErr error
|
||||||
|
err := c.Control(func(fd uintptr) {
|
||||||
|
controlErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptBoundInterface, int(ifidx))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return controlErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// nativeToBigEndian returns i converted into big-endian
|
||||||
|
// representation, suitable for passing to Windows APIs that require a
|
||||||
|
// mangled uint32.
|
||||||
|
func nativeToBigEndian(i uint32) uint32 {
|
||||||
|
var b [4]byte
|
||||||
|
binary.BigEndian.PutUint32(b[:], i)
|
||||||
|
return *(*uint32)(unsafe.Pointer(&b[0]))
|
||||||
|
}
|
11
tsconst/interface.go
Normal file
11
tsconst/interface.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package tsconst exports some constants used elsewhere in the
|
||||||
|
// codebase.
|
||||||
|
package tsconst
|
||||||
|
|
||||||
|
// WintunInterfaceDesc is the description attached to Tailscale
|
||||||
|
// interfaces on Windows. This is set by our modified WinTun driver.
|
||||||
|
const WintunInterfaceDesc = "Tailscale Tunnel"
|
@ -7,115 +7,48 @@
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
ole "github.com/go-ole/go-ole"
|
ole "github.com/go-ole/go-ole"
|
||||||
winipcfg "github.com/tailscale/winipcfg-go"
|
winipcfg "github.com/tailscale/winipcfg-go"
|
||||||
"github.com/tailscale/wireguard-go/conn"
|
|
||||||
"github.com/tailscale/wireguard-go/device"
|
|
||||||
"github.com/tailscale/wireguard-go/tun"
|
"github.com/tailscale/wireguard-go/tun"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
|
"tailscale.com/net/interfaces"
|
||||||
"tailscale.com/wgengine/winnet"
|
"tailscale.com/wgengine/winnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// monitorDefaultRoutes subscribes to route change events and updates
|
||||||
sockoptIP_UNICAST_IF = 31
|
// the Tailscale tunnel interface's MTU to match that of the
|
||||||
sockoptIPV6_UNICAST_IF = 31
|
// underlying default route.
|
||||||
)
|
//
|
||||||
|
// This is an attempt at making the MTU mostly correct, but in
|
||||||
func htonl(val uint32) uint32 {
|
// practice this entire piece of code ends up just using the 1280
|
||||||
bytes := make([]byte, 4)
|
// value passed in at device construction time. This code might make
|
||||||
binary.BigEndian.PutUint32(bytes, val)
|
// the MTU go lower due to very low-MTU IPv4 interfaces.
|
||||||
return *(*uint32)(unsafe.Pointer(&bytes[0]))
|
//
|
||||||
}
|
// TODO: this code is insufficient to control the MTU correctly. The
|
||||||
|
// correct way to do it is per-peer PMTU discovery, and synthesizing
|
||||||
func bindSocketRoute(family winipcfg.AddressFamily, device *device.Device, ourLuid uint64, lastLuid *uint64) error {
|
// ICMP fragmentation-needed messages within tailscaled. This code may
|
||||||
routes, err := winipcfg.GetRoutes(family)
|
// address a few rare corner cases, but is unlikely to significantly
|
||||||
if err != nil {
|
// help with MTU issues compared to a static 1280B implementation.
|
||||||
return err
|
func monitorDefaultRoutes(tun *tun.NativeTun) (*winipcfg.RouteChangeCallback, error) {
|
||||||
}
|
|
||||||
lowestMetric := ^uint32(0)
|
|
||||||
index := uint32(0) // Zero is "unspecified", which for IP_UNICAST_IF resets the value, which is what we want.
|
|
||||||
luid := uint64(0) // Hopefully luid zero is unspecified, but hard to find docs saying so.
|
|
||||||
for _, route := range routes {
|
|
||||||
if route.DestinationPrefix.PrefixLength != 0 || route.InterfaceLuid == ourLuid {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if route.Metric < lowestMetric {
|
|
||||||
lowestMetric = route.Metric
|
|
||||||
index = route.InterfaceIndex
|
|
||||||
luid = route.InterfaceLuid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if luid == *lastLuid {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*lastLuid = luid
|
|
||||||
if false {
|
|
||||||
bind, ok := device.Bind().(conn.BindSocketToInterface)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unexpected device.Bind type %T", device.Bind())
|
|
||||||
}
|
|
||||||
// TODO(apenwarr): doesn't work with magic socket yet.
|
|
||||||
if family == winipcfg.AF_INET {
|
|
||||||
return bind.BindSocketToInterface4(index, false)
|
|
||||||
} else if family == winipcfg.AF_INET6 {
|
|
||||||
return bind.BindSocketToInterface6(index, false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Printf("WARNING: skipping windows socket binding.")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTun) (*winipcfg.RouteChangeCallback, error) {
|
|
||||||
guid := tun.GUID()
|
guid := tun.GUID()
|
||||||
ourLuid, err := winipcfg.InterfaceGuidToLuid(&guid)
|
ourLuid, err := winipcfg.InterfaceGuidToLuid(&guid)
|
||||||
lastLuid4 := uint64(0)
|
|
||||||
lastLuid6 := uint64(0)
|
|
||||||
lastMtu := uint32(0)
|
lastMtu := uint32(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
doIt := func() error {
|
doIt := func() error {
|
||||||
err = bindSocketRoute(winipcfg.AF_INET, device, ourLuid, &lastLuid4)
|
mtu, err := getDefaultRouteMTU()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = bindSocketRoute(winipcfg.AF_INET6, device, ourLuid, &lastLuid6)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("bindSocketRoute(AF_INET6): %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !autoMTU {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
mtu := uint32(0)
|
|
||||||
if lastLuid4 != 0 {
|
|
||||||
iface, err := winipcfg.InterfaceFromLUID(lastLuid4)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if iface.Mtu > 0 {
|
|
||||||
mtu = iface.Mtu
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if lastLuid6 != 0 {
|
|
||||||
iface, err := winipcfg.InterfaceFromLUID(lastLuid6)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if iface.Mtu > 0 && iface.Mtu < mtu {
|
|
||||||
mtu = iface.Mtu
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if mtu > 0 && (lastMtu == 0 || lastMtu != mtu) {
|
if mtu > 0 && (lastMtu == 0 || lastMtu != mtu) {
|
||||||
iface, err := winipcfg.GetIpInterface(ourLuid, winipcfg.AF_INET)
|
iface, err := winipcfg.GetIpInterface(ourLuid, winipcfg.AF_INET)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -136,7 +69,7 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tun.ForceMTU(int(iface.NlMtu)) //TODO: it sort of breaks the model with v6 mtu and v4 mtu being different. Just set v4 one for now.
|
tun.ForceMTU(int(iface.NlMtu))
|
||||||
iface, err = winipcfg.GetIpInterface(ourLuid, winipcfg.AF_INET6)
|
iface, err = winipcfg.GetIpInterface(ourLuid, winipcfg.AF_INET6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !isMissingIPv6Err(err) {
|
if !isMissingIPv6Err(err) {
|
||||||
@ -172,6 +105,56 @@ func monitorDefaultRoutes(device *device.Device, autoMTU bool, tun *tun.NativeTu
|
|||||||
return cb, nil
|
return cb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDefaultRouteMTU() (uint32, error) {
|
||||||
|
mtus, err := interfaces.NonTailscaleMTUs()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err := winipcfg.GetRoutes(winipcfg.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
best := ^uint32(0)
|
||||||
|
mtu := uint32(0)
|
||||||
|
for _, route := range routes {
|
||||||
|
if route.DestinationPrefix.PrefixLength != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
routeMTU := mtus[route.InterfaceLuid]
|
||||||
|
if routeMTU == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if route.Metric < best {
|
||||||
|
best = route.Metric
|
||||||
|
mtu = routeMTU
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err = winipcfg.GetRoutes(winipcfg.AF_INET6)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
best = ^uint32(0)
|
||||||
|
for _, route := range routes {
|
||||||
|
if route.DestinationPrefix.PrefixLength != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
routeMTU := mtus[route.InterfaceLuid]
|
||||||
|
if routeMTU == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if route.Metric < best {
|
||||||
|
best = route.Metric
|
||||||
|
if routeMTU < mtu {
|
||||||
|
mtu = routeMTU
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mtu, nil
|
||||||
|
}
|
||||||
|
|
||||||
func setFirewall(ifcGUID *windows.GUID) (bool, error) {
|
func setFirewall(ifcGUID *windows.GUID) (bool, error) {
|
||||||
c := ole.Connection{}
|
c := ole.Connection{}
|
||||||
err := c.Initialize()
|
err := c.Initialize()
|
||||||
@ -232,7 +215,6 @@ func setFirewall(ifcGUID *windows.GUID) (bool, error) {
|
|||||||
func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
||||||
const mtu = 0
|
const mtu = 0
|
||||||
guid := tun.GUID()
|
guid := tun.GUID()
|
||||||
log.Printf("wintun GUID is %v", guid)
|
|
||||||
iface, err := winipcfg.InterfaceFromGUID(&guid)
|
iface, err := winipcfg.InterfaceFromGUID(&guid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -332,7 +314,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
}
|
}
|
||||||
deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
|
deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
|
||||||
}
|
}
|
||||||
log.Printf("routes: %v", routes)
|
|
||||||
|
|
||||||
var errAcc error
|
var errAcc error
|
||||||
err = iface.SyncRoutes(deduplicatedRoutes)
|
err = iface.SyncRoutes(deduplicatedRoutes)
|
||||||
@ -346,7 +327,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
log.Printf("getipif: %v", err)
|
log.Printf("getipif: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("foundDefault4: %v", foundDefault4)
|
|
||||||
if foundDefault4 {
|
if foundDefault4 {
|
||||||
ipif.UseAutomaticMetric = false
|
ipif.UseAutomaticMetric = false
|
||||||
ipif.Metric = 0
|
ipif.Metric = 0
|
||||||
|
@ -49,13 +49,10 @@ func newUserspaceRouter(logf logger.Logf, wgdev *device.Device, tundev tun.Devic
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *winRouter) Up() error {
|
func (r *winRouter) Up() error {
|
||||||
// MonitorDefaultRoutes handles making sure our wireguard UDP
|
|
||||||
// traffic goes through the old route, not recursively through the VPN.
|
|
||||||
|
|
||||||
r.removeFirewallAcceptRule()
|
r.removeFirewallAcceptRule()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
r.routeChangeCallback, err = monitorDefaultRoutes(r.wgdev, true, r.nativeTun)
|
r.routeChangeCallback, err = monitorDefaultRoutes(r.nativeTun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("MonitorDefaultRoutes: %v", err)
|
log.Fatalf("MonitorDefaultRoutes: %v", err)
|
||||||
}
|
}
|
||||||
@ -116,6 +113,7 @@ func (r *winRouter) Close() error {
|
|||||||
if r.routeChangeCallback != nil {
|
if r.routeChangeCallback != nil {
|
||||||
r.routeChangeCallback.Unregister()
|
r.routeChangeCallback.Unregister()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user