various: implement stateful firewalling on Linux (#12025)

Updates https://github.com/tailscale/corp/issues/19623


Change-Id: I7980e1fb736e234e66fa000d488066466c96ec85

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Co-authored-by: Andrew Dunham <andrew@du.nham.ca>
This commit is contained in:
Andrew Lytvynov
2024-05-06 15:22:17 -07:00
committed by GitHub
parent 5ef178fdca
commit c28f5767bf
17 changed files with 632 additions and 47 deletions
+48 -11
View File
@@ -38,17 +38,18 @@ const (
)
type linuxRouter struct {
closed atomic.Bool
logf func(fmt string, args ...any)
tunname string
netMon *netmon.Monitor
unregNetMon func()
addrs map[netip.Prefix]bool
routes map[netip.Prefix]bool
localRoutes map[netip.Prefix]bool
snatSubnetRoutes bool
netfilterMode preftype.NetfilterMode
netfilterKind string
closed atomic.Bool
logf func(fmt string, args ...any)
tunname string
netMon *netmon.Monitor
unregNetMon func()
addrs map[netip.Prefix]bool
routes map[netip.Prefix]bool
localRoutes map[netip.Prefix]bool
snatSubnetRoutes bool
statefulFiltering bool
netfilterMode preftype.NetfilterMode
netfilterKind string
// ruleRestorePending is whether a timer has been started to
// restore deleted ip rules.
@@ -390,6 +391,7 @@ func (r *linuxRouter) Set(cfg *Config) error {
}
r.addrs = newAddrs
// Ensure that the SNAT rule is added or removed as needed.
switch {
case cfg.SNATSubnetRoutes == r.snatSubnetRoutes:
// state already correct, nothing to do.
@@ -404,6 +406,21 @@ func (r *linuxRouter) Set(cfg *Config) error {
}
r.snatSubnetRoutes = cfg.SNATSubnetRoutes
// As above, for stateful filtering
switch {
case cfg.StatefulFiltering == r.statefulFiltering:
// state already correct, nothing to do.
case cfg.StatefulFiltering:
if err := r.addStatefulRule(); err != nil {
errs = append(errs, err)
}
default:
if err := r.delStatefulRule(); err != nil {
errs = append(errs, err)
}
}
r.statefulFiltering = cfg.StatefulFiltering
// Issue 11405: enable IP forwarding on gokrazy.
advertisingRoutes := len(cfg.SubnetRoutes) > 0
if distro.Get() == distro.Gokrazy && advertisingRoutes {
@@ -1327,6 +1344,26 @@ func (r *linuxRouter) delSNATRule() error {
return nil
}
// addStatefulRule adds a netfilter rule to perform stateful filtering from
// subnets onto the tailnet.
func (r *linuxRouter) addStatefulRule() error {
if r.netfilterMode == netfilterOff {
return nil
}
return r.nfr.AddStatefulRule(r.tunname)
}
// delStatefulRule removes the netfilter rule to perform stateful filtering
// from subnets onto the tailnet.
func (r *linuxRouter) delStatefulRule() error {
if r.netfilterMode == netfilterOff {
return nil
}
return r.nfr.DelStatefulRule(r.tunname)
}
// cidrDiff calls add and del as needed to make the set of prefixes in
// old and new match. Returns a map reflecting the actual new state
// (which may be somewhere in between old and new if some commands