Compare commits
6 Commits
docker_sta
...
v1.66.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88e23b6cfd | ||
|
|
d77499e101 | ||
|
|
d904990c14 | ||
|
|
b10ee74e24 | ||
|
|
60d8965df0 | ||
|
|
e2a0fc0bc8 |
@@ -1 +1 @@
|
||||
1.65.0
|
||||
1.66.1
|
||||
|
||||
@@ -58,6 +58,9 @@ type setArgsT struct {
|
||||
updateCheck bool
|
||||
updateApply bool
|
||||
postureChecking bool
|
||||
snat bool
|
||||
statefulFiltering bool
|
||||
netfilterMode string
|
||||
}
|
||||
|
||||
func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
@@ -98,6 +101,10 @@ func newSetFlagSet(goos string, setArgs *setArgsT) *flag.FlagSet {
|
||||
setf.StringVar(&setArgs.opUser, "operator", "", "Unix username to allow to operate on tailscaled without sudo")
|
||||
}
|
||||
switch goos {
|
||||
case "linux":
|
||||
setf.BoolVar(&setArgs.snat, "snat-subnet-routes", true, "source NAT traffic to local routes advertised with --advertise-routes")
|
||||
setf.BoolVar(&setArgs.statefulFiltering, "stateful-filtering", true, "apply stateful filtering to forwarded packets (subnet routers, exit nodes, etc.)")
|
||||
setf.StringVar(&setArgs.netfilterMode, "netfilter-mode", defaultNetfilterMode(), "netfilter mode (one of on, nodivert, off)")
|
||||
case "windows":
|
||||
setf.BoolVar(&setArgs.forceDaemon, "unattended", false, "run in \"Unattended Mode\" where Tailscale keeps running even after the current GUI user logs out (Windows-only)")
|
||||
}
|
||||
@@ -121,6 +128,9 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note that even though we set the values here regardless of whether the
|
||||
// user passed the flag, the value is only used if the user passed the flag.
|
||||
// See updateMaskedPrefsFromUpOrSetFlag.
|
||||
maskedPrefs := &ipn.MaskedPrefs{
|
||||
Prefs: ipn.Prefs{
|
||||
ProfileName: setArgs.profileName,
|
||||
@@ -132,6 +142,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
RunWebClient: setArgs.runWebClient,
|
||||
Hostname: setArgs.hostname,
|
||||
OperatorUser: setArgs.opUser,
|
||||
NoSNAT: !setArgs.snat,
|
||||
ForceDaemon: setArgs.forceDaemon,
|
||||
AutoUpdate: ipn.AutoUpdatePrefs{
|
||||
Check: setArgs.updateCheck,
|
||||
@@ -140,10 +151,22 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
||||
AppConnector: ipn.AppConnectorPrefs{
|
||||
Advertise: setArgs.advertiseConnector,
|
||||
},
|
||||
PostureChecking: setArgs.postureChecking,
|
||||
PostureChecking: setArgs.postureChecking,
|
||||
NoStatefulFiltering: opt.NewBool(!setArgs.statefulFiltering),
|
||||
},
|
||||
}
|
||||
|
||||
if effectiveGOOS() == "linux" {
|
||||
nfMode, warning, err := netfilterModeFromFlag(setArgs.netfilterMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if warning != "" {
|
||||
warnf(warning)
|
||||
}
|
||||
maskedPrefs.Prefs.NetfilterMode = nfMode
|
||||
}
|
||||
|
||||
if setArgs.exitNodeIP != "" {
|
||||
if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
||||
var e ipn.ExitNodeLocalIPError
|
||||
|
||||
@@ -295,25 +295,42 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo
|
||||
|
||||
// Backfills for NoStatefulFiltering occur when loading a profile; just set it explicitly here.
|
||||
prefs.NoStatefulFiltering.Set(!upArgs.statefulFiltering)
|
||||
|
||||
switch upArgs.netfilterMode {
|
||||
case "on":
|
||||
prefs.NetfilterMode = preftype.NetfilterOn
|
||||
case "nodivert":
|
||||
prefs.NetfilterMode = preftype.NetfilterNoDivert
|
||||
warnf("netfilter=nodivert; add iptables calls to ts-* chains manually.")
|
||||
case "off":
|
||||
prefs.NetfilterMode = preftype.NetfilterOff
|
||||
if defaultNetfilterMode() != "off" {
|
||||
warnf("netfilter=off; configure iptables yourself.")
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid value --netfilter-mode=%q", upArgs.netfilterMode)
|
||||
v, warning, err := netfilterModeFromFlag(upArgs.netfilterMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefs.NetfilterMode = v
|
||||
if warning != "" {
|
||||
warnf(warning)
|
||||
}
|
||||
}
|
||||
return prefs, nil
|
||||
}
|
||||
|
||||
// netfilterModeFromFlag returns the preftype.NetfilterMode for the provided
|
||||
// flag value. It returns a warning if there is something the user should know
|
||||
// about the value.
|
||||
func netfilterModeFromFlag(v string) (_ preftype.NetfilterMode, warning string, _ error) {
|
||||
switch v {
|
||||
case "on", "nodivert", "off":
|
||||
default:
|
||||
return preftype.NetfilterOn, "", fmt.Errorf("invalid value --netfilter-mode=%q", v)
|
||||
}
|
||||
m, err := preftype.ParseNetfilterMode(v)
|
||||
if err != nil {
|
||||
return preftype.NetfilterOn, "", err
|
||||
}
|
||||
switch m {
|
||||
case preftype.NetfilterNoDivert:
|
||||
warning = "netfilter=nodivert; add iptables calls to ts-* chains manually."
|
||||
case preftype.NetfilterOff:
|
||||
if defaultNetfilterMode() != "off" {
|
||||
warning = "netfilter=off; configure iptables yourself."
|
||||
}
|
||||
}
|
||||
return m, warning, nil
|
||||
}
|
||||
|
||||
// updatePrefs returns how to edit preferences based on the
|
||||
// flag-provided 'prefs' and the currently active 'curPrefs'.
|
||||
//
|
||||
|
||||
@@ -1773,7 +1773,7 @@ func makeStatefulRuleExprs(tunname string) []expr.Any {
|
||||
// going to our TUN.
|
||||
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpNeq,
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: []byte(tunname),
|
||||
},
|
||||
@@ -1926,7 +1926,7 @@ func (n *nftablesRunner) DelStatefulRule(tunname string) error {
|
||||
return fmt.Errorf("get forward chain: %w", err)
|
||||
}
|
||||
rule, err := findRule(conn, &nftables.Rule{
|
||||
Table: table.Nat,
|
||||
Table: table.Filter,
|
||||
Chain: chain,
|
||||
Exprs: exprs,
|
||||
})
|
||||
|
||||
@@ -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 @@ import (
|
||||
"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 @@ ip route add throw 192.168.0.0/24 table 52` + basic,
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user