util/linuxfw: fall back to nftables when iptables not found

When the desired netfilter mode was unset, we would always try
to use the `iptables` binary. In such cases if iptables was not found,
tailscaled would just crash as seen in #13440. To work around this, in those
cases check if the `iptables` binary even exists and if it doesn't fall back
to the nftables implementation.

Verified that it works on stock Ubuntu 24.04.

Updates #5621
Updates #8555
Updates #8762
Fixes #13440

Signed-off-by: Maisem Ali <maisem@tailscale.com>
pull/13444/head
Maisem Ali 3 months ago committed by Maisem Ali
parent 98f4dd9857
commit 4d6a8224d5

@ -6,6 +6,9 @@
package linuxfw package linuxfw
import ( import (
"errors"
"os/exec"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/hostinfo" "tailscale.com/hostinfo"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -30,11 +33,22 @@ func detectFirewallMode(logf logger.Logf, prefHint string) FirewallMode {
} else if prefHint != "" { } else if prefHint != "" {
logf("TS_DEBUG_FIREWALL_MODE set, overriding firewall mode from %s to %s", prefHint, mode) 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 // We now use iptables as default and have "auto" and "nftables" as
// options for people to test further. // options for people to test further.
switch mode { switch mode {
case "auto": case "auto":
return pickFirewallModeFromInstalledRules(logf, linuxFWDetector{}) return pickFirewallModeFromInstalledRules(logf, det)
case "nftables": case "nftables":
hostinfo.SetFirewallMode("nft-forced") hostinfo.SetFirewallMode("nft-forced")
return FirewallModeNfTables return FirewallModeNfTables

@ -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 // 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. // 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) { func detectIptables() (int, error) {
// run "iptables -S" to get the list of rules using iptables // run "iptables -S" to get the list of rules using iptables
// exec.Command returns an error if the binary is not found // exec.Command returns an error if the binary is not found

Loading…
Cancel
Save