diff --git a/internal/nftables/compiler.go b/internal/nftables/compiler.go index 416ca06..f492694 100644 --- a/internal/nftables/compiler.go +++ b/internal/nftables/compiler.go @@ -599,7 +599,7 @@ func (c *Compiler) compilePolicies(state *FirewallState) error { if si != "" { exprs = append(exprs, matchIfaceName(true, si)...) } - if di != "" && chain == "forward" { + if di != "" && chain != "input" { exprs = append(exprs, matchIfaceName(false, di)...) } @@ -997,7 +997,7 @@ func (c *Compiler) buildMatchExprs(srcIface, dstIface, chain, proto string, dpor if srcIface != "" { exprs = append(exprs, matchIfaceName(true, srcIface)...) } - if dstIface != "" && chain == "forward" { + if dstIface != "" && chain != "input" { exprs = append(exprs, matchIfaceName(false, dstIface)...) } diff --git a/internal/nftables/compiler_test.go b/internal/nftables/compiler_test.go index 623b4c3..46203af 100644 --- a/internal/nftables/compiler_test.go +++ b/internal/nftables/compiler_test.go @@ -1757,6 +1757,17 @@ func TestCompile_PortAndProtoLists(t *testing.T) { }) } } +func TestCompile_OutputPolicyMatchesOif(t *testing.T) { + cfg := listCfg(func(c *config.Config) { + c.Zones["lan"] = config.Zone{Type: config.ZoneIP} + c.Interfaces = append(c.Interfaces, config.Interface{Zone: "lan", Interface: "eth1"}) + c.Policy = []config.Policy{{Source: "fw", Dest: "lan", Action: config.PolicyAccept}} + }) + got := taggedRules(mustCompile(t, cfg), "output", "policy:0") + if len(got) != 1 || describeRule(got[0]) != "oif=eth1" { + t.Fatalf("fw->lan policy = %v, want one rule oif=eth1", got) + } +} // describeRule renders a rule's iif/oif/saddr/daddr matches, e.g. "iif=eth1 oif=eth2 daddr=192.0.2.1". func describeRule(r ManagedRule) string { @@ -1803,7 +1814,7 @@ func TestCompile_CommaZoneLists(t *testing.T) { { name: "fw in source list goes to output", rule: config.Rule{Action: config.RuleAccept, Source: "fw,lan", Dest: "svr", Proto: "tcp", DPort: config.PortSpec{"22"}}, - want: map[string][]string{"output": {""}, "forward": {"iif=eth1 oif=eth2"}}, + want: map[string][]string{"output": {"oif=eth2"}, "forward": {"iif=eth1 oif=eth2"}}, }, { name: "dest list with fw splits input and forward", @@ -1850,6 +1861,16 @@ func TestCompile_CommaZoneLists(t *testing.T) { rule: config.Rule{Action: config.RuleAccept, Source: "lan", Dest: "vpn,dmz"}, want: map[string][]string{"forward": {"iif=eth1"}}, }, + { + name: "fw source matches dest zone oif", + rule: config.Rule{Action: config.RuleAccept, Source: "fw", Dest: "lan,vpn,dmz", Proto: "tcp", DPort: config.PortSpec{"22"}}, + want: map[string][]string{"output": {"oif=eth1", ""}}, + }, + { + name: "fw to all has no oif", + rule: config.Rule{Action: config.RuleAccept, Source: "fw", Dest: "all:192.0.2.1"}, + want: map[string][]string{"output": {"daddr=192.0.2.1"}}, + }, { name: "blrule zone list", blrule: &config.BlruleRule{Action: config.BlruleDrop, Source: "net,anycast", Dest: "fw"},