wgengine/netstack: don't pass non-subnet traffic to netstack in hybrid mode

Fixes tailscale/corp#1725

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-05-05 12:32:46 -07:00 committed by Brad Fitzpatrick
parent 7629cd6120
commit eb06ec172f
2 changed files with 24 additions and 3 deletions

View File

@ -31,8 +31,8 @@ type NetworkMap struct {
Expiry time.Time Expiry time.Time
// Name is the DNS name assigned to this node. // Name is the DNS name assigned to this node.
Name string Name string
Addresses []netaddr.IPPrefix Addresses []netaddr.IPPrefix // same as tailcfg.Node.Addresses (IP addresses of this Node directly)
LocalPort uint16 // used for debugging LocalPort uint16 // used for debugging
MachineStatus tailcfg.MachineStatus MachineStatus tailcfg.MachineStatus
MachineKey tailcfg.MachineKey MachineKey tailcfg.MachineKey
Peers []*tailcfg.Node // sorted by Node.ID Peers []*tailcfg.Node // sorted by Node.ID

View File

@ -15,6 +15,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
@ -55,6 +56,12 @@ type Impl struct {
logf logger.Logf logf logger.Logf
onlySubnets bool // whether we only want to handle subnet relaying onlySubnets bool // whether we only want to handle subnet relaying
// atomicIsLocalIPFunc holds a func that reports whether an IP
// is a local (non-subnet) Tailscale IP address of this
// machine. It's always a non-nil func. It's changed on netmap
// updates.
atomicIsLocalIPFunc atomic.Value // of func(netaddr.IP) bool
mu sync.Mutex mu sync.Mutex
dns DNSMap dns DNSMap
// connsOpenBySubnetIP keeps track of number of connections open // connsOpenBySubnetIP keeps track of number of connections open
@ -119,6 +126,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
connsOpenBySubnetIP: make(map[netaddr.IP]int), connsOpenBySubnetIP: make(map[netaddr.IP]int),
onlySubnets: onlySubnets, onlySubnets: onlySubnets,
} }
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil))
return ns, nil return ns, nil
} }
@ -145,7 +153,7 @@ func (ns *Impl) Start() error {
ns.logf("netstack: could not parse local address %s for incoming TCP connection", ip) ns.logf("netstack: could not parse local address %s for incoming TCP connection", ip)
return false return false
} }
if !tsaddr.IsTailscaleIP(ip) { if !ns.isLocalIP(ip) {
ns.addSubnetAddress(pn, ip) ns.addSubnetAddress(pn, ip)
} }
return tcpFwd.HandlePacket(tei, pb) return tcpFwd.HandlePacket(tei, pb)
@ -219,6 +227,7 @@ func ipPrefixToAddressWithPrefix(ipp netaddr.IPPrefix) tcpip.AddressWithPrefix {
} }
func (ns *Impl) updateIPs(nm *netmap.NetworkMap) { func (ns *Impl) updateIPs(nm *netmap.NetworkMap) {
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.Addresses))
ns.updateDNS(nm) ns.updateDNS(nm)
oldIPs := make(map[tcpip.AddressWithPrefix]bool) oldIPs := make(map[tcpip.AddressWithPrefix]bool)
@ -373,7 +382,19 @@ func (ns *Impl) injectOutbound() {
} }
} }
// isLocalIP reports whether ip is a Tailscale IP assigned to this
// node directly (but not a subnet-routed IP).
func (ns *Impl) isLocalIP(ip netaddr.IP) bool {
return ns.atomicIsLocalIPFunc.Load().(func(netaddr.IP) bool)(ip)
}
func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response { func (ns *Impl) injectInbound(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
if ns.onlySubnets && ns.isLocalIP(p.Dst.IP) {
// In hybrid ("only subnets") mode, bail out early if
// the traffic is destined for an actual Tailscale
// address. The real host OS interface will handle it.
return filter.Accept
}
var pn tcpip.NetworkProtocolNumber var pn tcpip.NetworkProtocolNumber
switch p.IPVersion { switch p.IPVersion {
case 4: case 4: