Accept intra-zone traffic between different interfaces
This commit is contained in:
@@ -857,16 +857,21 @@ func (c *Compiler) compileDNATRule(state *FirewallState, tag, srcZone, srcAddr,
|
||||
func (c *Compiler) compilePolicies(state *FirewallState) error {
|
||||
fwZone := c.cfg.FirewallZone()
|
||||
|
||||
overridden := map[string]bool{}
|
||||
for i, pol := range c.cfg.Policy {
|
||||
tag := fmt.Sprintf("policy:%d", i)
|
||||
explicitIntra := pol.Source == pol.Dest && !isGlobalZone(pol.Source)
|
||||
|
||||
srcZones := c.expandZoneRef(pol.Source)
|
||||
dstZones := c.expandZoneRef(pol.Dest)
|
||||
|
||||
for _, sz := range srcZones {
|
||||
for _, dz := range dstZones {
|
||||
if sz == dz && !strings.HasSuffix(pol.Source, "+") {
|
||||
continue
|
||||
if sz == dz {
|
||||
if !explicitIntra && !strings.HasSuffix(pol.Source, "+") {
|
||||
continue
|
||||
}
|
||||
overridden[sz] = true
|
||||
}
|
||||
|
||||
chain := c.selectChain(sz, dz, fwZone)
|
||||
@@ -875,6 +880,9 @@ func (c *Compiler) compilePolicies(state *FirewallState) error {
|
||||
|
||||
for _, si := range srcIfaces {
|
||||
for _, di := range dstIfaces {
|
||||
if sz == dz && si != "" && si == di {
|
||||
continue
|
||||
}
|
||||
var exprs []expr.Any
|
||||
|
||||
if si != "" {
|
||||
@@ -909,9 +917,39 @@ func (c *Compiler) compilePolicies(state *FirewallState) error {
|
||||
}
|
||||
}
|
||||
|
||||
c.compileImplicitIntraZone(state, overridden)
|
||||
return nil
|
||||
}
|
||||
|
||||
// compileImplicitIntraZone accepts traffic between different interfaces of one zone, shorewall's implicit intra-zone ACCEPT policy.
|
||||
func (c *Compiler) compileImplicitIntraZone(state *FirewallState, overridden map[string]bool) {
|
||||
fwZone := c.cfg.FirewallZone()
|
||||
zones := make([]string, 0, len(c.cfg.Zones))
|
||||
for z := range c.cfg.Zones {
|
||||
zones = append(zones, z)
|
||||
}
|
||||
sort.Strings(zones)
|
||||
for _, z := range zones {
|
||||
if z == fwZone || overridden[z] {
|
||||
continue
|
||||
}
|
||||
ifaces := c.cfg.ZoneInterfaces(z)
|
||||
for _, si := range ifaces {
|
||||
for _, di := range ifaces {
|
||||
if si == di {
|
||||
continue
|
||||
}
|
||||
state.Rules["forward"] = append(state.Rules["forward"], ManagedRule{
|
||||
Chain: "forward",
|
||||
Exprs: append(append(matchIfaceName(true, si), matchIfaceName(false, di)...),
|
||||
&expr.Verdict{Kind: expr.VerdictAccept}),
|
||||
Tag: "intra:" + z,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) compileSNAT(state *FirewallState) error {
|
||||
for i, snat := range c.cfg.SNAT {
|
||||
tag := fmt.Sprintf("snat:%d", i)
|
||||
|
||||
@@ -3320,3 +3320,71 @@ func TestCompile_LogLimitSplitsAroundExtrasAndNAT(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompile_IntraZoneMultiInterface(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
policy []config.Policy
|
||||
tag string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "implicit accept between distinct interfaces",
|
||||
policy: []config.Policy{{Source: "all", Dest: "all", Action: config.PolicyDrop}},
|
||||
tag: "intra:lxd",
|
||||
want: []string{"iif=lxdbr0 oif=docker0", "iif=lxdbr0 oif=br-", "iif=docker0 oif=lxdbr0", "iif=docker0 oif=br-", "iif=br- oif=lxdbr0", "iif=br- oif=docker0"},
|
||||
},
|
||||
{
|
||||
name: "explicit zone policy overrides",
|
||||
policy: []config.Policy{{Source: "lxd", Dest: "lxd", Action: config.PolicyDrop, Log: "info"}, {Source: "all", Dest: "all", Action: config.PolicyDrop}},
|
||||
tag: "policy:0",
|
||||
want: []string{"iif=lxdbr0 oif=docker0", "iif=lxdbr0 oif=br-", "iif=docker0 oif=lxdbr0", "iif=docker0 oif=br-", "iif=br- oif=lxdbr0", "iif=br- oif=docker0"},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Settings: config.Settings{TableName: "test", AddressFamily: config.FamilyINET},
|
||||
Zones: map[string]config.Zone{
|
||||
"fw": {Type: config.ZoneFirewall},
|
||||
"net": {Type: config.ZoneIP},
|
||||
"lxd": {Type: config.ZoneIP},
|
||||
},
|
||||
Interfaces: []config.Interface{
|
||||
{Zone: "net", Interface: "eth0"},
|
||||
{Zone: "lxd", Interface: "lxdbr0"},
|
||||
{Zone: "lxd", Interface: "docker0"},
|
||||
{Zone: "lxd", Interface: "br-+"},
|
||||
},
|
||||
Policy: tc.policy,
|
||||
PortGroups: map[string]config.PortGroup{},
|
||||
}
|
||||
state, err := NewCompiler(cfg).Compile()
|
||||
if err != nil {
|
||||
t.Fatalf("Compile() error: %v", err)
|
||||
}
|
||||
var got, all []string
|
||||
for _, r := range state.Rules["forward"] {
|
||||
if r.Tag == tc.tag {
|
||||
got = append(got, describeRule(r))
|
||||
}
|
||||
if strings.HasPrefix(r.Tag, "intra:") {
|
||||
all = append(all, r.Tag)
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("%s rules = %q, want %q", tc.tag, got, tc.want)
|
||||
}
|
||||
if tc.tag != "intra:lxd" && len(all) != 0 {
|
||||
t.Errorf("explicit policy must replace implicit accept, got %q", all)
|
||||
}
|
||||
last := taggedRules(state, "forward", tc.tag)
|
||||
if len(last) == 0 {
|
||||
return
|
||||
}
|
||||
if v, ok := last[0].Exprs[len(last[0].Exprs)-1].(*expr.Verdict); !ok || (tc.tag == "intra:lxd") != (v.Kind == expr.VerdictAccept) {
|
||||
t.Errorf("%s verdict = %#v", tc.tag, last[0].Exprs[len(last[0].Exprs)-1])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user