diff --git a/net/tsaddr/tsaddr.go b/net/tsaddr/tsaddr.go index 76dd65f82..44cf5cf23 100644 --- a/net/tsaddr/tsaddr.go +++ b/net/tsaddr/tsaddr.go @@ -71,6 +71,17 @@ func Tailscale4To6Range() netaddr.IPPrefix { return ula4To6Range.v } +// Tailscale4To6Placeholder returns an IP address that can be used as +// a source IP when one is required, but a netmap didn't provide +// any. This address never gets allocated by the 4-to-6 algorithm in +// control. +// +// Currently used to work around a Windows limitation when programming +// IPv6 routes in corner cases. +func Tailscale4To6Placeholder() netaddr.IP { + return Tailscale4To6Range().IP +} + // Tailscale4To6 returns a Tailscale IPv6 address that maps 1:1 to the // given Tailscale IPv4 address. Returns a zero IP if ipv4 isn't a // Tailscale IPv4 address. diff --git a/wgengine/router/ifconfig_windows.go b/wgengine/router/ifconfig_windows.go index 9e7f4be3b..4a331319f 100644 --- a/wgengine/router/ifconfig_windows.go +++ b/wgengine/router/ifconfig_windows.go @@ -21,6 +21,7 @@ import ( "golang.org/x/sys/windows" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "tailscale.com/net/interfaces" + "tailscale.com/net/tsaddr" "tailscale.com/wgengine/winnet" ) @@ -305,7 +306,17 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) { foundDefault4 := false foundDefault6 := false for _, route := range cfg.Routes { - if (route.IP.Is4() && firstGateway4 == nil) || (route.IP.Is6() && firstGateway6 == nil) { + if route.IP.Is6() && firstGateway6 == nil { + // Windows won't let us set IPv6 routes without having an + // IPv6 local address set. However, when we've configured + // a default route, we want to forcibly grab IPv6 traffic + // even if the v6 overlay network isn't configured. To do + // that, we add a dummy local IPv6 address to serve as a + // route source. + ipnet := &net.IPNet{tsaddr.Tailscale4To6Placeholder().IPAddr().IP, net.CIDRMask(128, 128)} + addresses = append(addresses, ipnet) + firstGateway6 = &ipnet.IP + } else if route.IP.Is4() && firstGateway4 == nil { return errors.New("Due to a Windows limitation, one cannot have interface routes without an interface address") }