diff --git a/util/linuxfw/detector.go b/util/linuxfw/detector.go index ea9e6741f..f3ee4aa0b 100644 --- a/util/linuxfw/detector.go +++ b/util/linuxfw/detector.go @@ -6,6 +6,9 @@ package linuxfw import ( + "errors" + "os/exec" + "tailscale.com/envknob" "tailscale.com/hostinfo" "tailscale.com/types/logger" @@ -30,11 +33,22 @@ func detectFirewallMode(logf logger.Logf, prefHint string) FirewallMode { } else if prefHint != "" { logf("TS_DEBUG_FIREWALL_MODE set, overriding firewall mode from %s to %s", prefHint, mode) } + + var det linuxFWDetector + if mode == "" { + // We have no preference, so check if `iptables` is even available. + _, err := det.iptDetect() + if err != nil && errors.Is(err, exec.ErrNotFound) { + logf("iptables not found: %v; falling back to nftables", err) + mode = "nftables" + } + } + // We now use iptables as default and have "auto" and "nftables" as // options for people to test further. switch mode { case "auto": - return pickFirewallModeFromInstalledRules(logf, linuxFWDetector{}) + return pickFirewallModeFromInstalledRules(logf, det) case "nftables": hostinfo.SetFirewallMode("nft-forced") return FirewallModeNfTables diff --git a/util/linuxfw/iptables.go b/util/linuxfw/iptables.go index 7231c83fe..234fa526c 100644 --- a/util/linuxfw/iptables.go +++ b/util/linuxfw/iptables.go @@ -29,6 +29,9 @@ func DebugIptables(logf logger.Logf) error { // // It only returns an error when there is no iptables binary, or when iptables -S // fails. In all other cases, it returns the number of non-default rules. +// +// If the iptables binary is not found, it returns an underlying exec.ErrNotFound +// error. func detectIptables() (int, error) { // run "iptables -S" to get the list of rules using iptables // exec.Command returns an error if the binary is not found