package config import "fmt" // ResolveNesting computes the effective zone order, ensuring child zones // appear before their parents. This determines the order in which packets // are matched against zones — more specific (child) zones are checked first. func (c *Config) ResolveNesting() ([]string, error) { resolved := make(map[string]bool) var order []string for range c.Zones { progress := false for name, zone := range c.Zones { if resolved[name] { continue } ready := true for _, parent := range zone.Parents { if c.Zones[parent].Type == ZoneFirewall { continue } for childName, childZone := range c.Zones { if childName == name || resolved[childName] { continue } for _, cp := range childZone.Parents { if cp == parent && !resolved[childName] { ready = false } } } } _ = ready if !resolved[name] && allParentsDepsResolved(name, c.Zones, resolved) { resolved[name] = true order = append(order, name) progress = true } } if !progress { break } } if len(order) != len(c.Zones) { return nil, fmt.Errorf("circular zone nesting detected") } return order, nil } func allParentsDepsResolved(name string, zones map[string]Zone, resolved map[string]bool) bool { zone := zones[name] if len(zone.Parents) == 0 { return true } for _, parent := range zone.Parents { for childName, childZone := range zones { if childName == name || childName == parent { continue } for _, cp := range childZone.Parents { if cp == parent && !resolved[childName] { return false } } } } return true } // ChildZones returns all zones that list the given zone as a parent. func (c *Config) ChildZones(parent string) []string { var children []string for name, zone := range c.Zones { for _, p := range zone.Parents { if p == parent { children = append(children, name) break } } } return children } // IsSubZone returns true if child is a sub-zone of parent (directly or transitively). func (c *Config) IsSubZone(child, parent string) bool { zone, ok := c.Zones[child] if !ok { return false } for _, p := range zone.Parents { if p == parent { return true } if c.IsSubZone(p, parent) { return true } } return false }