wgengine/router: don't touch interface routes

Developed by a cast of dozens.

Fixes #1448

Signed-off-by: David Anderson <danderson@tailscale.com>
(cherry picked from commit fa6110e47b)
bradfitz/proposed_1.4.6
David Anderson 2021-03-11 19:24:45 -08:00 committed by Brad Fitzpatrick
parent f7ef32da5f
commit bbb0e84cf1
1 changed files with 28 additions and 2 deletions

View File

@ -20,6 +20,7 @@ import (
"github.com/tailscale/wireguard-go/tun" "github.com/tailscale/wireguard-go/tun"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"inet.af/netaddr"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/wgengine/winnet" "tailscale.com/wgengine/winnet"
) )
@ -378,7 +379,7 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
} }
var errAcc error var errAcc error
err = syncRoutes(iface, deduplicatedRoutes) err = syncRoutes(iface, deduplicatedRoutes, cfg.LocalAddrs)
if err != nil && errAcc == nil { if err != nil && errAcc == nil {
log.Printf("setroutes: %v", err) log.Printf("setroutes: %v", err)
errAcc = err errAcc = err
@ -659,9 +660,29 @@ func getInterfaceRoutes(ifc *winipcfg.IPAdapterAddresses, family winipcfg.Addres
return return
} }
// isSingleRouteInPrefixes reports whether r is a single-address
// prefix that appears in pfxs.
func isSingleRouteInPrefixes(r net.IPNet, pfxs []netaddr.IPPrefix) bool {
rr, ok := netaddr.FromStdIPNet(&r)
if !ok {
return false
}
if !rr.IsSingleIP() {
return false
}
for _, pfx := range pfxs {
if pfx == rr {
return true
}
}
return false
}
// syncRoutes incrementally sets multiples routes on an interface. // syncRoutes incrementally sets multiples routes on an interface.
// This avoids a full ifc.FlushRoutes call. // This avoids a full ifc.FlushRoutes call.
func syncRoutes(ifc *winipcfg.IPAdapterAddresses, want []*winipcfg.RouteData) error { // dontDelete is a list of interface address routes that the
// synchronization logic should never delete.
func syncRoutes(ifc *winipcfg.IPAdapterAddresses, want []*winipcfg.RouteData, dontDelete []netaddr.IPPrefix) error {
routes, err := getInterfaceRoutes(ifc, windows.AF_INET) routes, err := getInterfaceRoutes(ifc, windows.AF_INET)
if err != nil { if err != nil {
return err return err
@ -669,6 +690,11 @@ func syncRoutes(ifc *winipcfg.IPAdapterAddresses, want []*winipcfg.RouteData) er
got := make([]*winipcfg.RouteData, 0, len(routes)) got := make([]*winipcfg.RouteData, 0, len(routes))
for _, r := range routes { for _, r := range routes {
if isSingleRouteInPrefixes(r.DestinationPrefix.IPNet(), dontDelete) {
// See issue 1448: we don't want to touch the routes added
// by Windows for our interface addresses.
continue
}
got = append(got, &winipcfg.RouteData{ got = append(got, &winipcfg.RouteData{
Destination: r.DestinationPrefix.IPNet(), Destination: r.DestinationPrefix.IPNet(),
NextHop: r.NextHop.IP(), NextHop: r.NextHop.IP(),