mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-10 09:45:08 +00:00
wgengine: don't lose filter state on filter reconfig.
We were abandoning the UDP port LRU every time we got a new packet filter from tailcontrol, which caused return packets to suddenly stop arriving.
This commit is contained in:
@@ -15,11 +15,14 @@ import (
|
||||
"tailscale.com/wgengine/packet"
|
||||
)
|
||||
|
||||
type filterState struct {
|
||||
mu sync.Mutex
|
||||
lru *lru.Cache
|
||||
}
|
||||
|
||||
type Filter struct {
|
||||
matches Matches
|
||||
|
||||
udpMu sync.Mutex
|
||||
udplru *lru.Cache
|
||||
state *filterState
|
||||
}
|
||||
|
||||
type Response int
|
||||
@@ -66,17 +69,25 @@ var MatchAllowAll = Matches{
|
||||
}
|
||||
|
||||
func NewAllowAll() *Filter {
|
||||
return New(MatchAllowAll)
|
||||
return New(MatchAllowAll, nil)
|
||||
}
|
||||
|
||||
func NewAllowNone() *Filter {
|
||||
return New(nil)
|
||||
return New(nil, nil)
|
||||
}
|
||||
|
||||
func New(matches Matches) *Filter {
|
||||
func New(matches Matches, shareStateWith *Filter) *Filter {
|
||||
var state *filterState
|
||||
if shareStateWith != nil {
|
||||
state = shareStateWith.state
|
||||
} else {
|
||||
state = &filterState{
|
||||
lru: lru.New(LRU_MAX),
|
||||
}
|
||||
}
|
||||
f := &Filter{
|
||||
matches: matches,
|
||||
udplru: lru.New(LRU_MAX),
|
||||
state: state,
|
||||
}
|
||||
return f
|
||||
}
|
||||
@@ -144,6 +155,10 @@ func (f *Filter) runIn(q *packet.QDecode) (r Response, why string) {
|
||||
switch q.IPProto {
|
||||
case packet.ICMP:
|
||||
// If any port is open to an IP, allow ICMP to it.
|
||||
// TODO(apenwarr): allow ICMP packets on existing sessions.
|
||||
// Right now ICMP Echo Response doesn't always work, and
|
||||
// probably important ICMP responses on TCP sessions
|
||||
// also get blocked.
|
||||
if matchIPWithoutPorts(f.matches, q) {
|
||||
return Accept, "icmp ok"
|
||||
}
|
||||
@@ -165,9 +180,9 @@ func (f *Filter) runIn(q *packet.QDecode) (r Response, why string) {
|
||||
case packet.UDP:
|
||||
t := tuple{q.SrcIP, q.DstIP, q.SrcPort, q.DstPort}
|
||||
|
||||
f.udpMu.Lock()
|
||||
_, ok := f.udplru.Get(t)
|
||||
f.udpMu.Unlock()
|
||||
f.state.mu.Lock()
|
||||
_, ok := f.state.lru.Get(t)
|
||||
f.state.mu.Unlock()
|
||||
|
||||
if ok {
|
||||
return Accept, "udp cached"
|
||||
@@ -182,12 +197,13 @@ func (f *Filter) runIn(q *packet.QDecode) (r Response, why string) {
|
||||
}
|
||||
|
||||
func (f *Filter) runOut(q *packet.QDecode) (r Response, why string) {
|
||||
// TODO(apenwarr): create sessions on ICMP Echo Request too.
|
||||
if q.IPProto == packet.UDP {
|
||||
t := tuple{q.DstIP, q.SrcIP, q.DstPort, q.SrcPort}
|
||||
|
||||
f.udpMu.Lock()
|
||||
f.udplru.Add(t, t)
|
||||
f.udpMu.Unlock()
|
||||
f.state.mu.Lock()
|
||||
f.state.lru.Add(t, t)
|
||||
f.state.mu.Unlock()
|
||||
}
|
||||
return Accept, "ok out"
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ func TestFilter(t *testing.T) {
|
||||
{SrcIPs: []IP{0}, DstPorts: ippr(0, 443, 443)},
|
||||
{SrcIPs: []IP{0x99010101, 0x99010102, 0x99030303}, DstPorts: ippr(0x01020304, 999, 999)},
|
||||
}
|
||||
acl := New(mm)
|
||||
acl := New(mm, nil)
|
||||
|
||||
for _, ent := range []Matches{Matches{mm[0]}, mm} {
|
||||
b, err := json.Marshal(ent)
|
||||
|
Reference in New Issue
Block a user