mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 03:31:39 +00:00
wgengine: expand lazy config to work with dual-stacked peers.
Lazy wg configuration now triggers if a peer has only endpoint addresses (/32 for IPv4, /128 for IPv6). Subnet routers still trigger eager configuration to avoid the need for a CIDR match in the hot packet path. Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
aa353b8d0f
commit
891110e64c
@ -67,7 +67,8 @@ type TUN struct {
|
|||||||
|
|
||||||
lastActivityAtomic int64 // unix seconds of last send or receive
|
lastActivityAtomic int64 // unix seconds of last send or receive
|
||||||
|
|
||||||
destIPActivity atomic.Value // of map[packet.IP]func()
|
destIPActivity4 atomic.Value // of map[packet.IP4]func()
|
||||||
|
destIPActivity6 atomic.Value // of map[packet.IP6]func()
|
||||||
|
|
||||||
// buffer stores the oldest unconsumed packet from tdev.
|
// buffer stores the oldest unconsumed packet from tdev.
|
||||||
// It is made a static buffer in order to avoid allocations.
|
// It is made a static buffer in order to avoid allocations.
|
||||||
@ -136,8 +137,9 @@ func WrapTUN(logf logger.Logf, tdev tun.Device) *TUN {
|
|||||||
// destination (the map keys).
|
// destination (the map keys).
|
||||||
//
|
//
|
||||||
// The map ownership passes to the TUN. It must be non-nil.
|
// The map ownership passes to the TUN. It must be non-nil.
|
||||||
func (t *TUN) SetDestIPActivityFuncs(m map[packet.IP4]func()) {
|
func (t *TUN) SetDestIPActivityFuncs(m4 map[packet.IP4]func(), m6 map[packet.IP6]func()) {
|
||||||
t.destIPActivity.Store(m)
|
t.destIPActivity4.Store(m4)
|
||||||
|
t.destIPActivity6.Store(m6)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TUN) Close() error {
|
func (t *TUN) Close() error {
|
||||||
@ -282,11 +284,20 @@ func (t *TUN) Read(buf []byte, offset int) (int, error) {
|
|||||||
defer parsedPacketPool.Put(p)
|
defer parsedPacketPool.Put(p)
|
||||||
p.Decode(buf[offset : offset+n])
|
p.Decode(buf[offset : offset+n])
|
||||||
|
|
||||||
if m, ok := t.destIPActivity.Load().(map[packet.IP4]func()); ok {
|
switch p.IPVersion {
|
||||||
|
case 4:
|
||||||
|
if m, ok := t.destIPActivity4.Load().(map[packet.IP4]func()); ok {
|
||||||
if fn := m[p.DstIP4]; fn != nil {
|
if fn := m[p.DstIP4]; fn != nil {
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 6:
|
||||||
|
if m, ok := t.destIPActivity6.Load().(map[packet.IP6]func()); ok {
|
||||||
|
if fn := m[p.DstIP6]; fn != nil {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !t.disableFilter {
|
if !t.disableFilter {
|
||||||
response := t.filterOut(p)
|
response := t.filterOut(p)
|
||||||
|
@ -108,8 +108,10 @@ type userspaceEngine struct {
|
|||||||
lastEngineSigTrim string // of trimmed wireguard config
|
lastEngineSigTrim string // of trimmed wireguard config
|
||||||
recvActivityAt map[tailcfg.DiscoKey]time.Time
|
recvActivityAt map[tailcfg.DiscoKey]time.Time
|
||||||
trimmedDisco map[tailcfg.DiscoKey]bool // set of disco keys of peers currently excluded from wireguard config
|
trimmedDisco map[tailcfg.DiscoKey]bool // set of disco keys of peers currently excluded from wireguard config
|
||||||
sentActivityAt map[packet.IP4]*int64 // value is atomic int64 of unixtime
|
sentActivityAt4 map[packet.IP4]*int64 // value is atomic int64 of unixtime
|
||||||
destIPActivityFuncs map[packet.IP4]func()
|
destIPActivityFuncs4 map[packet.IP4]func()
|
||||||
|
sentActivityAt6 map[packet.IP6]*int64 // value is atomic int64 of unixtime
|
||||||
|
destIPActivityFuncs6 map[packet.IP6]func()
|
||||||
|
|
||||||
mu sync.Mutex // guards following; see lock order comment below
|
mu sync.Mutex // guards following; see lock order comment below
|
||||||
closing bool // Close was called (even if we're still closing)
|
closing bool // Close was called (even if we're still closing)
|
||||||
@ -631,21 +633,26 @@ func forceFullWireguardConfig(numPeers int) bool {
|
|||||||
// simplicity, have only one IP address (an IPv4 /32), which is the
|
// simplicity, have only one IP address (an IPv4 /32), which is the
|
||||||
// common case for most peers. Subnet router nodes will just always be
|
// common case for most peers. Subnet router nodes will just always be
|
||||||
// created in the wireguard-go config.
|
// created in the wireguard-go config.
|
||||||
|
//
|
||||||
|
// XXXXXXX DO NOT SUBMIT fix docstring
|
||||||
func isTrimmablePeer(p *wgcfg.Peer, numPeers int) bool {
|
func isTrimmablePeer(p *wgcfg.Peer, numPeers int) bool {
|
||||||
if forceFullWireguardConfig(numPeers) {
|
if forceFullWireguardConfig(numPeers) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(p.AllowedIPs) != 1 || len(p.Endpoints) != 1 {
|
if len(p.Endpoints) != 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(p.Endpoints[0].Host, ".disco.tailscale") {
|
if !strings.HasSuffix(p.Endpoints[0].Host, ".disco.tailscale") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
aip := p.AllowedIPs[0]
|
|
||||||
// TODO: IPv6 support, once we support IPv6 within the tunnel. In that case,
|
// AllowedIPs must all be single IPs, not subnets.
|
||||||
// len(p.AllowedIPs) probably will be more than 1.
|
for _, aip := range p.AllowedIPs {
|
||||||
if aip.Mask != 32 || !aip.IP.Is4() {
|
if aip.IP.Is4() && aip.Mask != 32 {
|
||||||
return false
|
return false
|
||||||
|
} else if aip.IP.Is6() && aip.Mask != 128 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -687,8 +694,17 @@ func (e *userspaceEngine) isActiveSince(dk tailcfg.DiscoKey, ip wgcfg.IP, t time
|
|||||||
if e.recvActivityAt[dk].After(t) {
|
if e.recvActivityAt[dk].After(t) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
timePtr *int64
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if ip.Is4() {
|
||||||
pip := packet.IP4(binary.BigEndian.Uint32(ip.Addr[12:]))
|
pip := packet.IP4(binary.BigEndian.Uint32(ip.Addr[12:]))
|
||||||
timePtr, ok := e.sentActivityAt[pip]
|
timePtr, ok = e.sentActivityAt4[pip]
|
||||||
|
} else {
|
||||||
|
pip := packet.IP6FromRaw16(ip.Addr)
|
||||||
|
timePtr, ok = e.sentActivityAt6[pip]
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -829,23 +845,17 @@ func (e *userspaceEngine) updateActivityMapsLocked(trackDisco []tailcfg.DiscoKey
|
|||||||
}
|
}
|
||||||
e.recvActivityAt = mr
|
e.recvActivityAt = mr
|
||||||
|
|
||||||
oldTime := e.sentActivityAt
|
oldTime4 := e.sentActivityAt4
|
||||||
e.sentActivityAt = make(map[packet.IP4]*int64, len(oldTime))
|
e.sentActivityAt4 = make(map[packet.IP4]*int64, len(oldTime4))
|
||||||
oldFunc := e.destIPActivityFuncs
|
oldFunc4 := e.destIPActivityFuncs4
|
||||||
e.destIPActivityFuncs = make(map[packet.IP4]func(), len(oldFunc))
|
e.destIPActivityFuncs4 = make(map[packet.IP4]func(), len(oldFunc4))
|
||||||
|
oldTime6 := e.sentActivityAt6
|
||||||
|
e.sentActivityAt6 = make(map[packet.IP6]*int64, len(oldTime6))
|
||||||
|
oldFunc6 := e.destIPActivityFuncs6
|
||||||
|
e.destIPActivityFuncs6 = make(map[packet.IP6]func(), len(oldFunc6))
|
||||||
|
|
||||||
for _, wip := range trackIPs {
|
updateFn := func(timePtr *int64) func() {
|
||||||
pip := packet.IP4(binary.BigEndian.Uint32(wip.Addr[12:]))
|
return func() {
|
||||||
timePtr := oldTime[pip]
|
|
||||||
if timePtr == nil {
|
|
||||||
timePtr = new(int64)
|
|
||||||
}
|
|
||||||
e.sentActivityAt[pip] = timePtr
|
|
||||||
|
|
||||||
fn := oldFunc[pip]
|
|
||||||
if fn == nil {
|
|
||||||
// This is the func that gets run on every outgoing packet for tracked IPs:
|
|
||||||
fn = func() {
|
|
||||||
now := e.timeNow().Unix()
|
now := e.timeNow().Unix()
|
||||||
old := atomic.LoadInt64(timePtr)
|
old := atomic.LoadInt64(timePtr)
|
||||||
|
|
||||||
@ -865,9 +875,37 @@ func (e *userspaceEngine) updateActivityMapsLocked(trackDisco []tailcfg.DiscoKey
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.destIPActivityFuncs[pip] = fn
|
|
||||||
|
for _, wip := range trackIPs {
|
||||||
|
if wip.Is4() {
|
||||||
|
pip := packet.IP4(binary.BigEndian.Uint32(wip.Addr[12:]))
|
||||||
|
timePtr := oldTime4[pip]
|
||||||
|
if timePtr == nil {
|
||||||
|
timePtr = new(int64)
|
||||||
}
|
}
|
||||||
e.tundev.SetDestIPActivityFuncs(e.destIPActivityFuncs)
|
e.sentActivityAt4[pip] = timePtr
|
||||||
|
|
||||||
|
fn := oldFunc4[pip]
|
||||||
|
if fn == nil {
|
||||||
|
fn = updateFn(timePtr)
|
||||||
|
}
|
||||||
|
e.destIPActivityFuncs4[pip] = fn
|
||||||
|
} else {
|
||||||
|
pip := packet.IP6FromRaw16(wip.Addr)
|
||||||
|
timePtr := oldTime6[pip]
|
||||||
|
if timePtr == nil {
|
||||||
|
timePtr = new(int64)
|
||||||
|
}
|
||||||
|
e.sentActivityAt6[pip] = timePtr
|
||||||
|
|
||||||
|
fn := oldFunc6[pip]
|
||||||
|
if fn == nil {
|
||||||
|
fn = updateFn(timePtr)
|
||||||
|
}
|
||||||
|
e.destIPActivityFuncs6[pip] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.tundev.SetDestIPActivityFuncs(e.destIPActivityFuncs4, e.destIPActivityFuncs6)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config) error {
|
func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config) error {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user