Read a machine's iptables rules when it has no nft, instead of calling it unfiltered (hq ADR 0100)

This commit is contained in:
2026-09-22 19:59:22 +02:00
parent c7ff0b9026
commit b4c21b4f67
2 changed files with 46 additions and 3 deletions
+15 -3
View File
@@ -63,19 +63,31 @@ func Detect(ctx context.Context, run Runner) (Kind, string, error) {
ufwActive = statusActive(out)
}
noNft := false
out, err := run(ctx, "nft", "list", "ruleset")
switch {
case err == nil:
if refusing := Refusing(out, ufwActive); len(refusing) > 0 {
return Unsupported, "nftables rules that refuse traffic, in " + strings.Join(refusing, ", "), nil
}
case !missing(err):
case missing(err):
// **No nft on this machine does not mean no rules.** iptables-nft writes tables nft would
// have shown, and a machine whose only tool is iptables answers about them through that.
// Read as "nothing filters here", a machine with an iptables firewall would be adopted
// with no openings and nothing would reach the mesh (novox/hq ADR 0100).
noNft = true
default:
return "", "", fmt.Errorf("cannot read this machine's packet filter to know what it has: %w", err)
}
if !ufwActive {
// iptables with the legacy backend is invisible to nft.
for _, legacy := range []string{"iptables-legacy", "ip6tables-legacy"} {
// iptables with the legacy backend is invisible to nft; and where nft is not installed,
// the iptables command is the only way to see anything at all.
tools := []string{"iptables-legacy", "ip6tables-legacy"}
if noNft {
tools = append(tools, "iptables", "ip6tables")
}
for _, legacy := range tools {
out, err := run(ctx, legacy, "-S")
if err != nil {
continue