@ -11,15 +11,14 @@ import (
"fmt"
"log"
"net"
"os"
"sort"
"time"
"github.com/go-multierror/multierror"
ole "github.com/go-ole/go-ole"
winipcfg "github.com/tailscale/winipcfg-go"
"github.com/tailscale/wireguard-go/tun"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"tailscale.com/net/interfaces"
"tailscale.com/wgengine/winnet"
)
@ -40,51 +39,51 @@ import (
// help with MTU issues compared to a static 1280B implementation.
func monitorDefaultRoutes ( tun * tun . NativeTun ) ( * winipcfg . RouteChangeCallback , error ) {
guid := tun . GUID ( )
ourLuid , err := winipcfg . InterfaceGuidToLuid ( & guid )
ourLuid , err := winipcfg . LUIDFromGUID ( & guid )
lastMtu := uint32 ( 0 )
if err != nil {
return nil , err
return nil , fmt. Errorf ( " error mapping GUID %v to LUID: %w", guid , err )
}
doIt := func ( ) error {
mtu , err := getDefaultRouteMTU ( )
if err != nil {
return err
return fmt. Errorf ( " error getting default route MTU: %w", err )
}
if mtu > 0 && ( lastMtu == 0 || lastMtu != mtu ) {
iface , err := winipcfg. GetIpInterface ( ourLuid , winipcfg . AF_INET )
iface , err := ourLuid. IPInterface ( windows . AF_INET )
if err != nil {
return err
return fmt. Errorf ( " error getting v4 interface: %w", err )
}
iface . N lMtu = mtu - 80
iface . N LMTU = mtu - 80
// If the TUN device was created with a smaller MTU,
// though, such as 1280, we don't want to go bigger than
// configured. (See the comment on minimalMTU in the
// wgengine package.)
if min , err := tun . MTU ( ) ; err == nil && min < int ( iface . N lMtu ) {
iface . N lMtu = uint32 ( min )
if min , err := tun . MTU ( ) ; err == nil && min < int ( iface . N LMTU ) {
iface . N LMTU = uint32 ( min )
}
if iface . N lMtu < 576 {
iface . N lMtu = 576
if iface . N LMTU < 576 {
iface . N LMTU = 576
}
err = iface . Set ( )
if err != nil {
return err
return fmt. Errorf ( " error setting v4 MTU: %w", err )
}
tun . ForceMTU ( int ( iface . N lMtu ) )
iface , err = winipcfg. GetIpInterface ( ourLuid , winipcfg . AF_INET6 )
tun . ForceMTU ( int ( iface . N LMTU ) )
iface , err = ourLuid. IPInterface ( windows . AF_INET6 )
if err != nil {
if ! isMissingIPv6Err ( err ) {
return err
if ! errors . Is ( err , windows . ERROR_NOT_FOUND ) {
return fmt. Errorf ( " error getting v6 interface: %w", err )
}
} else {
iface . N lMtu = mtu - 80
if iface . N lMtu < 1280 {
iface . N lMtu = 1280
iface . N LMTU = mtu - 80
if iface . N LMTU < 1280 {
iface . N LMTU = 1280
}
err = iface . Set ( )
if err != nil {
return err
return fmt. Errorf ( " error setting v6 MTU: %w", err )
}
}
lastMtu = mtu
@ -95,7 +94,7 @@ func monitorDefaultRoutes(tun *tun.NativeTun) (*winipcfg.RouteChangeCallback, er
if err != nil {
return nil , err
}
cb , err := winipcfg . RegisterRouteChangeCallback ( func ( notificationType winipcfg . MibNotificationType , route * winipcfg . Route ) {
cb , err := winipcfg . RegisterRouteChangeCallback ( func ( notificationType winipcfg . MibNotificationType , route * winipcfg . MibIPforwardRow2 ) {
//fmt.Printf("MonitorDefaultRoutes: changed: %v\n", route.DestinationPrefix)
if route . DestinationPrefix . PrefixLength == 0 {
_ = doIt ( )
@ -113,7 +112,7 @@ func getDefaultRouteMTU() (uint32, error) {
return 0 , err
}
routes , err := winipcfg . Get Routes( winipcfg . AF_INET )
routes , err := winipcfg . Get IPForwardTable2( windows . AF_INET )
if err != nil {
return 0 , err
}
@ -123,7 +122,7 @@ func getDefaultRouteMTU() (uint32, error) {
if route . DestinationPrefix . PrefixLength != 0 {
continue
}
routeMTU := mtus [ route . InterfaceL uid ]
routeMTU := mtus [ route . InterfaceL UID ]
if routeMTU == 0 {
continue
}
@ -133,7 +132,7 @@ func getDefaultRouteMTU() (uint32, error) {
}
}
routes , err = winipcfg . Get Routes( winipcfg . AF_INET6 )
routes , err = winipcfg . Get IPForwardTable2( windows . AF_INET6 )
if err != nil {
return 0 , err
}
@ -142,7 +141,7 @@ func getDefaultRouteMTU() (uint32, error) {
if route . DestinationPrefix . PrefixLength != 0 {
continue
}
routeMTU := mtus [ route . InterfaceL uid ]
routeMTU := mtus [ route . InterfaceL UID ]
if routeMTU == 0 {
continue
}
@ -215,16 +214,34 @@ func setPrivateNetwork(ifcGUID *windows.GUID) (bool, error) {
return false , nil
}
// interfaceFromGUID returns IPAdapterAddresses with specified GUID.
func interfaceFromGUID ( guid * windows . GUID , flags winipcfg . GAAFlags ) ( * winipcfg . IPAdapterAddresses , error ) {
luid , err := winipcfg . LUIDFromGUID ( guid )
if err != nil {
return nil , err
}
addresses , err := winipcfg . GetAdaptersAddresses ( windows . AF_UNSPEC , flags )
if err != nil {
return nil , err
}
for _ , addr := range addresses {
if addr . LUID == luid {
return addr , nil
}
}
return nil , fmt . Errorf ( "interfaceFromGUID: interface with LUID %v (from GUID %v) not found" , luid , guid )
}
func configureInterface ( cfg * Config , tun * tun . NativeTun ) error {
const mtu = 0
guid := tun . GUID ( )
iface , err := winipcfg . InterfaceFromGUIDEx ( & guid , & winipcfg . GetAdapterAddressesFlags {
iface , err := interfaceFromGUID ( & guid ,
// Issue 474: on early boot, when the network is still
// coming up, if the Tailscale service comes up first,
// the Tailscale adapter it finds might not have the
// IPv4 service available yet? Try this flag:
GAA_FLAG_INCLUDE_ALL_INTERFACES : true ,
} )
winipcfg. GAAFlagIncludeAllInterfaces ,
)
if err != nil {
return err
}
@ -327,6 +344,18 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
deduplicatedRoutes = append ( deduplicatedRoutes , & routes [ i ] )
}
// Re-read interface after syncAddresses.
iface , err = interfaceFromGUID ( & guid ,
// Issue 474: on early boot, when the network is still
// coming up, if the Tailscale service comes up first,
// the Tailscale adapter it finds might not have the
// IPv4 service available yet? Try this flag:
winipcfg . GAAFlagIncludeAllInterfaces ,
)
if err != nil {
return err
}
var errAcc error
err = syncRoutes ( iface , deduplicatedRoutes )
if err != nil && errAcc == nil {
@ -334,7 +363,7 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
errAcc = err
}
ipif , err := iface . GetIpInterface ( winipcfg . AF_INET )
ipif , err := iface . LUID . IPInterface ( windows . AF_INET )
if err != nil {
log . Printf ( "getipif: %v" , err )
return err
@ -344,17 +373,17 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
ipif . Metric = 0
}
if mtu > 0 {
ipif . N lMtu = uint32 ( mtu )
tun . ForceMTU ( int ( ipif . N lMtu ) )
ipif . N LMTU = uint32 ( mtu )
tun . ForceMTU ( int ( ipif . N LMTU ) )
}
err = ipif . Set ( )
if err != nil && errAcc == nil {
errAcc = err
}
ipif , err = iface . GetIpInterface ( winipcfg . AF_INET6 )
ipif , err = iface . LUID . IPInterface ( windows . AF_INET6 )
if err != nil {
if ! isMissingIPv6Err ( err ) {
if ! errors . Is ( err , windows . ERROR_NOT_FOUND ) {
return err
}
} else {
@ -363,7 +392,7 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
ipif . Metric = 0
}
if mtu > 0 {
ipif . N lMtu = uint32 ( mtu )
ipif . N LMTU = uint32 ( mtu )
}
ipif . DadTransmits = 0
ipif . RouterDiscoveryBehavior = winipcfg . RouterDiscoveryDisabled
@ -376,22 +405,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
return errAcc
}
// isMissingIPv6Err reports whether err is due to IPv6 not being enabled on the machine.
//
// It only currently supports the errors returned by winipcfg.Interface.GetIpInterface.
func isMissingIPv6Err ( err error ) bool {
if se , ok := err . ( * os . SyscallError ) ; ok {
switch se . Syscall {
case "iphlpapi.GetIpInterfaceEntry" :
// ERROR_NOT_FOUND from means the address family (IPv6) is not found.
// (ERROR_FILE_NOT_FOUND means that the interface doesn't exist.)
// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getipinterfaceentry
return se . Err == windows . ERROR_NOT_FOUND
}
}
return false
}
// routeLess reports whether ri should sort before rj.
// The actual sort order doesn't appear to matter. The caller just
// wants them sorted to be able to de-dup.
@ -495,31 +508,53 @@ func excludeIPv6LinkLocal(in []*net.IPNet) (out []*net.IPNet) {
return out
}
// ipAdapterUnicastAddressToIPNet converts windows.IpAdapterUnicastAddress to net.IPNet.
func ipAdapterUnicastAddressToIPNet ( u * windows . IpAdapterUnicastAddress ) * net . IPNet {
ip := u . Address . IP ( )
w := 32
if ip . To4 ( ) == nil {
w = 128
}
return & net . IPNet {
IP : ip ,
Mask : net . CIDRMask ( int ( u . OnLinkPrefixLength ) , w ) ,
}
}
// unicastIPNets returns all unicast net.IPNet for ifc interface.
func unicastIPNets ( ifc * winipcfg . IPAdapterAddresses ) [ ] * net . IPNet {
nets := make ( [ ] * net . IPNet , 0 )
for addr := ifc . FirstUnicastAddress ; addr != nil ; addr = addr . Next {
nets = append ( nets , ipAdapterUnicastAddressToIPNet ( addr ) )
}
return nets
}
// syncAddresses incrementally sets the interface's unicast IP addresses,
// doing the minimum number of AddAddresses & DeleteAddress calls.
// This avoids the full FlushAddresses.
//
// Any IPv6 link-local addresses are not deleted.
func syncAddresses ( ifc * winipcfg . Interface , want [ ] * net . IPNet ) error {
func syncAddresses ( ifc * winipcfg . I PAdapterAddresses , want [ ] * net . IPNet ) error {
var erracc error
got := ifc . UnicastIPNets
got := unicastIPNets ( ifc )
add , del := deltaNets ( got , want )
del = excludeIPv6LinkLocal ( del )
for _ , a := range del {
err := ifc . DeleteAddress ( & a . IP )
err := ifc . LUID . DeleteIPAddress ( * a )
if err != nil {
erracc = err
}
}
err := ifc . AddAddresses ( add )
for _ , a := range add {
err := ifc . LUID . AddIPAddress ( * a )
if err != nil {
erracc = err
}
}
ifc . UnicastIPNets = make ( [ ] * net . IPNet , len ( want ) )
copy ( ifc . UnicastIPNets , want )
return erracc
}
@ -588,28 +623,46 @@ func deltaRouteData(a, b []*winipcfg.RouteData) (add, del []*winipcfg.RouteData)
return
}
// getInterfaceRoutes returns all the interface's routes.
// Corresponds to GetIpForwardTable2 function, but filtered by interface.
func getInterfaceRoutes ( ifc * winipcfg . IPAdapterAddresses , family winipcfg . AddressFamily ) ( [ ] * winipcfg . MibIPforwardRow2 , error ) {
routes , err := winipcfg . GetIPForwardTable2 ( family )
if err != nil {
return nil , err
}
matches := make ( [ ] * winipcfg . MibIPforwardRow2 , len ( routes ) )
i := 0
for i := range routes {
if routes [ i ] . InterfaceLUID == ifc . LUID {
matches [ i ] = & routes [ i ]
i ++
}
}
return matches [ : i ] , nil
}
// syncRoutes incrementally sets multiples routes on an interface.
// This avoids a full ifc.FlushRoutes call.
func syncRoutes ( ifc * winipcfg . Interface , want [ ] * winipcfg . RouteData ) error {
routes , err := ifc . GetRoutes ( windows . AF_INET )
func syncRoutes ( ifc * winipcfg . I PAdapterAddresses , want [ ] * winipcfg . RouteData ) error {
routes , err := getInterfaceRoutes ( ifc , windows . AF_INET )
if err != nil {
return err
}
got := make ( [ ] * winipcfg . RouteData , 0 , len ( routes ) )
for _ , r := range routes {
v , err := r . ToRouteData ( )
if err != nil {
return err
}
got = append ( got , v )
got = append ( got , & winipcfg . RouteData {
Destination : r . DestinationPrefix . IPNet ( ) ,
NextHop : r . NextHop . IP ( ) ,
Metric : r . Metric ,
} )
}
add , del := deltaRouteData ( got , want )
var errs [ ] error
for _ , a := range del {
err := ifc . DeleteRoute ( & a . Destination , & a . NextHop )
err := ifc . LUID . DeleteRoute ( a . Destination , a . NextHop )
if err != nil {
dstStr := a . Destination . String ( )
if dstStr == "169.254.255.255/32" {
@ -622,7 +675,7 @@ func syncRoutes(ifc *winipcfg.Interface, want []*winipcfg.RouteData) error {
}
for _ , a := range add {
err := ifc . AddRoute ( a )
err := ifc . LUID . AddRoute ( a . Destination , a . NextHop , a . Metric )
if err != nil {
errs = append ( errs , fmt . Errorf ( "adding route %v: %w" , & a . Destination , err ) )
}