fix: improve firewall compatibility

This commit is contained in:
ssongliu
2026-10-12 22:36:18 +08:00
parent e90b201001
commit a40158e3c4
3 changed files with 86 additions and 8 deletions
+28 -5
View File
@@ -582,6 +582,18 @@ func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallR
if err != nil {
return result, err
}
importPrioritySupported := true
if adapter, ok := runtime.(*filterfirewalld.Adapter); ok && slices.ContainsFunc(request.Items, func(item dto.FirewallRuleCreateItem) bool {
return item.SourceKind == constant.FirewallRuleSourceImported
}) {
importPrioritySupported, err = adapter.SupportsRichRulePriority(ctx)
if err != nil {
return result, err
}
if !importPrioritySupported && t != nil {
t.Log("firewalld does not support rich rule priority; ignoring priority for imported rules, original rule ordering is not preserved")
}
}
preparedItems := make([]*createItem, 0, len(request.Items))
var stop error
for index, item := range request.Items {
@@ -593,6 +605,16 @@ func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallR
continue
}
item.Rule.OrderIndex = nil
if item.SourceKind == constant.FirewallRuleSourceImported && !importPrioritySupported {
item.Rule.Priority = nil
if item.Rule.Scope.Provider == filter.ProviderFirewalld && item.Raw != "" && item.ParseStatus != "" && item.ParseStatus != filter.ParseStatusSupported && item.Rule.NativeKind != filter.NativeKindZoneService {
item.Raw, err = filterfirewalld.RemoveRichRulePriority(item.Raw)
if err != nil {
record(createItem{index: index, request: item}, "skipped", err)
continue
}
}
}
rules, err := expandFirewallCreateRule(item, selected)
if err != nil {
status := "failed"
@@ -693,7 +715,7 @@ func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallR
record(*item, "skipped", buserr.New("ErrRecordExist"))
continue
}
if converted {
if converted && importPrioritySupported {
priority++
}
if existing[key] {
@@ -713,7 +735,7 @@ func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallR
}
ufwActions[matchKey] = map[filter.Action]bool{item.request.Rule.Action: true}
}
if converted {
if converted && importPrioritySupported {
if priority > 32767 {
return result, fmt.Errorf("%w: firewalld import order exceeds the priority range", filter.ErrExpansionLimit)
}
@@ -729,18 +751,19 @@ func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallR
continue
}
item.request = prepared
actualKey, err := firewallRuleDuplicateKey(filter.ObservedRule{Rule: prepared.Rule, ParseStatus: prepared.ParseStatus}, false)
}
pending[key] = true
if converted {
actualKey, err := firewallRuleDuplicateKey(filter.ObservedRule{Rule: item.request.Rule, ParseStatus: item.request.ParseStatus}, false)
if err != nil {
return result, err
}
pending[key] = true
if existing[actualKey] || pending[actualKey] {
record(*item, "skipped", buserr.New("ErrRecordExist"))
continue
}
pending[actualKey] = true
}
pending[key] = true
mergedItems = append(mergedItems, item)
}
for _, item := range mergedItems {
+10 -1
View File
@@ -92,6 +92,9 @@ func dockerPolicyRuleKey(tokens []string, backend string) string {
if address, err := netip.ParseAddr(value); err == nil {
value = netip.PrefixFrom(address, address.BitLen()).String()
} else if prefix, err := netip.ParsePrefix(value); err == nil {
if prefix.Bits() == 0 {
continue
}
value = prefix.Masked().String()
}
}
@@ -156,7 +159,13 @@ func parseDockerGuardPolicies(output, family string) (PolicyInventory, error) {
group.acceptedSource = append(group.acceptedSource, source)
case action == "accept":
group.acceptAll = true
case action == "return" && source != "":
case action == "return":
if source == "" {
source = "0.0.0.0/0"
if family == FamilyIPv6 {
source = "::/0"
}
}
group.allowedSource = append(group.allowedSource, source)
case action == "drop" && source != "":
group.droppedSource = append(group.droppedSource, source)
@@ -50,7 +50,7 @@ func (a *Adapter) CheckRule(ctx context.Context, rule filter.FirewallRule) error
if rule.Priority == nil || *rule.Priority == 0 {
return nil
}
supported, err := a.supportsRichRulePriority(ctx)
supported, err := a.SupportsRichRulePriority(ctx)
if err != nil {
return err
}
@@ -60,7 +60,7 @@ func (a *Adapter) CheckRule(ctx context.Context, rule filter.FirewallRule) error
return nil
}
func (a *Adapter) supportsRichRulePriority(ctx context.Context) (bool, error) {
func (a *Adapter) SupportsRichRulePriority(ctx context.Context) (bool, error) {
a.prioritySupportMu.Lock()
defer a.prioritySupportMu.Unlock()
if a.richRulePrioritySupported != nil {
@@ -82,6 +82,52 @@ func (a *Adapter) supportsRichRulePriority(ctx context.Context) (bool, error) {
return supported, nil
}
func RemoveRichRulePriority(raw string) (string, error) {
if strings.ContainsAny(raw, "\r\n\x00") {
return "", filter.ErrInvalidRule
}
parts := make([]string, 0)
removed := false
for start := 0; start < len(raw); {
if raw[start] == ' ' || raw[start] == '\t' {
start++
continue
}
end, quote := start, byte(0)
for end < len(raw) {
char := raw[end]
if char == '\\' && quote != '\'' {
end += 2
continue
}
if quote != 0 {
if char == quote {
quote = 0
}
} else if char == '\'' || char == '"' {
quote = char
} else if char == ' ' || char == '\t' {
break
}
end++
}
if quote != 0 || end > len(raw) {
return "", filter.ErrInvalidRule
}
token := raw[start:end]
if strings.HasPrefix(token, "priority=") {
removed = true
} else {
parts = append(parts, token)
}
start = end
}
if !removed || len(parts) == 0 || parts[0] != "rule" {
return raw, nil
}
return strings.Join(parts, " "), nil
}
func parseFirewalldVersion(output string) (int, int, error) {
version := strings.TrimSpace(output)
parts := strings.Split(version, ".")