|
|
|
@ -25,6 +25,10 @@ type Filter struct {
|
|
|
|
// destination within local, regardless of the policy filter
|
|
|
|
// destination within local, regardless of the policy filter
|
|
|
|
// below.
|
|
|
|
// below.
|
|
|
|
local *netaddr.IPSet
|
|
|
|
local *netaddr.IPSet
|
|
|
|
|
|
|
|
// logIPs is the set of IPs that are allowed to appear in flow
|
|
|
|
|
|
|
|
// logs. If a packet is to or from an IP not in logIPs, it will
|
|
|
|
|
|
|
|
// never be logged.
|
|
|
|
|
|
|
|
logIPs *netaddr.IPSet
|
|
|
|
// matches4 and matches6 are lists of match->action rules
|
|
|
|
// matches4 and matches6 are lists of match->action rules
|
|
|
|
// applied to all packets arriving over tailscale
|
|
|
|
// applied to all packets arriving over tailscale
|
|
|
|
// tunnels. Matches are checked in order, and processing stops
|
|
|
|
// tunnels. Matches are checked in order, and processing stops
|
|
|
|
@ -125,24 +129,24 @@ func NewAllowAllForTest(logf logger.Logf) *Filter {
|
|
|
|
var sb netaddr.IPSetBuilder
|
|
|
|
var sb netaddr.IPSetBuilder
|
|
|
|
sb.AddPrefix(any4)
|
|
|
|
sb.AddPrefix(any4)
|
|
|
|
sb.AddPrefix(any6)
|
|
|
|
sb.AddPrefix(any6)
|
|
|
|
return New(ms, sb.IPSet(), nil, logf)
|
|
|
|
return New(ms, sb.IPSet(), sb.IPSet(), nil, logf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewAllowNone returns a packet filter that rejects everything.
|
|
|
|
// NewAllowNone returns a packet filter that rejects everything.
|
|
|
|
func NewAllowNone(logf logger.Logf) *Filter {
|
|
|
|
func NewAllowNone(logf logger.Logf, logIPs *netaddr.IPSet) *Filter {
|
|
|
|
return New(nil, &netaddr.IPSet{}, nil, logf)
|
|
|
|
return New(nil, &netaddr.IPSet{}, logIPs, nil, logf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewShieldsUpFilter returns a packet filter that rejects incoming connections.
|
|
|
|
// NewShieldsUpFilter returns a packet filter that rejects incoming connections.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// If shareStateWith is non-nil, the returned filter shares state with the previous one,
|
|
|
|
// If shareStateWith is non-nil, the returned filter shares state with the previous one,
|
|
|
|
// as long as the previous one was also a shields up filter.
|
|
|
|
// as long as the previous one was also a shields up filter.
|
|
|
|
func NewShieldsUpFilter(localNets *netaddr.IPSet, shareStateWith *Filter, logf logger.Logf) *Filter {
|
|
|
|
func NewShieldsUpFilter(localNets *netaddr.IPSet, logIPs *netaddr.IPSet, shareStateWith *Filter, logf logger.Logf) *Filter {
|
|
|
|
// Don't permit sharing state with a prior filter that wasn't a shields-up filter.
|
|
|
|
// Don't permit sharing state with a prior filter that wasn't a shields-up filter.
|
|
|
|
if shareStateWith != nil && !shareStateWith.shieldsUp {
|
|
|
|
if shareStateWith != nil && !shareStateWith.shieldsUp {
|
|
|
|
shareStateWith = nil
|
|
|
|
shareStateWith = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f := New(nil, localNets, shareStateWith, logf)
|
|
|
|
f := New(nil, localNets, logIPs, shareStateWith, logf)
|
|
|
|
f.shieldsUp = true
|
|
|
|
f.shieldsUp = true
|
|
|
|
return f
|
|
|
|
return f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -152,7 +156,7 @@ func NewShieldsUpFilter(localNets *netaddr.IPSet, shareStateWith *Filter, logf l
|
|
|
|
// by matches. If shareStateWith is non-nil, the returned filter
|
|
|
|
// by matches. If shareStateWith is non-nil, the returned filter
|
|
|
|
// shares state with the previous one, to enable changing rules at
|
|
|
|
// shares state with the previous one, to enable changing rules at
|
|
|
|
// runtime without breaking existing stateful flows.
|
|
|
|
// runtime without breaking existing stateful flows.
|
|
|
|
func New(matches []Match, localNets *netaddr.IPSet, shareStateWith *Filter, logf logger.Logf) *Filter {
|
|
|
|
func New(matches []Match, localNets *netaddr.IPSet, logIPs *netaddr.IPSet, shareStateWith *Filter, logf logger.Logf) *Filter {
|
|
|
|
var state *filterState
|
|
|
|
var state *filterState
|
|
|
|
if shareStateWith != nil {
|
|
|
|
if shareStateWith != nil {
|
|
|
|
state = shareStateWith.state
|
|
|
|
state = shareStateWith.state
|
|
|
|
@ -166,6 +170,7 @@ func New(matches []Match, localNets *netaddr.IPSet, shareStateWith *Filter, logf
|
|
|
|
matches4: matchesFamily(matches, netaddr.IP.Is4),
|
|
|
|
matches4: matchesFamily(matches, netaddr.IP.Is4),
|
|
|
|
matches6: matchesFamily(matches, netaddr.IP.Is6),
|
|
|
|
matches6: matchesFamily(matches, netaddr.IP.Is6),
|
|
|
|
local: localNets,
|
|
|
|
local: localNets,
|
|
|
|
|
|
|
|
logIPs: logIPs,
|
|
|
|
state: state,
|
|
|
|
state: state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return f
|
|
|
|
return f
|
|
|
|
@ -210,12 +215,15 @@ var acceptBucket = rate.NewLimiter(rate.Every(10*time.Second), 3)
|
|
|
|
var dropBucket = rate.NewLimiter(rate.Every(5*time.Second), 10)
|
|
|
|
var dropBucket = rate.NewLimiter(rate.Every(5*time.Second), 10)
|
|
|
|
|
|
|
|
|
|
|
|
func (f *Filter) logRateLimit(runflags RunFlags, q *packet.Parsed, dir direction, r Response, why string) {
|
|
|
|
func (f *Filter) logRateLimit(runflags RunFlags, q *packet.Parsed, dir direction, r Response, why string) {
|
|
|
|
var verdict string
|
|
|
|
if !f.loggingAllowed(q) {
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if r == Drop && omitDropLogging(q, dir) {
|
|
|
|
if r == Drop && omitDropLogging(q, dir) {
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var verdict string
|
|
|
|
if r == Drop && (runflags&LogDrops) != 0 && dropBucket.Allow() {
|
|
|
|
if r == Drop && (runflags&LogDrops) != 0 && dropBucket.Allow() {
|
|
|
|
verdict = "Drop"
|
|
|
|
verdict = "Drop"
|
|
|
|
runflags &= HexdumpDrops
|
|
|
|
runflags &= HexdumpDrops
|
|
|
|
@ -491,6 +499,11 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
|
|
|
|
return noVerdict
|
|
|
|
return noVerdict
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// loggingAllowed reports whether p can appear in logs at all.
|
|
|
|
|
|
|
|
func (f *Filter) loggingAllowed(p *packet.Parsed) bool {
|
|
|
|
|
|
|
|
return f.logIPs.Contains(p.Src.IP) && f.logIPs.Contains(p.Dst.IP)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// omitDropLogging reports whether packet p, which has already been
|
|
|
|
// omitDropLogging reports whether packet p, which has already been
|
|
|
|
// deemed a packet to Drop, should bypass the [rate-limited] logging.
|
|
|
|
// deemed a packet to Drop, should bypass the [rate-limited] logging.
|
|
|
|
// We don't want to log scary & spammy reject warnings for packets
|
|
|
|
// We don't want to log scary & spammy reject warnings for packets
|
|
|
|
|