Fail closed on unknown/none conntrack DEST and pair all+ symmetrically
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful

This commit is contained in:
2026-10-03 23:50:18 +10:00
parent 1c379bf5f1
commit bf235291d0
2 changed files with 35 additions and 1 deletions
+4 -1
View File
@@ -268,6 +268,9 @@ func (c *Compiler) compileConntrackPair(state *FirewallState, tag, chain string,
return fmt.Errorf("conntrack DEST zone %q needs an address in prerouting", dstZone)
}
srcIfaces, dstIfaces := c.resolveZoneInterfaces(srcZone, srcAddr), []string{""}
if chain == "raw_prerouting" && c.resolveZoneInterfaces(dstZone, dstAddr) == nil {
return nil
}
if chain == "raw_output" {
srcIfaces, dstIfaces = []string{""}, c.resolveZoneInterfaces(dstZone, dstAddr)
}
@@ -417,7 +420,7 @@ func (c *Compiler) compileOneRule(state *FirewallState, tag, srcSpec, dstSpec, p
for _, dst := range c.zoneSpecs(dstSpec) {
// Exclusion expansion never pairs fw with itself, and pairs a zone with itself only for "all+".
if src.Zone == dst.Zone && (isZoneExclusion(srcSpec) || isZoneExclusion(dstSpec)) &&
(src.Zone == fwZone || !strings.Contains(srcSpec, "+!")) {
(src.Zone == fwZone || !strings.Contains(srcSpec, "+!") && !strings.Contains(dstSpec, "+!")) {
continue
}
for _, dstAddr := range splitAddrs(dst.Addr) {
+31
View File
@@ -2506,6 +2506,16 @@ func TestCompile_ConntrackZones(t *testing.T) {
ct: config.ConntrackRule{Action: config.ConntrackDrop, Source: "nte", Dest: "fw"},
want: map[string][]string{},
},
{
name: "unknown dest zone fails closed in prerouting",
ct: config.ConntrackRule{Action: config.ConntrackDrop, Source: "net", Dest: "typo"},
want: map[string][]string{},
},
{
name: "none dest zone yields no rule",
ct: config.ConntrackRule{Action: config.ConntrackDrop, Source: "net", Dest: "none"},
want: map[string][]string{},
},
{
name: "all!net expands to every other zone",
ct: config.ConntrackRule{Action: config.ConntrackNoTrack, Source: "all!net", Dest: "fw:192.0.2.53"},
@@ -2576,3 +2586,24 @@ func TestCompile_RuleZoneExclusionExpands(t *testing.T) {
t.Errorf("unknown zone compiled %d rules, want 0", len(r))
}
}
func TestCompile_RuleZoneExclusionIntraZoneSymmetric(t *testing.T) {
cfg := listCfg(func(cfg *config.Config) {
cfg.Zones["lan"] = config.Zone{Type: config.ZoneIP}
cfg.Interfaces = append(cfg.Interfaces, config.Interface{Zone: "lan", Interface: "eth1"})
cfg.Rules = []config.Rule{
{Source: "lan", Dest: "all+!net", Action: config.RuleAccept},
{Source: "lan", Dest: "all!net", Action: config.RuleAccept},
}
})
state := mustCompile(t, cfg)
for i, want := range []bool{true, false} {
got := false
for _, r := range taggedRules(state, "forward", fmt.Sprintf("rule:%d", i)) {
got = got || describeRule(r) == "iif=eth1 oif=eth1"
}
if got != want {
t.Errorf("rule:%d lan->lan forward = %v, want %v", i, got, want)
}
}
}