From c695a2a408287751f21c0786d5175b2f3f95144f Mon Sep 17 00:00:00 2001 From: ssongliu Date: Fri, 16 Oct 2026 17:27:48 +0800 Subject: [PATCH] fix(firewall): prepare access whitelist before startup (#14114) --- agent/app/service/firewall_utils.go | 65 +++++++++++++++++++ .../src/views/host/firewall/status/index.vue | 4 +- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/agent/app/service/firewall_utils.go b/agent/app/service/firewall_utils.go index 3cd3227f8..da2d096eb 100644 --- a/agent/app/service/firewall_utils.go +++ b/agent/app/service/firewall_utils.go @@ -1807,17 +1807,82 @@ func operateFirewallLifecycle(client lifecycle.Client, operation string, withDoc } func (c firewallLifecycleClient) Start() error { + firewallWhitelistMu.Lock() + defer firewallWhitelistMu.Unlock() firewallRuleMutationMu.Lock() defer firewallRuleMutationMu.Unlock() + if err := c.prepareAccessWhitelistBeforeStart(); err != nil { + global.LOG.Warnf("prepare %s access whitelist before start failed: %v", c.Name(), err) + } return c.Client.Start() } func (c firewallLifecycleClient) Restart() error { + firewallWhitelistMu.Lock() + defer firewallWhitelistMu.Unlock() firewallRuleMutationMu.Lock() defer firewallRuleMutationMu.Unlock() + if err := c.prepareAccessWhitelistBeforeStart(); err != nil { + global.LOG.Warnf("prepare %s access whitelist before restart failed: %v", c.Name(), err) + } return c.Client.Restart() } +func (c firewallLifecycleClient) prepareAccessWhitelistBeforeStart() error { + provider := filter.Provider(c.Name()) + if provider != filter.ProviderFirewalld && provider != filter.ProviderUFW { + return nil + } + ports, err := LoadRequiredFirewallPortWhiteList() + if err != nil { + return err + } + var adapter filter.Adapter + var active bool + if provider == filter.ProviderFirewalld { + active, err = c.Status() + if err != nil { + return err + } + adapter = filterfirewalld.NewAdapter() + } else { + adapter = filterufw.NewAdapter() + } + var commands []filter.NativeCommand + for _, port := range firewall.ExpandPortWhitelist(ports) { + rule := firewall.RuleForSystemPort(provider, port) + rule.Scope = rule.Scope.Normalize() + rule.UUID = uuid.NewString() + if provider == filter.ProviderUFW { + position := int64(1) + rule.OrderIndex = &position + } + plan, err := adapter.BuildCommands(filter.RuleSet{Scope: rule.Scope}, []filter.RuleChange{{Operation: filter.ChangeCreate, After: &rule}}) + if err != nil { + return err + } + for _, item := range plan.Rules { + for _, command := range item.Commands { + if provider == filter.ProviderFirewalld { + if active { + command.Args = append(command.Args, "--permanent") + } else { + command.Executable = "firewall-offline-cmd" + } + } + commands = append(commands, command) + } + } + } + manager := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second), cmd.WithEnv("LC_ALL=C", "LANGUAGE=en_US:en")) + for _, command := range commands { + if err := manager.RunWithOptionalSudo(command.Executable, command.Args...); err != nil { + return fmt.Errorf("prepare %s access whitelist before start: %w", provider, err) + } + } + return nil +} + func runFirewallLifecycleAction(t *task.Task, name string, action func() error) error { t.Log(i18n.GetWithName("TaskStart", name)) started := time.Now() diff --git a/frontend/src/views/host/firewall/status/index.vue b/frontend/src/views/host/firewall/status/index.vue index 25374b38a..69a331b3d 100644 --- a/frontend/src/views/host/firewall/status/index.vue +++ b/frontend/src/views/host/firewall/status/index.vue @@ -227,7 +227,7 @@ import { useGlobalStore } from '@/composables/useGlobalStore'; const props = defineProps({ currentTab: String, }); -const { docsUrl } = useGlobalStore(); +const { docsUrl, isIntl } = useGlobalStore(); const goToFirewallSetting = () => routerToName('FirewallSetting'); const goToScriptLibrary = () => routerToNameWithQuery('Library', { uncached: 'true' }); @@ -317,7 +317,7 @@ const familyActions = computed(() => message: familyIssueText(issue), helpUrl: issue.available && issue.reason === 'ipv6_ra_required' - ? `${docsUrl.value}/user_manual/hosts/firewall` + ? `${docsUrl.value}/user_manual/${isIntl.value ? 'system' : 'hosts'}/firewall` : undefined, action, };