|
|
|
@ -23,21 +23,23 @@ import (
|
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
|
"tailscale.com/types/views"
|
|
|
|
|
"tailscale.com/util/mak"
|
|
|
|
|
"tailscale.com/util/slicesx"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Filter is a stateful packet filter.
|
|
|
|
|
type Filter struct {
|
|
|
|
|
logf logger.Logf
|
|
|
|
|
// local is the set of IPs prefixes that we know to be "local" to
|
|
|
|
|
// this node. All packets coming in over tailscale must have a
|
|
|
|
|
// destination within local, regardless of the policy filter
|
|
|
|
|
// below.
|
|
|
|
|
local func(netip.Addr) bool
|
|
|
|
|
// local4 and local6 report whether an IP is "local" to this node, for the
|
|
|
|
|
// respective address family. All packets coming in over tailscale must have
|
|
|
|
|
// a destination within local, regardless of the policy filter below.
|
|
|
|
|
local4 func(netip.Addr) bool
|
|
|
|
|
local6 func(netip.Addr) bool
|
|
|
|
|
|
|
|
|
|
// 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 func(netip.Addr) bool
|
|
|
|
|
logIPs4 func(netip.Addr) bool
|
|
|
|
|
logIPs6 func(netip.Addr) bool
|
|
|
|
|
|
|
|
|
|
// matches4 and matches6 are lists of match->action rules
|
|
|
|
|
// applied to all packets arriving over tailscale
|
|
|
|
@ -184,23 +186,31 @@ func New(matches []Match, localNets, logIPs *netipx.IPSet, shareStateWith *Filte
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
containsFunc := func(s *netipx.IPSet) func(netip.Addr) bool {
|
|
|
|
|
if s == nil {
|
|
|
|
|
return tsaddr.FalseContainsIPFunc()
|
|
|
|
|
}
|
|
|
|
|
return tsaddr.NewContainsIPFunc(views.SliceOf(s.Prefixes()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f := &Filter{
|
|
|
|
|
logf: logf,
|
|
|
|
|
matches4: matchesFamily(matches, netip.Addr.Is4),
|
|
|
|
|
matches6: matchesFamily(matches, netip.Addr.Is6),
|
|
|
|
|
cap4: capMatchesFunc(matches, netip.Addr.Is4),
|
|
|
|
|
cap6: capMatchesFunc(matches, netip.Addr.Is6),
|
|
|
|
|
local: containsFunc(localNets),
|
|
|
|
|
logIPs: containsFunc(logIPs),
|
|
|
|
|
local4: tsaddr.FalseContainsIPFunc(),
|
|
|
|
|
local6: tsaddr.FalseContainsIPFunc(),
|
|
|
|
|
logIPs4: tsaddr.FalseContainsIPFunc(),
|
|
|
|
|
logIPs6: tsaddr.FalseContainsIPFunc(),
|
|
|
|
|
state: state,
|
|
|
|
|
}
|
|
|
|
|
if localNets != nil {
|
|
|
|
|
p := localNets.Prefixes()
|
|
|
|
|
p4, p6 := slicesx.Partition(p, func(p netip.Prefix) bool { return p.Addr().Is4() })
|
|
|
|
|
f.local4 = tsaddr.NewContainsIPFunc(views.SliceOf(p4))
|
|
|
|
|
f.local6 = tsaddr.NewContainsIPFunc(views.SliceOf(p6))
|
|
|
|
|
}
|
|
|
|
|
if logIPs != nil {
|
|
|
|
|
p := logIPs.Prefixes()
|
|
|
|
|
p4, p6 := slicesx.Partition(p, func(p netip.Prefix) bool { return p.Addr().Is4() })
|
|
|
|
|
f.logIPs4 = tsaddr.NewContainsIPFunc(views.SliceOf(p4))
|
|
|
|
|
f.logIPs6 = tsaddr.NewContainsIPFunc(views.SliceOf(p6))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -431,7 +441,7 @@ func (f *Filter) runIn4(q *packet.Parsed) (r Response, why string) {
|
|
|
|
|
// A compromised peer could try to send us packets for
|
|
|
|
|
// destinations we didn't explicitly advertise. This check is to
|
|
|
|
|
// prevent that.
|
|
|
|
|
if !f.local(q.Dst.Addr()) {
|
|
|
|
|
if !f.local4(q.Dst.Addr()) {
|
|
|
|
|
return Drop, "destination not allowed"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -491,7 +501,7 @@ func (f *Filter) runIn6(q *packet.Parsed) (r Response, why string) {
|
|
|
|
|
// A compromised peer could try to send us packets for
|
|
|
|
|
// destinations we didn't explicitly advertise. This check is to
|
|
|
|
|
// prevent that.
|
|
|
|
|
if !f.local(q.Dst.Addr()) {
|
|
|
|
|
if !f.local6(q.Dst.Addr()) {
|
|
|
|
|
return Drop, "destination not allowed"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -617,7 +627,13 @@ func (f *Filter) pre(q *packet.Parsed, rf RunFlags, dir direction) Response {
|
|
|
|
|
|
|
|
|
|
// loggingAllowed reports whether p can appear in logs at all.
|
|
|
|
|
func (f *Filter) loggingAllowed(p *packet.Parsed) bool {
|
|
|
|
|
return f.logIPs(p.Src.Addr()) && f.logIPs(p.Dst.Addr())
|
|
|
|
|
switch p.IPVersion {
|
|
|
|
|
case 4:
|
|
|
|
|
return f.logIPs4(p.Src.Addr()) && f.logIPs4(p.Dst.Addr())
|
|
|
|
|
case 6:
|
|
|
|
|
return f.logIPs6(p.Src.Addr()) && f.logIPs6(p.Dst.Addr())
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// omitDropLogging reports whether packet p, which has already been
|
|
|
|
|