mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
wgengine/router: print Docker warning when stateful filtering is enabled
When Docker is detected on the host and stateful filtering is enabled, Docker containers may be unable to reach Tailscale nodes (depending on the network settings of a container). Detect Docker when stateful filtering is enabled and print a health warning to aid users in noticing this issue. We avoid printing the warning if the current node isn't advertising any subnet routes and isn't an exit node, since without one of those being true, the node wouldn't have the correct AllowedIPs in WireGuard to allow a Docker container to connect to another Tailscale node anyway. Updates #12070 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Idef538695f4d101b0ef6f3fb398c0eaafc3ae281
This commit is contained in:
parent
25e32cc3ae
commit
5708fc0639
@ -42,6 +42,7 @@ type linuxRouter struct {
|
||||
logf func(fmt string, args ...any)
|
||||
tunname string
|
||||
netMon *netmon.Monitor
|
||||
health *health.Tracker
|
||||
unregNetMon func()
|
||||
addrs map[netip.Prefix]bool
|
||||
routes map[netip.Prefix]bool
|
||||
@ -81,15 +82,16 @@ func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Moni
|
||||
ambientCapNetAdmin: useAmbientCaps(),
|
||||
}
|
||||
|
||||
return newUserspaceRouterAdvanced(logf, tunname, netMon, cmd)
|
||||
return newUserspaceRouterAdvanced(logf, tunname, netMon, cmd, health)
|
||||
}
|
||||
|
||||
func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, netMon *netmon.Monitor, cmd commandRunner) (Router, error) {
|
||||
func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, netMon *netmon.Monitor, cmd commandRunner, health *health.Tracker) (Router, error) {
|
||||
r := &linuxRouter{
|
||||
logf: logf,
|
||||
tunname: tunname,
|
||||
netfilterMode: netfilterOff,
|
||||
netMon: netMon,
|
||||
health: health,
|
||||
|
||||
cmd: cmd,
|
||||
|
||||
@ -420,6 +422,7 @@ func (r *linuxRouter) Set(cfg *Config) error {
|
||||
}
|
||||
}
|
||||
r.statefulFiltering = cfg.StatefulFiltering
|
||||
r.updateStatefulFilteringWithDockerWarning(cfg)
|
||||
|
||||
// Issue 11405: enable IP forwarding on gokrazy.
|
||||
advertisingRoutes := len(cfg.SubnetRoutes) > 0
|
||||
@ -430,6 +433,53 @@ func (r *linuxRouter) Set(cfg *Config) error {
|
||||
return multierr.New(errs...)
|
||||
}
|
||||
|
||||
var warnStatefulFilteringWithDocker = health.NewWarnable()
|
||||
|
||||
func (r *linuxRouter) updateStatefulFilteringWithDockerWarning(cfg *Config) {
|
||||
// If stateful filtering is disabled, clear the warning.
|
||||
if !r.statefulFiltering {
|
||||
r.health.SetWarnable(warnStatefulFilteringWithDocker, nil)
|
||||
return
|
||||
}
|
||||
|
||||
advertisingRoutes := len(cfg.SubnetRoutes) > 0
|
||||
|
||||
// TODO(andrew-d,maisem): we might want to check if we're running in a
|
||||
// container, since, if so, stateful filtering might prevent other
|
||||
// containers from connecting through the Tailscale in this container.
|
||||
//
|
||||
// For now, just check for the case where we're running Tailscale on
|
||||
// the host and Docker is also running.
|
||||
|
||||
// If this node isn't a subnet router or exit node, then we would never
|
||||
// have allowed traffic from a Docker container in to Tailscale, since
|
||||
// there wouldn't be an AllowedIP for the container's source IP. So we
|
||||
// don't need to warn in this case.
|
||||
//
|
||||
// cfg.SubnetRoutes contains all subnet routes for the node, including
|
||||
// the default route (0.0.0.0/0 or ::/0) if this node is an exit node.
|
||||
if advertisingRoutes {
|
||||
// Check for the presence of a Docker interface and warn if it's found
|
||||
// on the system.
|
||||
//
|
||||
// TODO(andrew-d): do a better job at detecting Docker, e.g. by looking
|
||||
// for it in the $PATH or by checking for the presence of the Docker
|
||||
// socket/daemon/etc.
|
||||
ifstate := r.netMon.InterfaceState()
|
||||
if _, found := ifstate.Interface["docker0"]; found {
|
||||
r.health.SetWarnable(warnStatefulFilteringWithDocker, fmt.Errorf(""+
|
||||
"Stateful filtering is enabled and Docker was detected; this may prevent Docker containers "+
|
||||
"on this host from connecting to Tailscale nodes. "+
|
||||
"See https://tailscale.com/s/stateful-docker",
|
||||
))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, then we have no warnings; clear anything existing.
|
||||
r.health.SetWarnable(warnStatefulFilteringWithDocker, nil)
|
||||
}
|
||||
|
||||
// UpdateMagicsockPort implements the Router interface.
|
||||
func (r *linuxRouter) UpdateMagicsockPort(port uint16, network string) error {
|
||||
if r.nfr == nil {
|
||||
|
@ -22,6 +22,7 @@
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"github.com/vishvananda/netlink"
|
||||
"go4.org/netipx"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tstest"
|
||||
@ -369,7 +370,8 @@ func TestRouterStates(t *testing.T) {
|
||||
defer mon.Close()
|
||||
|
||||
fake := NewFakeOS(t)
|
||||
router, err := newUserspaceRouterAdvanced(t.Logf, "tailscale0", mon, fake)
|
||||
ht := new(health.Tracker)
|
||||
router, err := newUserspaceRouterAdvanced(t.Logf, "tailscale0", mon, fake, ht)
|
||||
router.(*linuxRouter).nfr = fake.nfr
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create router: %v", err)
|
||||
|
Loading…
Reference in New Issue
Block a user