mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 00:00:50 +00:00
fix: improve firewall abnormal state diagnostics (#13673)
This commit is contained in:
@@ -121,24 +121,31 @@ func (b *BaseApi) OperateForwardingRules(c *gin.Context) {
|
||||
|
||||
// @Tags Firewall
|
||||
// @Summary Enable forwarding
|
||||
// @Success 200
|
||||
// @Accept json
|
||||
// @Param request body dto.FirewallInitializationTask true "request"
|
||||
// @Success 200 {object} dto.FilterChainOperationResponse
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/firewall/forward/enable [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"初始化并启用端口转发","formatEN":"initialize and enable port forwarding"}
|
||||
func (b *BaseApi) EnableForwarding(c *gin.Context) {
|
||||
if err := forwardingService.Enable(); err != nil {
|
||||
var request dto.FirewallInitializationTask
|
||||
if err := helper.CheckBindAndValidate(&request, c); err != nil {
|
||||
return
|
||||
}
|
||||
result, err := forwardingService.QueueInitialization(request)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
helper.SuccessWithData(c, result)
|
||||
}
|
||||
|
||||
// @Tags Firewall
|
||||
// @Summary Apply/Unload/Init firewall filter chain
|
||||
// @Accept json
|
||||
// @Param request body dto.FilterChainOperation true "request"
|
||||
// @Success 200
|
||||
// @Success 200 {object} dto.FilterChainOperationResponse
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/firewall/filter/operate [post]
|
||||
@@ -148,12 +155,20 @@ func (b *BaseApi) OperateFilterChain(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&request, c); err != nil {
|
||||
return
|
||||
}
|
||||
if request.Operate == "init-base" {
|
||||
result, err := firewallService.QueueFilterChainInitialization(request)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, result)
|
||||
return
|
||||
}
|
||||
if err := firewallService.OperateFilterChain(request); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.Success(c)
|
||||
helper.SuccessWithData(c, dto.FilterChainOperationResponse{})
|
||||
}
|
||||
|
||||
// @Tags Firewall
|
||||
@@ -533,7 +548,7 @@ func (b *BaseApi) SyncDockerPortGuard(c *gin.Context) {
|
||||
// @Summary Operate Docker port guard
|
||||
// @Accept json
|
||||
// @Param request body dto.DockerPortGuardOperation true "request"
|
||||
// @Success 200
|
||||
// @Success 200 {object} dto.FilterChainOperationResponse
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/firewall/docker/operate [post]
|
||||
@@ -543,6 +558,15 @@ func (b *BaseApi) OperateDockerPortGuard(c *gin.Context) {
|
||||
if err := helper.CheckBindAndValidate(&request, c); err != nil {
|
||||
return
|
||||
}
|
||||
if request.Operation == "initialize" {
|
||||
result, err := dockerPortGuardService.QueueInitialization(request)
|
||||
if err != nil {
|
||||
handleDockerPortGuardError(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, result)
|
||||
return
|
||||
}
|
||||
if err := dockerPortGuardService.Operate(c.Request.Context(), request); err != nil {
|
||||
handleDockerPortGuardError(c, err)
|
||||
return
|
||||
|
||||
@@ -71,6 +71,16 @@ type FirewallBackendOperation struct {
|
||||
type FilterChainOperation struct {
|
||||
Name string `json:"name" validate:"required,eq=1PANEL_BASIC"`
|
||||
Operate string `json:"operate" validate:"required,oneof=init-base bind-base unbind-base"`
|
||||
TaskID string `json:"taskID,omitempty" validate:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
type FilterChainOperationResponse struct {
|
||||
TaskID string `json:"taskID"`
|
||||
Queued bool `json:"queued"`
|
||||
}
|
||||
|
||||
type FirewallInitializationTask struct {
|
||||
TaskID string `json:"taskID,omitempty" validate:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
type FirewallSystemPort struct {
|
||||
@@ -206,6 +216,7 @@ type DockerPortGuardPolicyBatchDelete struct {
|
||||
|
||||
type DockerPortGuardOperation struct {
|
||||
Operation string `json:"operation" validate:"required,oneof=initialize bind unbind"`
|
||||
TaskID string `json:"taskID,omitempty" validate:"omitempty,max=64"`
|
||||
}
|
||||
|
||||
type FirewallRuleCheckItem struct {
|
||||
|
||||
@@ -13,8 +13,10 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
filterruntime "github.com/1Panel-dev/1Panel/agent/utils/firewall/filter/runtime"
|
||||
@@ -50,6 +52,7 @@ type IFirewallService interface {
|
||||
LoadBaseInfo(chainGroup string) (dto.FirewallSubsystemStatus, error)
|
||||
OperateFirewall(request dto.FirewallLifecycleOperation) error
|
||||
OperateFilterChain(request dto.FilterChainOperation) error
|
||||
QueueFilterChainInitialization(request dto.FilterChainOperation) (dto.FilterChainOperationResponse, error)
|
||||
Reset(context.Context, dto.FirewallRuleReset) (dto.FirewallRuleResetResponse, error)
|
||||
Inventory(context.Context, dto.FirewallRuleInventory) (dto.FirewallRuleInventoryResponse, error)
|
||||
LoadFirewallNativeDetail(context.Context, dto.FirewallNativeDetail) (string, error)
|
||||
@@ -156,6 +159,61 @@ func (s *FirewallService) OperateFilterChain(request dto.FilterChainOperation) e
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.operateFilterChainBase(provider, request); err != nil {
|
||||
return err
|
||||
}
|
||||
if request.Operate != string(firewall.BaseOperationInit) && request.Operate != string(firewall.BaseOperationBind) {
|
||||
return nil
|
||||
}
|
||||
ctx := context.Background()
|
||||
if err := s.restoreStoredFirewallRules(ctx, filter.Provider(provider)); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.syncConfiguredFirewallPorts(ctx)
|
||||
}
|
||||
|
||||
func (s *FirewallService) QueueFilterChainInitialization(
|
||||
request dto.FilterChainOperation,
|
||||
) (dto.FilterChainOperationResponse, error) {
|
||||
if request.Operate != string(firewall.BaseOperationInit) {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("only filter chain initialization can be queued")
|
||||
}
|
||||
provider, err := selectedSystemFirewallProvider()
|
||||
if err != nil {
|
||||
return dto.FilterChainOperationResponse{}, err
|
||||
}
|
||||
if !supportsManagedFilterChains(provider) {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("filter chain operations are not supported for %s", provider)
|
||||
}
|
||||
if err := task.CheckScopeTaskIsExecuting(task.TaskScopeFirewall, 0); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, err
|
||||
}
|
||||
|
||||
resourceName := fmt.Sprintf("%s filter", provider)
|
||||
taskItem, err := task.NewTaskWithOps(resourceName, task.TaskExec, task.TaskScopeFirewall, request.TaskID, 0)
|
||||
if err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("create firewall initialization task: %w", err)
|
||||
}
|
||||
taskItem.AddSubTask(i18n.GetWithName("FirewallInitializeChainsStep", provider), func(t *task.Task) error {
|
||||
t.Logf("backend=%s", provider)
|
||||
return s.operateFilterChainBase(provider, request)
|
||||
}, nil)
|
||||
taskItem.AddSubTask(i18n.GetWithName("FirewallRestoreRulesStep", provider), func(t *task.Task) error {
|
||||
return s.restoreStoredFirewallRules(t.TaskCtx, filter.Provider(provider))
|
||||
}, nil)
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("FirewallSyncWhitelistStep"), func(t *task.Task) error {
|
||||
return s.syncConfiguredFirewallPorts(t.TaskCtx)
|
||||
}, nil)
|
||||
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("save firewall initialization task: %w", err)
|
||||
}
|
||||
go func() {
|
||||
_ = taskItem.Execute()
|
||||
}()
|
||||
return dto.FilterChainOperationResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
||||
}
|
||||
|
||||
func (s *FirewallService) operateFilterChainBase(provider string, request dto.FilterChainOperation) error {
|
||||
if !supportsManagedFilterChains(provider) {
|
||||
return fmt.Errorf("filter chain operations are not supported for %s", provider)
|
||||
}
|
||||
@@ -166,13 +224,10 @@ func (s *FirewallService) OperateFilterChain(request dto.FilterChainOperation) e
|
||||
} else if err := s.iptablesHelper.Operate(firewall.BaseOperation(request.Operate)); err != nil {
|
||||
return err
|
||||
}
|
||||
if request.Operate != string(firewall.BaseOperationInit) && request.Operate != string(firewall.BaseOperationBind) {
|
||||
return nil
|
||||
}
|
||||
ctx := context.Background()
|
||||
if err := s.restoreStoredFirewallRules(ctx, filter.Provider(provider)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FirewallService) syncConfiguredFirewallPorts(ctx context.Context) error {
|
||||
configured, err := loadConfiguredFirewallPortWhiteList()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
agenti18n "github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
@@ -56,6 +57,7 @@ type IDockerPortGuardService interface {
|
||||
LoadOverview(context.Context) (dto.DockerPortGuardList, error)
|
||||
LoadPublishedPorts(context.Context) ([]dto.DockerPortGuardContainer, error)
|
||||
Operate(context.Context, dto.DockerPortGuardOperation) error
|
||||
QueueInitialization(dto.DockerPortGuardOperation) (dto.FilterChainOperationResponse, error)
|
||||
DeletePolicies(context.Context, dto.DockerPortGuardPolicyBatchDelete) error
|
||||
UpsertPolicies(context.Context, dto.DockerPortGuardPolicyBatch) error
|
||||
Reconcile(context.Context) error
|
||||
@@ -219,6 +221,60 @@ func (s *DockerPortGuardService) Operate(ctx context.Context, request dto.Docker
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerPortGuardService) QueueInitialization(
|
||||
request dto.DockerPortGuardOperation,
|
||||
) (dto.FilterChainOperationResponse, error) {
|
||||
if request.Operation != "initialize" {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("only Docker port guard initialization can be queued")
|
||||
}
|
||||
if err := task.CheckScopeTaskIsExecuting(task.TaskScopeFirewall, 0); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, err
|
||||
}
|
||||
taskItem, err := task.NewTaskWithOps("Docker port guard", task.TaskExec, task.TaskScopeFirewall, request.TaskID, 0)
|
||||
if err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("create Docker port guard initialization task: %w", err)
|
||||
}
|
||||
var runtime dockerGuardRuntime
|
||||
var backend string
|
||||
var policies []docker_guard.Policy
|
||||
taskItem.AddSubTask(agenti18n.GetMsgByKey("FirewallInspectDockerGuardStep"), func(t *task.Task) error {
|
||||
var err error
|
||||
runtime, backend, err = s.runtimeForDocker(t.TaskCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policies, err = s.runtimePolicies(t.TaskCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Logf("backend=%s", backend)
|
||||
return nil
|
||||
}, nil)
|
||||
taskItem.AddSubTask(agenti18n.GetWithName("FirewallInitializeDockerGuardStep", "Docker"), func(t *task.Task) error {
|
||||
dockerPortGuardServiceMu.Lock()
|
||||
defer dockerPortGuardServiceMu.Unlock()
|
||||
t.Logf("backend=%s", backend)
|
||||
err := runtime.Initialize(policies)
|
||||
recordDockerPortGuardReconcileError(err)
|
||||
return err
|
||||
}, nil)
|
||||
taskItem.AddSubTask(agenti18n.GetMsgByKey("FirewallPersistDockerGuardStep"), func(t *task.Task) error {
|
||||
if err := settingRepo.UpdateOrCreate(constant.FirewallDockerBackendKey, backend); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.UpdateOrCreate(constant.FirewallDockerPortGuardStatusKey, constant.StatusEnable); err != nil {
|
||||
return err
|
||||
}
|
||||
recordDockerPortGuardReconcileError(nil)
|
||||
return nil
|
||||
}, nil)
|
||||
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("save Docker port guard initialization task: %w", err)
|
||||
}
|
||||
go func() { _ = taskItem.Execute() }()
|
||||
return dto.FilterChainOperationResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
||||
}
|
||||
|
||||
func (s *DockerPortGuardService) DeletePolicies(ctx context.Context, request dto.DockerPortGuardPolicyBatchDelete) error {
|
||||
dockerPortGuardServiceMu.Lock()
|
||||
defer dockerPortGuardServiceMu.Unlock()
|
||||
|
||||
@@ -11,9 +11,11 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/forwarding"
|
||||
forwardingproviders "github.com/1Panel-dev/1Panel/agent/utils/firewall/forwarding/providers"
|
||||
@@ -26,6 +28,7 @@ type IForwardingService interface {
|
||||
SearchRules(request dto.ForwardRuleSearch) (int64, interface{}, error)
|
||||
OperateRules(request dto.ForwardRuleOperate) error
|
||||
Enable() error
|
||||
QueueInitialization(dto.FirewallInitializationTask) (dto.FilterChainOperationResponse, error)
|
||||
Restore(context.Context) error
|
||||
}
|
||||
|
||||
@@ -249,6 +252,58 @@ func (s *ForwardingService) Enable() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ForwardingService) QueueInitialization(
|
||||
request dto.FirewallInitializationTask,
|
||||
) (dto.FilterChainOperationResponse, error) {
|
||||
if err := task.CheckScopeTaskIsExecuting(task.TaskScopeFirewall, 0); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, err
|
||||
}
|
||||
taskItem, err := task.NewTaskWithOps("port forwarding", task.TaskExec, task.TaskScopeFirewall, request.TaskID, 0)
|
||||
if err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("create forwarding initialization task: %w", err)
|
||||
}
|
||||
var manager *forwarding.Manager
|
||||
var backend string
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("FirewallEnableForwardingStep"), func(t *task.Task) error {
|
||||
forwardingMutationMu.Lock()
|
||||
defer forwardingMutationMu.Unlock()
|
||||
var err error
|
||||
manager, err = s.manager()
|
||||
if err != nil {
|
||||
recordForwardingSyncError(err)
|
||||
return err
|
||||
}
|
||||
backend = manager.Name()
|
||||
t.Logf("backend=%s", backend)
|
||||
if err := s.persistForwardingEnabled(); err != nil {
|
||||
recordForwardingSyncError(err)
|
||||
return err
|
||||
}
|
||||
if err := s.activateManager(manager); err != nil {
|
||||
recordForwardingSyncError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
taskItem.AddSubTask(i18n.GetMsgByKey("FirewallRestoreForwardingRulesStep"), func(t *task.Task) error {
|
||||
forwardingMutationMu.Lock()
|
||||
defer forwardingMutationMu.Unlock()
|
||||
rules, err := s.rules.List(t.TaskCtx)
|
||||
if err != nil {
|
||||
recordForwardingSyncError(err)
|
||||
return err
|
||||
}
|
||||
err = manager.Reconcile(forwardingRulesFromModels(rules))
|
||||
recordForwardingSyncError(err)
|
||||
return err
|
||||
}, nil)
|
||||
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
||||
return dto.FilterChainOperationResponse{}, fmt.Errorf("save forwarding initialization task: %w", err)
|
||||
}
|
||||
go func() { _ = taskItem.Execute() }()
|
||||
return dto.FilterChainOperationResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
||||
}
|
||||
|
||||
func (s *ForwardingService) Restore(ctx context.Context) error {
|
||||
forwardingMutationMu.Lock()
|
||||
defer forwardingMutationMu.Unlock()
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: "The {{ .name }} application is not compatible with the
|
||||
ErrDockerFailed: 'Docker is abnormal; check service status'
|
||||
ErrDockerIptablesChainUnavailable: 'The Docker DOCKER-USER chain was not found. Restart Docker and try again'
|
||||
ErrDockerNftablesChainUnavailable: 'The Docker nftables IPv4 firewall chain was not found. Verify that the current Docker version supports the nftables firewall backend, restart Docker, and try again'
|
||||
ErrUFWRuleAdopt: 'Failed to adopt the UFW rule: {{ .detail }}. If the installed UFW version is earlier than 0.35, upgrade UFW and try again'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose not found on host'
|
||||
UseExistImage: 'Image exists; using existing image'
|
||||
UpgradePrepare: 'Prepare application upgrade'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} firewall rules failed to synchron
|
||||
FirewallResetSourceStep: 'Reset and disable source firewall {{ .name }}'
|
||||
FirewallResetSourceResult: 'Source firewall reset completed; {{ .removed }} database rules were deleted'
|
||||
FirewallVerifyTargetStep: 'Verify target firewall rules'
|
||||
FirewallInitializeChainsStep: 'Initialize and bind {{ .name }} base chains'
|
||||
FirewallRestoreRulesStep: 'Restore database rules to {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'Synchronize firewall port whitelist'
|
||||
FirewallEnableForwardingStep: 'Enable and bind port forwarding chains'
|
||||
FirewallRestoreForwardingRulesStep: 'Restore database port forwarding rules'
|
||||
FirewallInspectDockerGuardStep: 'Inspect Docker firewall backend and policies'
|
||||
FirewallInitializeDockerGuardStep: 'Initialize and bind {{ .name }} port guard chains'
|
||||
FirewallPersistDockerGuardStep: 'Persist Docker port guard status'
|
||||
FirewallTargetRuleIneffective: 'The target rule is no longer effective'
|
||||
FirewallVerifyRuleFailed: 'Failed to verify synchronized rule {{ .name }}: {{ .detail }}'
|
||||
TaskSync: 'Sync'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: 'La aplicación {{ .name }} no es compatible con la ver
|
||||
ErrDockerFailed: 'El estado de Docker es anómalo, revise el servicio'
|
||||
ErrDockerIptablesChainUnavailable: 'No se encontró la cadena DOCKER-USER de Docker. Reinicie Docker y vuelva a intentarlo'
|
||||
ErrDockerNftablesChainUnavailable: 'No se encontró la cadena de firewall IPv4 de nftables de Docker. Compruebe que la versión actual de Docker admita el backend de firewall nftables, reinicie Docker y vuelva a intentarlo'
|
||||
ErrUFWRuleAdopt: 'No se pudo administrar la regla UFW: {{ .detail }}. Si la versión actual de UFW es anterior a 0.35, actualice UFW y vuelva a intentarlo'
|
||||
ErrDockerComposeCmdNotFound: 'El comando Docker Compose no existe instálelo primero en el host'
|
||||
UseExistImage: 'La imagen ya existe, usando imagen existente'
|
||||
UpgradePrepare: 'Preparar actualización de la aplicación'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: 'No se pudieron sincronizar {{ .failed }} reglas
|
||||
FirewallResetSourceStep: 'Restablecer y desactivar el firewall de origen {{ .name }}'
|
||||
FirewallResetSourceResult: 'Firewall de origen restablecido; se eliminaron {{ .removed }} reglas de la base de datos'
|
||||
FirewallVerifyTargetStep: 'Verificar las reglas del firewall de destino'
|
||||
FirewallInitializeChainsStep: 'Inicializar y vincular las cadenas base de {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'Restaurar las reglas de la base de datos en {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'Sincronizar la lista de puertos permitidos del firewall'
|
||||
FirewallEnableForwardingStep: 'Habilitar y vincular las cadenas de reenvío de puertos'
|
||||
FirewallRestoreForwardingRulesStep: 'Restaurar las reglas de reenvío de puertos de la base de datos'
|
||||
FirewallInspectDockerGuardStep: 'Inspeccionar el backend del firewall de Docker y las políticas'
|
||||
FirewallInitializeDockerGuardStep: 'Inicializar y vincular las cadenas de protección de puertos de {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'Guardar el estado de protección de puertos de Docker'
|
||||
FirewallTargetRuleIneffective: 'La regla de destino ya no es efectiva'
|
||||
FirewallVerifyRuleFailed: 'No se pudo verificar la regla sincronizada {{ .name }}: {{ .detail }}'
|
||||
TaskSync: 'Sincronizar'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: "برنامه {{ .name }} با نسخه فعلی 1Panel
|
||||
ErrDockerFailed: 'Docker غیرعادی است؛ وضعیت سرویس را بررسی کنید'
|
||||
ErrDockerIptablesChainUnavailable: 'زنجیره DOCKER-USER داکر یافت نشد. داکر را راهاندازی مجدد کنید و دوباره تلاش کنید'
|
||||
ErrDockerNftablesChainUnavailable: 'زنجیره فایروال IPv4 مربوط به nftables داکر یافت نشد. بررسی کنید نسخه فعلی داکر از بکاند فایروال nftables پشتیبانی کند، سپس داکر را راهاندازی مجدد کرده و دوباره تلاش کنید'
|
||||
ErrUFWRuleAdopt: 'مدیریت قانون UFW ناموفق بود: {{ .detail }}. اگر نسخه فعلی UFW قدیمیتر از 0.35 است، ابتدا UFW را ارتقا دهید و دوباره تلاش کنید'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose روی میزبان یافت نشد'
|
||||
UseExistImage: 'تصویر وجود دارد؛ استفاده از تصویر موجود'
|
||||
UpgradePrepare: 'آمادهسازی ارتقاء برنامه'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: 'همگامسازی {{ .failed }} قانون
|
||||
FirewallResetSourceStep: 'بازنشانی و غیرفعالکردن فایروال مبدأ {{ .name }}'
|
||||
FirewallResetSourceResult: 'فایروال مبدأ بازنشانی شد و {{ .removed }} قانون پایگاه داده حذف شد'
|
||||
FirewallVerifyTargetStep: 'بررسی قوانین فایروال مقصد'
|
||||
FirewallInitializeChainsStep: 'راهاندازی و اتصال زنجیرههای پایه {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'بازیابی قوانین پایگاه داده در {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'همگامسازی فهرست مجاز پورتهای فایروال'
|
||||
FirewallEnableForwardingStep: 'فعالسازی و اتصال زنجیرههای هدایت پورت'
|
||||
FirewallRestoreForwardingRulesStep: 'بازیابی قوانین هدایت پورت پایگاه داده'
|
||||
FirewallInspectDockerGuardStep: 'بررسی پشتیبان فایروال Docker و سیاستها'
|
||||
FirewallInitializeDockerGuardStep: 'راهاندازی و اتصال زنجیرههای محافظت پورت {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'ذخیره وضعیت محافظت پورت Docker'
|
||||
FirewallTargetRuleIneffective: 'قانون مقصد دیگر مؤثر نیست'
|
||||
FirewallVerifyRuleFailed: 'بررسی قانون همگامشده {{ .name }} ناموفق بود: {{ .detail }}'
|
||||
TaskSync: 'همگامسازی'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: '{{ .name }} アプリケーションは現在の 1Pane
|
||||
ErrDockerFailed: 'Docker の状態が異常です。サービス状態を確認してください'
|
||||
ErrDockerIptablesChainUnavailable: 'Docker の DOCKER-USER チェーンが見つかりません。Docker を再起動してから再試行してください'
|
||||
ErrDockerNftablesChainUnavailable: 'Docker の nftables IPv4 ファイアウォールチェーンが見つかりません。現在の Docker バージョンが nftables ファイアウォールバックエンドをサポートしていることを確認し、Docker を再起動してから再試行してください'
|
||||
ErrUFWRuleAdopt: 'UFW ルールの管理に失敗しました:{{ .detail }}。現在の UFW バージョンが 0.35 未満の場合は、UFW をアップグレードしてから再試行してください'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose コマンドは存在しません。ホストマシンにこのコマンドを先にインストールしてください'
|
||||
UseExistImage: 'イメージは既に存在します。既存のイメージを使用します'
|
||||
UpgradePrepare: 'アプリケーションのアップグレードを準備'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} 件のルールを同期できな
|
||||
FirewallResetSourceStep: '移行元ファイアウォール {{ .name }} をリセットして無効化'
|
||||
FirewallResetSourceResult: '移行元ファイアウォールをリセットし、データベースルール {{ .removed }} 件を削除しました'
|
||||
FirewallVerifyTargetStep: '移行先ファイアウォールルールを検証'
|
||||
FirewallInitializeChainsStep: '{{ .name }} のベースチェーンを初期化してバインド'
|
||||
FirewallRestoreRulesStep: 'データベースルールを {{ .name }} に復元'
|
||||
FirewallSyncWhitelistStep: 'ファイアウォールポート許可リストを同期'
|
||||
FirewallEnableForwardingStep: 'ポート転送チェーンを有効化してバインド'
|
||||
FirewallRestoreForwardingRulesStep: 'データベースのポート転送ルールを復元'
|
||||
FirewallInspectDockerGuardStep: 'Docker ファイアウォールバックエンドと保護ポリシーを確認'
|
||||
FirewallInitializeDockerGuardStep: '{{ .name }} のポート保護チェーンを初期化してバインド'
|
||||
FirewallPersistDockerGuardStep: 'Docker ポート保護状態を保存'
|
||||
FirewallTargetRuleIneffective: '移行先ルールは有効ではありません'
|
||||
FirewallVerifyRuleFailed: '同期ルール {{ .name }} の検証に失敗しました:{{ .detail }}'
|
||||
TaskSync: '同期'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: '{{ .name }} 응용 프로그램은 현재 1Panel 버
|
||||
ErrDockerFailed: 'Docker의 상태가 비정상입니다. 서비스 상태를 확인하세요'
|
||||
ErrDockerIptablesChainUnavailable: 'Docker DOCKER-USER 체인을 찾을 수 없습니다. Docker를 다시 시작한 후 재시도하세요'
|
||||
ErrDockerNftablesChainUnavailable: 'Docker nftables IPv4 방화벽 체인을 찾을 수 없습니다. 현재 Docker 버전이 nftables 방화벽 백엔드를 지원하는지 확인하고 Docker를 다시 시작한 후 재시도하세요'
|
||||
ErrUFWRuleAdopt: 'UFW 규칙 관리에 실패했습니다: {{ .detail }}. 현재 UFW 버전이 0.35 미만이면 UFW를 업그레이드한 후 다시 시도하세요'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose 명령이 없습니다. 호스트 머신에 먼저 이 명령을 설치하세요'
|
||||
UseExistImage: '이미지가 이미 존재하여 기존 이미지를 사용합니다'
|
||||
UpgradePrepare: '애플리케이션 업그레이드 준비'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '규칙 {{ .failed }}개를 동기화하지 못
|
||||
FirewallResetSourceStep: '원본 방화벽 {{ .name }} 초기화 및 비활성화'
|
||||
FirewallResetSourceResult: '원본 방화벽을 초기화하고 데이터베이스 규칙 {{ .removed }}개를 삭제했습니다'
|
||||
FirewallVerifyTargetStep: '대상 방화벽 규칙 확인'
|
||||
FirewallInitializeChainsStep: '{{ .name }} 기본 체인 초기화 및 바인딩'
|
||||
FirewallRestoreRulesStep: '데이터베이스 규칙을 {{ .name }}에 복원'
|
||||
FirewallSyncWhitelistStep: '방화벽 포트 허용 목록 동기화'
|
||||
FirewallEnableForwardingStep: '포트 전달 체인 활성화 및 바인딩'
|
||||
FirewallRestoreForwardingRulesStep: '데이터베이스 포트 전달 규칙 복원'
|
||||
FirewallInspectDockerGuardStep: 'Docker 방화벽 백엔드 및 보호 정책 확인'
|
||||
FirewallInitializeDockerGuardStep: '{{ .name }} 포트 보호 체인 초기화 및 바인딩'
|
||||
FirewallPersistDockerGuardStep: 'Docker 포트 보호 상태 저장'
|
||||
FirewallTargetRuleIneffective: '대상 규칙이 더 이상 적용되지 않습니다'
|
||||
FirewallVerifyRuleFailed: '동기화된 규칙 {{ .name }} 확인 실패: {{ .detail }}'
|
||||
TaskSync: '동기화'
|
||||
|
||||
@@ -150,6 +150,7 @@ ErrAppVersionDeprecated: "ແອັບພລິເຄຊັນ {{ .name }} ບ
|
||||
ErrDockerFailed: 'Docker ຜິດປົກກະຕິ; ກະລຸນາກວດສອບສະຖານະການບໍລິການ'
|
||||
ErrDockerIptablesChainUnavailable: 'ບໍ່ພົບ chain DOCKER-USER ຂອງ Docker. ກະລຸນາເລີ່ມ Docker ໃໝ່ແລ້ວລອງອີກຄັ້ງ'
|
||||
ErrDockerNftablesChainUnavailable: 'ບໍ່ພົບ chain ໄຟວໍ nftables IPv4 ຂອງ Docker. ກະລຸນາກວດສອບວ່າ Docker ລຸ້ນປັດຈຸບັນຮອງຮັບ backend ໄຟວໍ nftables, ເລີ່ມ Docker ໃໝ່ແລ້ວລອງອີກຄັ້ງ'
|
||||
ErrUFWRuleAdopt: 'ຈັດການກົດ UFW ບໍ່ສຳເລັດ: {{ .detail }}. ຖ້າ UFW ລຸ້ນປັດຈຸບັນຕ່ຳກວ່າ 0.35, ກະລຸນາອັບເກຣດ UFW ແລ້ວລອງໃໝ່'
|
||||
ErrDockerComposeCmdNotFound: 'ບໍ່ພົບຄຳສັ່ງ Docker Compose ໃນເຄື່ອງ'
|
||||
UseExistImage: 'ມີຮູບພາບຢູ່ແລ້ວ; ກຳລັງໃຊ້ຮູບພາບທີ່ມີຢູ່'
|
||||
UpgradePrepare: 'ກະກຽມອັບເກຣດແອັບ'
|
||||
@@ -502,6 +503,14 @@ FirewallSyncFailedResetSkipped: 'ຊິງຄ໌ກົດ {{ .failed }} ລາ
|
||||
FirewallResetSourceStep: 'ຣີເຊັດ ແລະ ປິດໃຊ້ໄຟວອລຕົ້ນທາງ {{ .name }}'
|
||||
FirewallResetSourceResult: 'ຣີເຊັດໄຟວອລຕົ້ນທາງແລ້ວ ແລະ ລຶບກົດຖານຂໍ້ມູນ {{ .removed }} ລາຍການ'
|
||||
FirewallVerifyTargetStep: 'ກວດສອບກົດໄຟວອລປາຍທາງ'
|
||||
FirewallInitializeChainsStep: 'ເລີ່ມຕົ້ນ ແລະ ຜູກ chain ພື້ນຖານ {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'ກູ້ຄືນກົດຖານຂໍ້ມູນໄປຫາ {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'ຊິງຄ໌ລາຍການພອດໄຟວໍທີ່ອະນຸຍາດ'
|
||||
FirewallEnableForwardingStep: 'ເປີດໃຊ້ ແລະ ຜູກ chain ສົ່ງຕໍ່ພອດ'
|
||||
FirewallRestoreForwardingRulesStep: 'ກູ້ຄືນກົດສົ່ງຕໍ່ພອດຈາກຖານຂໍ້ມູນ'
|
||||
FirewallInspectDockerGuardStep: 'ກວດສອບ backend firewall Docker ແລະ ນະໂຍບາຍ'
|
||||
FirewallInitializeDockerGuardStep: 'ເລີ່ມຕົ້ນ ແລະ ຜູກ chain ປ້ອງກັນພອດ {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'ບັນທຶກສະຖານະປ້ອງກັນພອດ Docker'
|
||||
FirewallTargetRuleIneffective: 'ກົດປາຍທາງບໍ່ມີຜົນແລ້ວ'
|
||||
FirewallVerifyRuleFailed: 'ກວດສອບກົດທີ່ຊິງຄ໌ {{ .name }} ບໍ່ສຳເລັດ: {{ .detail }}'
|
||||
TaskSync: 'ຊິງຄ໌'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: 'Aplikasi {{ .name }} tidak sesuai dengan versi 1Panel
|
||||
ErrDockerFailed: 'Keadaan Docker tidak normal, sila periksa status perkhidmatan'
|
||||
ErrDockerIptablesChainUnavailable: 'Rantaian DOCKER-USER Docker tidak ditemui. Mulakan semula Docker dan cuba lagi'
|
||||
ErrDockerNftablesChainUnavailable: 'Rantaian firewall IPv4 nftables Docker tidak ditemui. Pastikan versi Docker semasa menyokong bahagian belakang firewall nftables, mulakan semula Docker dan cuba lagi'
|
||||
ErrUFWRuleAdopt: 'Gagal mengurus peraturan UFW: {{ .detail }}. Jika versi UFW semasa lebih lama daripada 0.35, tingkatkan UFW dan cuba lagi'
|
||||
ErrDockerComposeCmdNotFound: 'Perintah Docker Compose tidak wujud, sila pasang perintah ini di mesin tuan terlebih dahulu'
|
||||
UseExistImage: 'Imej sudah wujud, menggunakan imej sedia ada'
|
||||
UpgradePrepare: 'Sediakan naik taraf aplikasi'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} peraturan gagal disegerakkan; fir
|
||||
FirewallResetSourceStep: 'Tetapkan semula dan nyahdayakan firewall sumber {{ .name }}'
|
||||
FirewallResetSourceResult: 'Firewall sumber ditetapkan semula; {{ .removed }} peraturan pangkalan data dipadamkan'
|
||||
FirewallVerifyTargetStep: 'Sahkan peraturan firewall sasaran'
|
||||
FirewallInitializeChainsStep: 'Mulakan dan ikat rantai asas {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'Pulihkan peraturan pangkalan data ke {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'Segerakkan senarai putih port firewall'
|
||||
FirewallEnableForwardingStep: 'Aktifkan dan ikat rantai pemajuan port'
|
||||
FirewallRestoreForwardingRulesStep: 'Pulihkan peraturan pemajuan port pangkalan data'
|
||||
FirewallInspectDockerGuardStep: 'Periksa backend firewall Docker dan polisi'
|
||||
FirewallInitializeDockerGuardStep: 'Mulakan dan ikat rantai perlindungan port {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'Simpan status perlindungan port Docker'
|
||||
FirewallTargetRuleIneffective: 'Peraturan sasaran tidak lagi berkesan'
|
||||
FirewallVerifyRuleFailed: 'Gagal mengesahkan peraturan disegerakkan {{ .name }}: {{ .detail }}'
|
||||
TaskSync: 'Segerakkan'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: 'O aplicativo {{ .name }} não é compatível com a ver
|
||||
ErrDockerFailed: 'O estado do Docker está anormal, verifique o status do serviço'
|
||||
ErrDockerIptablesChainUnavailable: 'A cadeia DOCKER-USER do Docker não foi encontrada. Reinicie o Docker e tente novamente'
|
||||
ErrDockerNftablesChainUnavailable: 'A cadeia de firewall IPv4 do nftables do Docker não foi encontrada. Confirme se a versão atual do Docker oferece suporte ao backend de firewall nftables, reinicie o Docker e tente novamente'
|
||||
ErrUFWRuleAdopt: 'Falha ao gerenciar a regra UFW: {{ .detail }}. Se a versão atual do UFW for anterior à 0.35, atualize o UFW e tente novamente'
|
||||
ErrDockerComposeCmdNotFound: 'O comando Docker Compose não existe, instale este comando na máquina host primeiro'
|
||||
UseExistImage: 'A imagem já existe, usando imagem existente'
|
||||
UpgradePrepare: 'Preparar atualização do aplicativo'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} regras falharam na sincronizaçã
|
||||
FirewallResetSourceStep: 'Redefinir e desativar o firewall de origem {{ .name }}'
|
||||
FirewallResetSourceResult: 'Firewall de origem redefinido; {{ .removed }} regras do banco de dados foram excluídas'
|
||||
FirewallVerifyTargetStep: 'Verificar regras do firewall de destino'
|
||||
FirewallInitializeChainsStep: 'Inicializar e vincular as cadeias base do {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'Restaurar regras do banco de dados para {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'Sincronizar a lista de portas permitidas do firewall'
|
||||
FirewallEnableForwardingStep: 'Habilitar e vincular as cadeias de encaminhamento de portas'
|
||||
FirewallRestoreForwardingRulesStep: 'Restaurar regras de encaminhamento de portas do banco de dados'
|
||||
FirewallInspectDockerGuardStep: 'Inspecionar o backend do firewall Docker e as políticas'
|
||||
FirewallInitializeDockerGuardStep: 'Inicializar e vincular as cadeias de proteção de portas do {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'Salvar o status da proteção de portas do Docker'
|
||||
FirewallTargetRuleIneffective: 'A regra de destino não está mais efetiva'
|
||||
FirewallVerifyRuleFailed: 'Falha ao verificar a regra sincronizada {{ .name }}: {{ .detail }}'
|
||||
TaskSync: 'Sincronizar'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: 'Приложение {{ .name }} несовмести
|
||||
ErrDockerFailed: 'Состояние Docker аномально, проверьте состояние сервиса'
|
||||
ErrDockerIptablesChainUnavailable: 'Цепочка Docker DOCKER-USER не найдена. Перезапустите Docker и повторите попытку'
|
||||
ErrDockerNftablesChainUnavailable: 'Цепочка IPv4 брандмауэра nftables Docker не найдена. Убедитесь, что текущая версия Docker поддерживает бэкенд брандмауэра nftables, перезапустите Docker и повторите попытку'
|
||||
ErrUFWRuleAdopt: 'Не удалось принять правило UFW под управление: {{ .detail }}. Если текущая версия UFW ниже 0.35, обновите UFW и повторите попытку'
|
||||
ErrDockerComposeCmdNotFound: 'Команда Docker Compose отсутствует, пожалуйста, установите эту команду на хост-машине сначала'
|
||||
UseExistImage: 'Образ уже существует, используется существующий образ'
|
||||
UpgradePrepare: 'Подготовка обновления приложения'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: 'Не удалось синхронизиров
|
||||
FirewallResetSourceStep: 'Сбросить и отключить исходный межсетевой экран {{ .name }}'
|
||||
FirewallResetSourceResult: 'Исходный межсетевой экран сброшен; удалено правил из базы данных: {{ .removed }}'
|
||||
FirewallVerifyTargetStep: 'Проверить правила целевого межсетевого экрана'
|
||||
FirewallInitializeChainsStep: 'Инициализировать и привязать базовые цепочки {{ .name }}'
|
||||
FirewallRestoreRulesStep: 'Восстановить правила базы данных в {{ .name }}'
|
||||
FirewallSyncWhitelistStep: 'Синхронизировать белый список портов межсетевого экрана'
|
||||
FirewallEnableForwardingStep: 'Включить и привязать цепочки перенаправления портов'
|
||||
FirewallRestoreForwardingRulesStep: 'Восстановить правила перенаправления портов из базы данных'
|
||||
FirewallInspectDockerGuardStep: 'Проверить бэкенд межсетевого экрана Docker и политики'
|
||||
FirewallInitializeDockerGuardStep: 'Инициализировать и привязать цепочки защиты портов {{ .name }}'
|
||||
FirewallPersistDockerGuardStep: 'Сохранить состояние защиты портов Docker'
|
||||
FirewallTargetRuleIneffective: 'Целевое правило больше не действует'
|
||||
FirewallVerifyRuleFailed: 'Не удалось проверить синхронизированное правило {{ .name }}: {{ .detail }}'
|
||||
TaskSync: 'Синхронизировать'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: '{{ .name }} uygulaması mevcut 1Panel sürümü ile uy
|
||||
ErrDockerFailed: 'Docker durumu anormal, lütfen servis durumunu kontrol edin'
|
||||
ErrDockerIptablesChainUnavailable: 'Docker DOCKER-USER zinciri bulunamadı. Docker’ı yeniden başlatıp tekrar deneyin'
|
||||
ErrDockerNftablesChainUnavailable: 'Docker nftables IPv4 güvenlik duvarı zinciri bulunamadı. Geçerli Docker sürümünün nftables güvenlik duvarı arka ucunu desteklediğini doğrulayın, Docker’ı yeniden başlatıp tekrar deneyin'
|
||||
ErrUFWRuleAdopt: 'UFW kuralı yönetilemedi: {{ .detail }}. Geçerli UFW sürümü 0.35’ten eskiyse UFW’yi yükseltip tekrar deneyin'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose komutu mevcut değil, lütfen önce bu komutu host makinesine yükleyin'
|
||||
UseExistImage: 'Görüntü zaten mevcut, mevcut görüntü kullanılıyor'
|
||||
UpgradePrepare: 'Uygulama yükseltmesini hazırla'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} kural eşitlenemedi; kaynak güve
|
||||
FirewallResetSourceStep: 'Kaynak güvenlik duvarı {{ .name }} sıfırla ve devre dışı bırak'
|
||||
FirewallResetSourceResult: 'Kaynak güvenlik duvarı sıfırlandı; {{ .removed }} veritabanı kuralı silindi'
|
||||
FirewallVerifyTargetStep: 'Hedef güvenlik duvarı kurallarını doğrula'
|
||||
FirewallInitializeChainsStep: '{{ .name }} temel zincirlerini başlat ve bağla'
|
||||
FirewallRestoreRulesStep: 'Veritabanı kurallarını {{ .name }} üzerine geri yükle'
|
||||
FirewallSyncWhitelistStep: 'Güvenlik duvarı bağlantı noktası izin listesini eşitle'
|
||||
FirewallEnableForwardingStep: 'Bağlantı noktası yönlendirme zincirlerini etkinleştir ve bağla'
|
||||
FirewallRestoreForwardingRulesStep: 'Veritabanı bağlantı noktası yönlendirme kurallarını geri yükle'
|
||||
FirewallInspectDockerGuardStep: 'Docker güvenlik duvarı arka ucunu ve ilkelerini denetle'
|
||||
FirewallInitializeDockerGuardStep: '{{ .name }} bağlantı noktası koruma zincirlerini başlat ve bağla'
|
||||
FirewallPersistDockerGuardStep: 'Docker bağlantı noktası koruma durumunu kaydet'
|
||||
FirewallTargetRuleIneffective: 'Hedef kural artık etkili değil'
|
||||
FirewallVerifyRuleFailed: 'Eşitlenen {{ .name }} kuralı doğrulanamadı: {{ .detail }}'
|
||||
TaskSync: 'Senkronize Et'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: '{{ .name }} 應用不適配目前 1Panel 版本,跳
|
||||
ErrDockerFailed: 'Docker 狀態異常,請檢查服務狀態'
|
||||
ErrDockerIptablesChainUnavailable: '未偵測到 Docker 的 DOCKER-USER 鏈,請重新啟動 Docker 後再試'
|
||||
ErrDockerNftablesChainUnavailable: '未偵測到 Docker 的 nftables IPv4 防火牆鏈,請確認目前 Docker 版本支援 nftables 防火牆後端,重新啟動 Docker 後再試'
|
||||
ErrUFWRuleAdopt: 'UFW 規則納管失敗:{{ .detail }}。如果目前 UFW 版本低於 0.35,請先升級 UFW 後再試'
|
||||
ErrDockerComposeCmdNotFound: 'Docker Compose 指令不存在,請先在宿主機安裝此指令'
|
||||
UseExistImage: '映像已存在,使用現有映像'
|
||||
UpgradePrepare: '準備應用程式升級'
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: '{{ .failed }} 條防火牆規則同步失敗,
|
||||
FirewallResetSourceStep: '重設並停用來源防火牆 {{ .name }}'
|
||||
FirewallResetSourceResult: '來源防火牆重設完成,已刪除 {{ .removed }} 條資料庫規則'
|
||||
FirewallVerifyTargetStep: '驗證目標防火牆規則'
|
||||
FirewallInitializeChainsStep: '初始化並綁定 {{ .name }} 基礎鏈'
|
||||
FirewallRestoreRulesStep: '恢復資料庫規則至 {{ .name }}'
|
||||
FirewallSyncWhitelistStep: '同步防火牆連接埠白名單'
|
||||
FirewallEnableForwardingStep: '啟用並綁定連接埠轉發鏈'
|
||||
FirewallRestoreForwardingRulesStep: '恢復資料庫連接埠轉發規則'
|
||||
FirewallInspectDockerGuardStep: '檢查 Docker 防火牆後端與防護策略'
|
||||
FirewallInitializeDockerGuardStep: '初始化並綁定 {{ .name }} 連接埠防護鏈'
|
||||
FirewallPersistDockerGuardStep: '儲存 Docker 連接埠防護狀態'
|
||||
FirewallTargetRuleIneffective: '目標規則已失效'
|
||||
FirewallVerifyRuleFailed: '驗證同步規則 {{ .name }} 失敗:{{ .detail }}'
|
||||
TaskSync: '同步'
|
||||
|
||||
@@ -160,6 +160,7 @@ ErrAppVersionDeprecated: "{{ .name }} 应用不适配当前 1Panel 版本,跳
|
||||
ErrDockerFailed: "Docker 状态异常,请检查服务状态"
|
||||
ErrDockerIptablesChainUnavailable: "未检测到 Docker 的 DOCKER-USER 链,请重启 Docker 后重试"
|
||||
ErrDockerNftablesChainUnavailable: "未检测到 Docker 的 nftables IPv4 防火墙链,请确认当前 Docker 版本支持 nftables 防火墙后端,重启 Docker 后重试"
|
||||
ErrUFWRuleAdopt: "UFW 规则纳管失败:{{ .detail }}。如果当前 UFW 版本低于 0.35,请先升级 UFW 后重试"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,请先在宿主机安装"
|
||||
UseExistImage: "镜像已存在,使用存量镜像"
|
||||
UpgradePrepare: "准备应用升级"
|
||||
@@ -512,6 +513,14 @@ FirewallSyncFailedResetSkipped: "{{ .failed }} 条防火墙规则同步失败,
|
||||
FirewallResetSourceStep: "重置并停用源防火墙 {{ .name }}"
|
||||
FirewallResetSourceResult: "源防火墙重置完成,已删除 {{ .removed }} 条数据库规则"
|
||||
FirewallVerifyTargetStep: "验证目标防火墙规则"
|
||||
FirewallInitializeChainsStep: "初始化并绑定 {{ .name }} 基础链"
|
||||
FirewallRestoreRulesStep: "恢复数据库规则到 {{ .name }}"
|
||||
FirewallSyncWhitelistStep: "同步防火墙端口白名单"
|
||||
FirewallEnableForwardingStep: "启用并绑定端口转发链"
|
||||
FirewallRestoreForwardingRulesStep: "恢复数据库端口转发规则"
|
||||
FirewallInspectDockerGuardStep: "检查 Docker 防火墙后端和防护策略"
|
||||
FirewallInitializeDockerGuardStep: "初始化并绑定 {{ .name }} 端口防护链"
|
||||
FirewallPersistDockerGuardStep: "保存 Docker 端口防护状态"
|
||||
FirewallTargetRuleIneffective: "目标规则已失效"
|
||||
FirewallVerifyRuleFailed: "验证同步规则 {{ .name }} 失败:{{ .detail }}"
|
||||
TaskSync: "同步"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const maxCommandDiagnosticInput = 16 * 1024
|
||||
|
||||
// WrapBatchCommandError keeps successful task logs compact while making failed
|
||||
// generated firewall batches directly diagnosable from the task log.
|
||||
func WrapBatchCommandError(command, input string, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("command=%s failed: %w\nbatch input:\n%s", command, err, numberedCommandInput(input))
|
||||
}
|
||||
|
||||
func numberedCommandInput(input string) string {
|
||||
input = strings.TrimSpace(input)
|
||||
truncated := false
|
||||
if len(input) > maxCommandDiagnosticInput {
|
||||
input = input[:maxCommandDiagnosticInput]
|
||||
truncated = true
|
||||
}
|
||||
lines := strings.Split(input, "\n")
|
||||
var result strings.Builder
|
||||
for index, line := range lines {
|
||||
fmt.Fprintf(&result, "%04d %s\n", index+1, line)
|
||||
}
|
||||
if truncated {
|
||||
result.WriteString("... batch input truncated ...\n")
|
||||
}
|
||||
return strings.TrimRight(result.String(), "\n")
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
firewallutil "github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/nftables_helper"
|
||||
)
|
||||
@@ -79,7 +80,11 @@ type commandRunner struct{}
|
||||
func (commandRunner) Run(executable string, args ...string) (string, error) {
|
||||
executable = dockerGuardExecutable(executable)
|
||||
manager := cmd.NewCommandMgr(cmd.WithTimeout(60 * time.Second))
|
||||
return manager.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
stdout, err := manager.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
if err != nil {
|
||||
return stdout, fmt.Errorf("command=%s %s failed: %w", executable, strings.Join(args, " "), err)
|
||||
}
|
||||
return stdout, nil
|
||||
}
|
||||
|
||||
func (commandRunner) RunInput(executable, input string, args ...string) (string, error) {
|
||||
@@ -88,7 +93,8 @@ func (commandRunner) RunInput(executable, input string, args ...string) (string,
|
||||
return "", nftables_helper.RunScript(input)
|
||||
}
|
||||
manager := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second), cmd.WithStdin(strings.NewReader(input)))
|
||||
return manager.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
stdout, err := manager.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
return stdout, firewallutil.WrapBatchCommandError(executable+" "+strings.Join(args, " "), input, err)
|
||||
}
|
||||
|
||||
func (commandRunner) Exists(executable string) bool {
|
||||
|
||||
@@ -401,6 +401,9 @@ func nftHasFirstUniqueJump(output string) bool {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 || fields[0] == "table" || fields[0] == "chain" {
|
||||
continue
|
||||
}
|
||||
return len(fields) >= 2 && fields[0] == "jump" && fields[1] == NftChain
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -542,7 +542,7 @@ type systemBackend struct{}
|
||||
|
||||
func (systemBackend) ListChain(ctx context.Context, scope filter.Scope) (string, error) {
|
||||
return cmd.NewCommandMgr(cmd.WithContext(ctx), cmd.WithTimeout(60*time.Second)).RunWithOptionalSudoAndStdout(
|
||||
"nft", "-n", "-a", "list", "chain", nftables_helper.TableFamily(scope.Family), nftables_helper.TableName, nativeChainName(scope),
|
||||
"nft", "-n", "-n", "-a", "list", "chain", nftables_helper.TableFamily(scope.Family), nftables_helper.TableName, nativeChainName(scope),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/re"
|
||||
@@ -164,24 +165,27 @@ func (a *Adapter) Apply(ctx context.Context, plan filter.BackendPlan) (filter.Ap
|
||||
if a.failedCommandApplied(ctx, plan.Rules[0], index) {
|
||||
executed = index + 1
|
||||
}
|
||||
return filter.ApplyResult{}, a.compensate(ctx, plan.Rules[0], executed, fmt.Errorf("execute UFW rule: %w", err))
|
||||
cause := ufwApplyError(plan.Rules[0], fmt.Errorf("execute UFW rule: %w", err))
|
||||
return filter.ApplyResult{}, a.compensate(ctx, plan.Rules[0], executed, cause)
|
||||
}
|
||||
executed = index + 1
|
||||
}
|
||||
verification, err := a.verify(ctx, plan)
|
||||
if err != nil {
|
||||
return filter.ApplyResult{}, a.compensate(ctx, plan.Rules[0], executed, fmt.Errorf("verify UFW rule: %w", err))
|
||||
cause := ufwApplyError(plan.Rules[0], fmt.Errorf("verify UFW rule: %w", err))
|
||||
return filter.ApplyResult{}, a.compensate(ctx, plan.Rules[0], executed, cause)
|
||||
}
|
||||
if !verification.Matched {
|
||||
cause := ufwApplyError(plan.Rules[0], fmt.Errorf(
|
||||
"ufw write verification failed for marker %q in scope %s",
|
||||
plan.Rules[0].Expected.Marker,
|
||||
plan.Scope.Key(),
|
||||
))
|
||||
return filter.ApplyResult{}, a.compensate(
|
||||
ctx,
|
||||
plan.Rules[0],
|
||||
executed,
|
||||
fmt.Errorf(
|
||||
"ufw write verification failed for marker %q in scope %s",
|
||||
plan.Rules[0].Expected.Marker,
|
||||
plan.Scope.Key(),
|
||||
),
|
||||
cause,
|
||||
)
|
||||
}
|
||||
return filter.ApplyResult{
|
||||
@@ -190,6 +194,13 @@ func (a *Adapter) Apply(ctx context.Context, plan filter.BackendPlan) (filter.Ap
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ufwApplyError(plan filter.NativeRulePlan, cause error) error {
|
||||
if plan.Operation == filter.ChangeAdopt {
|
||||
return buserr.WithDetail("ErrUFWRuleAdopt", cause.Error(), cause)
|
||||
}
|
||||
return cause
|
||||
}
|
||||
|
||||
func (a *Adapter) failedCommandApplied(ctx context.Context, plan filter.NativeRulePlan, commandIndex int) bool {
|
||||
snapshot, err := a.Observe(ctx, plan.Expected.Rule.Scope)
|
||||
if err != nil {
|
||||
@@ -197,8 +208,10 @@ func (a *Adapter) failedCommandApplied(ctx context.Context, plan filter.NativeRu
|
||||
}
|
||||
markerCount := countMarker(snapshot, plan.Expected.Marker)
|
||||
switch plan.Operation {
|
||||
case filter.ChangeCreate, filter.ChangeAdopt:
|
||||
case filter.ChangeCreate:
|
||||
return markerCount > 0
|
||||
case filter.ChangeAdopt:
|
||||
return plan.Previous == nil || !containsObservedRule(snapshot, *plan.Previous)
|
||||
case filter.ChangeUpdate:
|
||||
if commandIndex == 0 {
|
||||
return markerCount == 0
|
||||
@@ -307,14 +320,11 @@ func compileChange(snapshot filter.Snapshot, change filter.DesiredChange) (filte
|
||||
position = *target.Locator.Position
|
||||
plan.Previous = &target
|
||||
plan.Expected = observedForRule(normalized, marker, position)
|
||||
plan.Commands = []filter.NativeCommand{
|
||||
deletePositionCommand(position),
|
||||
insertCommand(position, normalized, marker),
|
||||
}
|
||||
plan.RollbackCommands = []filter.NativeCommand{
|
||||
insertCommand(position, target.Rule, observedComment(target)),
|
||||
deleteRuleCommand(normalized, marker),
|
||||
}
|
||||
// UFW updates the comment of an existing rule when the same rule is added
|
||||
// without insert/prepend. This keeps the rule active and in its original
|
||||
// position throughout adoption.
|
||||
plan.Commands = []filter.NativeCommand{commentCommand(normalized, marker)}
|
||||
plan.RollbackCommands = []filter.NativeCommand{commentCommand(target.Rule, observedComment(target))}
|
||||
case filter.ChangeUpdate:
|
||||
target, targetErr := validateMutationTarget(snapshot, change, normalized, marker, true)
|
||||
if targetErr != nil {
|
||||
@@ -655,6 +665,19 @@ func countMarker(snapshot filter.Snapshot, marker string) int {
|
||||
return count
|
||||
}
|
||||
|
||||
func containsObservedRule(snapshot filter.Snapshot, expected filter.ObservedRule) bool {
|
||||
for _, observed := range snapshot.Rules {
|
||||
if expected.Locator.Position != nil &&
|
||||
(observed.Locator.Position == nil || *observed.Locator.Position != *expected.Locator.Position) {
|
||||
continue
|
||||
}
|
||||
if observed.Marker == expected.Marker && filter.ObservedRuleMatchesExpected(observed, expected.Rule) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasScopeNotice(notices []filter.ScopeNotice, code filter.ScopeNoticeCode) bool {
|
||||
for _, notice := range notices {
|
||||
if notice.Code == code {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
firewallutil "github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/forwarding"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/iptables_helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle"
|
||||
@@ -63,7 +64,8 @@ func (systemIptablesBackend) Restore(family, input string) error {
|
||||
}
|
||||
}
|
||||
manager := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second), cmd.WithStdin(strings.NewReader(input)))
|
||||
return manager.RunWithOptionalSudo(executable, "--noflush", "--wait")
|
||||
err = manager.RunWithOptionalSudo(executable, "--noflush", "--wait")
|
||||
return firewallutil.WrapBatchCommandError(executable+" --noflush --wait", input, err)
|
||||
}
|
||||
|
||||
func (systemIptablesBackend) LoadRulesFromFile(table, chain, fileName string) error {
|
||||
|
||||
@@ -329,11 +329,19 @@ func nftForwardChain(logical string) string {
|
||||
}
|
||||
|
||||
func nftRun(args ...string) (string, error) {
|
||||
return cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudoAndStdout("nft", args...)
|
||||
stdout, err := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudoAndStdout("nft", args...)
|
||||
if err != nil {
|
||||
return stdout, fmt.Errorf("command=nft %s failed: %w", strings.Join(args, " "), err)
|
||||
}
|
||||
return stdout, nil
|
||||
}
|
||||
|
||||
func nftRunCommand(args ...string) error {
|
||||
return cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudo("nft", args...)
|
||||
err := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudo("nft", args...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("command=nft %s failed: %w", strings.Join(args, " "), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func nftRunCommands(commands [][]string) error {
|
||||
|
||||
@@ -54,7 +54,11 @@ func runTables(ctx context.Context, executable, tab string, ignoreExist1, withWa
|
||||
args = append(args, "-w")
|
||||
}
|
||||
args = append(args, ruleArgs...)
|
||||
return cmdMgr.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
stdout, err := cmdMgr.RunWithOptionalSudoAndStdout(executable, args...)
|
||||
if err != nil {
|
||||
return stdout, fmt.Errorf("command=%s %s failed: %w", executable, strings.Join(args, " "), err)
|
||||
}
|
||||
return stdout, nil
|
||||
}
|
||||
|
||||
func runIptables(ctx context.Context, tab string, ignoreExist1, withWait bool, ruleArgs ...string) (string, error) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
firewallutil "github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle"
|
||||
)
|
||||
|
||||
@@ -190,5 +191,6 @@ func loadRulesFromFile(executable, restoreExecutable, tab, chain, fileName strin
|
||||
|
||||
func restoreRules(executable, input string) error {
|
||||
manager := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second), cmd.WithStdin(strings.NewReader(input)))
|
||||
return manager.RunWithOptionalSudo(executable, "--noflush", "--wait")
|
||||
err := manager.RunWithOptionalSudo(executable, "--noflush", "--wait")
|
||||
return firewallutil.WrapBatchCommandError(executable+" --noflush --wait", input, err)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
firewallutil "github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
)
|
||||
|
||||
@@ -31,11 +32,19 @@ func BasicChains() []string {
|
||||
}
|
||||
|
||||
func run(args ...string) (string, error) {
|
||||
return cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudoAndStdout("nft", args...)
|
||||
stdout, err := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudoAndStdout("nft", args...)
|
||||
if err != nil {
|
||||
return stdout, fmt.Errorf("command=nft %s failed: %w", strings.Join(args, " "), err)
|
||||
}
|
||||
return stdout, nil
|
||||
}
|
||||
|
||||
func runCommand(args ...string) error {
|
||||
return cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudo("nft", args...)
|
||||
err := cmd.NewCommandMgr(cmd.WithTimeout(60*time.Second)).RunWithOptionalSudo("nft", args...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("command=nft %s failed: %w", strings.Join(args, " "), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runBatch(commands ...[]string) error {
|
||||
@@ -75,7 +84,7 @@ func runScriptFile(script string, run func(string) error) error {
|
||||
if err := file.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return run(name)
|
||||
return firewallutil.WrapBatchCommandError("nft -f <generated-batch>", script, run(name))
|
||||
}
|
||||
|
||||
func buildBatchScript(commands ...[]string) (string, error) {
|
||||
|
||||
@@ -18579,7 +18579,10 @@ const docTemplate = `{
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -18763,7 +18766,10 @@ const docTemplate = `{
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -18818,9 +18824,26 @@ const docTemplate = `{
|
||||
},
|
||||
"/hosts/firewall/forward/enable": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"in": "body",
|
||||
"name": "request",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FirewallInitializationTask"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -35619,6 +35642,10 @@ const docTemplate = `{
|
||||
"unbind"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -35882,6 +35909,10 @@ const docTemplate = `{
|
||||
"unbind-base"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -35890,6 +35921,17 @@ const docTemplate = `{
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FilterChainOperationResponse": {
|
||||
"properties": {
|
||||
"queued": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"taskID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallBackendFamilyStatus": {
|
||||
"properties": {
|
||||
"bound": {
|
||||
@@ -35988,6 +36030,15 @@ const docTemplate = `{
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallInitializationTask": {
|
||||
"properties": {
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallLifecycleOperation": {
|
||||
"properties": {
|
||||
"operation": {
|
||||
|
||||
@@ -18575,7 +18575,10 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -18759,7 +18762,10 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -18814,9 +18820,26 @@
|
||||
},
|
||||
"/hosts/firewall/forward/enable": {
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"in": "body",
|
||||
"name": "request",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FirewallInitializationTask"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.FilterChainOperationResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
@@ -35615,6 +35638,10 @@
|
||||
"unbind"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -35878,6 +35905,10 @@
|
||||
"unbind-base"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -35886,6 +35917,17 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FilterChainOperationResponse": {
|
||||
"properties": {
|
||||
"queued": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"taskID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallBackendFamilyStatus": {
|
||||
"properties": {
|
||||
"bound": {
|
||||
@@ -35984,6 +36026,15 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallInitializationTask": {
|
||||
"properties": {
|
||||
"taskID": {
|
||||
"maxLength": 64,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"dto.FirewallLifecycleOperation": {
|
||||
"properties": {
|
||||
"operation": {
|
||||
|
||||
@@ -40,6 +40,10 @@ export namespace Firewall {
|
||||
backend: Provider;
|
||||
operation: BackendOperation;
|
||||
}
|
||||
export interface FilterChainOperationResult {
|
||||
taskID?: string;
|
||||
queued?: boolean;
|
||||
}
|
||||
export interface FirewallBase {
|
||||
name: string;
|
||||
backend: string;
|
||||
|
||||
@@ -18,10 +18,19 @@ export const operateFire = (operation: string, withDockerRestart: boolean) =>
|
||||
export const operateForwardRule = (request: { rules: Firewall.RuleForward[]; forceDelete?: boolean }) =>
|
||||
http.post('/hosts/firewall/forward/operate', request, TimeoutEnum.T_40S);
|
||||
|
||||
export const enableForwarding = () => http.post('/hosts/firewall/forward/enable', {}, TimeoutEnum.T_60S);
|
||||
export const enableForwarding = (taskID?: string) =>
|
||||
http.post<Firewall.FilterChainOperationResult>(
|
||||
'/hosts/firewall/forward/enable',
|
||||
taskID ? { taskID } : {},
|
||||
TimeoutEnum.T_60S,
|
||||
);
|
||||
|
||||
export const operateFilterChain = (name: string, operate: string) =>
|
||||
http.post('/hosts/firewall/filter/operate', { name, operate }, TimeoutEnum.T_60S);
|
||||
export const operateFilterChain = (name: string, operate: string, taskID?: string) =>
|
||||
http.post<Firewall.FilterChainOperationResult>(
|
||||
'/hosts/firewall/filter/operate',
|
||||
{ name, operate, ...(taskID ? { taskID } : {}) },
|
||||
TimeoutEnum.T_60S,
|
||||
);
|
||||
|
||||
export const searchFirewallRules = (request: Firewall.InventoryRequest) => {
|
||||
return http.post<Firewall.Inventory>('/hosts/firewall/rules/search', request, TimeoutEnum.T_40S);
|
||||
@@ -83,10 +92,10 @@ export const syncDockerPortGuard = () =>
|
||||
},
|
||||
);
|
||||
|
||||
export const operateDockerPortGuard = (operation: 'initialize' | 'bind' | 'unbind') =>
|
||||
http.postWithConfig(
|
||||
export const operateDockerPortGuard = (operation: 'initialize' | 'bind' | 'unbind', taskID?: string) =>
|
||||
http.postWithConfig<Firewall.FilterChainOperationResult>(
|
||||
'/hosts/firewall/docker/operate',
|
||||
{ operation },
|
||||
{ operation, ...(taskID ? { taskID } : {}) },
|
||||
{
|
||||
timeout: TimeoutEnum.T_60S,
|
||||
skipErrorMessage: true,
|
||||
|
||||
@@ -88,6 +88,12 @@
|
||||
<span class="port-card-value">{{ group.endpoint.description || '-' }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-if="group.endpoint.policyUUID && !group.endpoint.effective" class="port-card-field">
|
||||
<span class="port-card-label">{{ $t('commons.table.message') }}</span>
|
||||
<el-tooltip :content="statusMessage(group.endpoint)" placement="top" :show-after="400">
|
||||
<span class="port-card-value is-warning">{{ statusMessage(group.endpoint) }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -159,10 +165,10 @@ import { deleteDockerPortGuardPolicies, upsertDockerPortGuardPolicies } from '@/
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
|
||||
import { isValidDockerGuardSource } from '@/views/host/firewall/docker/model';
|
||||
import { dockerGuardEndpointStatusMessage, isValidDockerGuardSource } from '@/views/host/firewall/docker/model';
|
||||
import { formatHostAddress, formatHostAddressList, splitTagValues } from '@/views/host/firewall/utils/validation';
|
||||
|
||||
const props = defineProps<{ containers: Firewall.DockerGuardContainer[] }>();
|
||||
const props = defineProps<{ base: Firewall.DockerGuardBase; containers: Firewall.DockerGuardContainer[] }>();
|
||||
const emit = defineEmits<{ search: [] }>();
|
||||
|
||||
const drawerVisible = ref(false);
|
||||
@@ -225,6 +231,8 @@ const selectedPolicyUUIDs = computed(() => policyUUIDs(selectedEndpoints.value))
|
||||
const sourcesLabel = computed(() =>
|
||||
form.mode === 'allow_sources' ? i18n.global.t('firewall.allowedSources') : i18n.global.t('firewall.deniedSources'),
|
||||
);
|
||||
const statusMessage = (endpoint: Firewall.DockerGuardEndpoint) =>
|
||||
dockerGuardEndpointStatusMessage(props.base, endpoint);
|
||||
type ValidationCallback = (error?: Error) => void;
|
||||
const validateSources = (_rule: unknown, value: string[], callback: ValidationCallback) => {
|
||||
const sources = splitTagValues(value || []);
|
||||
@@ -471,6 +479,10 @@ defineExpose({ acceptParams, openPolicy });
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.port-card-value.is-warning {
|
||||
color: var(--el-color-warning);
|
||||
}
|
||||
|
||||
.port-card-actions {
|
||||
display: flex;
|
||||
flex: none;
|
||||
|
||||
@@ -105,13 +105,21 @@
|
||||
v-if="group.endpoint.policyUUID"
|
||||
:label="$t('commons.table.status')"
|
||||
>
|
||||
{{
|
||||
$t(
|
||||
group.endpoint.effective
|
||||
? 'firewall.effective'
|
||||
: 'firewall.notEffective',
|
||||
)
|
||||
}}
|
||||
<div>
|
||||
{{
|
||||
$t(
|
||||
group.endpoint.effective
|
||||
? 'firewall.effective'
|
||||
: 'firewall.notEffective',
|
||||
)
|
||||
}}
|
||||
<div
|
||||
v-if="!group.endpoint.effective"
|
||||
class="docker-guard-status-message"
|
||||
>
|
||||
{{ endpointStatusMessage(group.endpoint) }}
|
||||
</div>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item
|
||||
v-if="group.endpoint.description"
|
||||
@@ -200,10 +208,11 @@
|
||||
</template>
|
||||
</DrawerPro>
|
||||
|
||||
<DockerGuardDetail ref="detailRef" :containers="containerRows" @search="search" />
|
||||
<DockerGuardDetail ref="detailRef" :base="data.base" :containers="containerRows" @search="search" />
|
||||
<DockerGuardImport ref="importRef" @search="search" />
|
||||
<RuleSync ref="ruleSyncRef" @search="search" />
|
||||
<ConfirmDialog ref="cleanupConfirmRef" @confirm="submitCleanupBackend" />
|
||||
<TaskLog ref="taskLogRef" @close="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -215,6 +224,7 @@ import DockerGuardDetail from '@/views/host/firewall/docker/detail/index.vue';
|
||||
import DockerGuardImport from '@/views/host/firewall/docker/import/index.vue';
|
||||
import RuleSync from '@/views/host/firewall/sync/index.vue';
|
||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { Firewall } from '@/api/interface/firewall';
|
||||
import {
|
||||
deleteDockerPortGuardPolicies,
|
||||
@@ -228,14 +238,16 @@ import { ElMessageBox } from 'element-plus';
|
||||
import { Lock } from '@element-plus/icons-vue';
|
||||
import { downloadWithContent } from '@/utils/file';
|
||||
import { getCurrentDateFormatted } from '@/utils/date';
|
||||
import { dockerGuardEndpointKey } from '@/views/host/firewall/docker/model';
|
||||
import { dockerGuardEndpointKey, dockerGuardEndpointStatusMessage } from '@/views/host/firewall/docker/model';
|
||||
import { formatHostAddressList } from '@/views/host/firewall/utils/validation';
|
||||
import { newUUID } from '@/utils/id';
|
||||
|
||||
const loading = ref(false);
|
||||
const detailRef = ref<InstanceType<typeof DockerGuardDetail>>();
|
||||
const importRef = ref<InstanceType<typeof DockerGuardImport>>();
|
||||
const ruleSyncRef = ref<InstanceType<typeof RuleSync>>();
|
||||
const cleanupConfirmRef = ref<InstanceType<typeof ConfirmDialog>>();
|
||||
const taskLogRef = ref<InstanceType<typeof TaskLog>>();
|
||||
const orphanDrawerVisible = ref(false);
|
||||
const searchName = ref('');
|
||||
const selects = ref<Firewall.DockerGuardContainer[]>([]);
|
||||
@@ -387,6 +399,8 @@ const endpointLabel = (endpoint: Firewall.DockerGuardEndpoint) => {
|
||||
};
|
||||
const displaySources = (endpoint: Firewall.DockerGuardEndpoint) =>
|
||||
formatHostAddressList(endpoint.sources, endpoint.family);
|
||||
const endpointStatusMessage = (endpoint: Firewall.DockerGuardEndpoint) =>
|
||||
dockerGuardEndpointStatusMessage(data.base, endpoint);
|
||||
|
||||
const search = async () => {
|
||||
loading.value = true;
|
||||
@@ -411,7 +425,12 @@ const operate = async (operation: 'initialize' | 'bind' | 'unbind') => {
|
||||
}
|
||||
}
|
||||
try {
|
||||
await operateDockerPortGuard(operation);
|
||||
const result = (await operateDockerPortGuard(operation, operation === 'initialize' ? newUUID() : undefined))
|
||||
.data;
|
||||
if (operation === 'initialize' && result.queued && result.taskID) {
|
||||
taskLogRef.value?.openWithTaskID(result.taskID, true);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
await search();
|
||||
return;
|
||||
@@ -523,4 +542,10 @@ search();
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.docker-guard-status-message {
|
||||
margin-top: 4px;
|
||||
color: var(--el-color-warning);
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Firewall } from '@/api/interface/firewall';
|
||||
import i18n from '@/lang';
|
||||
import { isValidAddressForFamily } from '@/views/host/firewall/utils/validation';
|
||||
|
||||
type DockerGuardEndpointIdentity = Pick<Firewall.DockerGuardEndpoint, 'family' | 'hostIP' | 'hostPort' | 'protocol'>;
|
||||
@@ -9,6 +10,34 @@ export const dockerGuardEndpointKey = (endpoint: DockerGuardEndpointIdentity): s
|
||||
export const isValidDockerGuardSource = (family: Firewall.DockerGuardEndpoint['family'], value: string): boolean =>
|
||||
isValidAddressForFamily(family, value);
|
||||
|
||||
export const dockerGuardFamilyStatusMessage = (
|
||||
base: Firewall.DockerGuardBase,
|
||||
family: 'IPv4' | 'IPv6',
|
||||
status: Firewall.DockerGuardFamilyStatus,
|
||||
): string => {
|
||||
if (status.reason) {
|
||||
return i18n.global.t(`firewall.dockerGuardStatusReason.${status.reason}`, [family]);
|
||||
}
|
||||
const state = i18n.global.t(
|
||||
!status.initialized
|
||||
? 'firewall.notInitialized'
|
||||
: !status.bound
|
||||
? 'commons.status.unbind'
|
||||
: 'firewall.notEffective',
|
||||
);
|
||||
const chainName = base.backend === 'nftables' ? 'NFT_1PANEL_DOCKER' : '1PANEL_DOCKER';
|
||||
return i18n.global.t('firewall.familyChainIssue', [family, chainName, state]);
|
||||
};
|
||||
|
||||
export const dockerGuardEndpointStatusMessage = (
|
||||
base: Firewall.DockerGuardBase,
|
||||
endpoint: Firewall.DockerGuardEndpoint,
|
||||
): string => {
|
||||
if (!endpoint.policyUUID || endpoint.effective) return '';
|
||||
const ipv6 = endpoint.family === 'ipv6';
|
||||
return dockerGuardFamilyStatusMessage(base, ipv6 ? 'IPv6' : 'IPv4', ipv6 ? base.ipv6 : base.ipv4);
|
||||
};
|
||||
|
||||
export const normalizeDockerGuardPolicy = (value: unknown): Firewall.DockerGuardPolicy | undefined => {
|
||||
if (!value || typeof value !== 'object') return;
|
||||
const policy = value as Partial<Firewall.DockerGuardPolicy>;
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Firewall } from '@/api/interface/firewall';
|
||||
import i18n from '@/lang';
|
||||
import NoSuchService from '@/components/layout-content/no-such-service.vue';
|
||||
import { WarningFilled } from '@element-plus/icons-vue';
|
||||
import { computed } from 'vue';
|
||||
import { routerToName, routerToNameWithQuery } from '@/utils/router';
|
||||
import { dockerGuardFamilyStatusMessage } from '@/views/host/firewall/docker/model';
|
||||
|
||||
const props = defineProps<{ base: Firewall.DockerGuardBase }>();
|
||||
const emit = defineEmits<{
|
||||
@@ -133,24 +133,8 @@ const retryableFamilyIssues = computed(() =>
|
||||
const familyRetryOperation = computed<'initialize' | 'bind'>(() =>
|
||||
retryableFamilyIssues.value.some((item) => !item.status.initialized) ? 'initialize' : 'bind',
|
||||
);
|
||||
const dockerChainName = computed(() => (props.base.backend === 'nftables' ? 'NFT_1PANEL_DOCKER' : '1PANEL_DOCKER'));
|
||||
const familyStatusText = (family: string, status: Firewall.DockerGuardFamilyStatus) => {
|
||||
if (
|
||||
status.reason === 'command_missing' ||
|
||||
status.reason === 'docker_chain_missing' ||
|
||||
status.reason === 'inspect_failed'
|
||||
) {
|
||||
return i18n.global.t(`firewall.dockerGuardStatusReason.${status.reason}`, [family]);
|
||||
}
|
||||
const state = i18n.global.t(
|
||||
!status.initialized
|
||||
? 'firewall.notInitialized'
|
||||
: !status.bound
|
||||
? 'commons.status.unbind'
|
||||
: 'firewall.notEffective',
|
||||
);
|
||||
return i18n.global.t('firewall.familyChainIssue', [family, dockerChainName.value, state]);
|
||||
};
|
||||
const familyStatusText = (family: 'IPv4' | 'IPv6', status: Firewall.DockerGuardFamilyStatus) =>
|
||||
dockerGuardFamilyStatusMessage(props.base, family, status);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -77,9 +77,15 @@
|
||||
<el-table-column :label="$t('commons.table.protocol')" :min-width="70" prop="protocol" />
|
||||
<el-table-column :label="$t('commons.table.status')" :min-width="90" prop="syncStatus">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="syncStatusType(row.syncStatus)">
|
||||
{{ syncStatusLabel(row.syncStatus) }}
|
||||
</el-tag>
|
||||
<el-tooltip
|
||||
:disabled="!syncStatusMessage(row.syncStatus)"
|
||||
:content="syncStatusMessage(row.syncStatus)"
|
||||
placement="top"
|
||||
>
|
||||
<el-tag :type="syncStatusType(row.syncStatus)">
|
||||
{{ syncStatusLabel(row.syncStatus) }}
|
||||
</el-tag>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('firewall.sourcePort')" :min-width="70" prop="port" />
|
||||
@@ -196,6 +202,11 @@ const syncStatusType = (status?: Firewall.RuleForward['syncStatus']) => {
|
||||
if (status === 'converged') return 'success';
|
||||
return status === 'runtime_only' ? 'warning' : 'danger';
|
||||
};
|
||||
const syncStatusMessage = (status?: Firewall.RuleForward['syncStatus']) => {
|
||||
if (status === 'missing') return i18n.global.t('firewall.ruleSyncReasonDetail.missingFromTarget');
|
||||
if (status === 'runtime_only') return i18n.global.t('firewall.ruleSyncReasonDetail.onlyInTarget');
|
||||
return '';
|
||||
};
|
||||
|
||||
const opRef = ref();
|
||||
const dialogImportRef = ref();
|
||||
|
||||
@@ -426,6 +426,35 @@ interface PriorityPositionRange {
|
||||
|
||||
type RuleFilter = 'family:ipv4' | 'family:ipv6' | 'action:accept' | 'action:deny' | `state:${Firewall.InventoryState}`;
|
||||
|
||||
const ruleFilterStorageKey = 'firewall-rule-filters';
|
||||
const chainFilterStorageKey = 'firewall-rule-visible-chains';
|
||||
const ruleFilterOptions: RuleFilter[] = [
|
||||
'family:ipv4',
|
||||
'family:ipv6',
|
||||
'action:accept',
|
||||
'action:deny',
|
||||
'state:managed',
|
||||
'state:adopted',
|
||||
'state:external',
|
||||
'state:protected',
|
||||
'state:drifted',
|
||||
];
|
||||
const iptablesChains = ['1PANEL_BASIC_BEFORE', '1PANEL_BASIC', '1PANEL_BASIC_AFTER'] as const;
|
||||
|
||||
const loadCachedFilterValues = <T extends string>(key: string, allowed: readonly T[], defaults: readonly T[]): T[] => {
|
||||
try {
|
||||
const cached = JSON.parse(localStorage.getItem(key) || 'null');
|
||||
if (!Array.isArray(cached)) return [...defaults];
|
||||
return cached.filter((item): item is T => typeof item === 'string' && allowed.includes(item as T));
|
||||
} catch {
|
||||
return [...defaults];
|
||||
}
|
||||
};
|
||||
|
||||
const cacheFilterValues = (key: string, values: readonly string[]) => {
|
||||
localStorage.setItem(key, JSON.stringify(values));
|
||||
};
|
||||
|
||||
const fireStatusRef = ref<InstanceType<typeof FireStatus>>();
|
||||
const ruleOperateRef = ref<InstanceType<typeof RuleOperate>>();
|
||||
const ruleImportRef = ref<InstanceType<typeof RuleImport>>();
|
||||
@@ -451,9 +480,10 @@ const showFirewallUnavailablePrompt = computed(
|
||||
() => (isDirectBackend.value && (!isInit.value || !isBind.value)) || (isServiceBackend.value && !isActive.value),
|
||||
);
|
||||
const firewallVersion = ref('');
|
||||
const selectedRuleFilters = ref<RuleFilter[]>([]);
|
||||
const iptablesChains = ['1PANEL_BASIC_BEFORE', '1PANEL_BASIC', '1PANEL_BASIC_AFTER'] as const;
|
||||
const visibleIptablesChains = ref<string[]>([...iptablesChains]);
|
||||
const selectedRuleFilters = ref<RuleFilter[]>(loadCachedFilterValues(ruleFilterStorageKey, ruleFilterOptions, []));
|
||||
const visibleIptablesChains = ref<string[]>(
|
||||
loadCachedFilterValues(chainFilterStorageKey, iptablesChains, iptablesChains),
|
||||
);
|
||||
const searchName = ref('');
|
||||
const inventoryItems = ref<Firewall.InventoryItem[]>([]);
|
||||
const inventoryTotal = ref(0);
|
||||
@@ -850,11 +880,13 @@ const searchWithReset = () => {
|
||||
};
|
||||
|
||||
const changeIptablesChainFilter = () => {
|
||||
cacheFilterValues(chainFilterStorageKey, visibleIptablesChains.value);
|
||||
selects.value = [];
|
||||
return searchWithReset();
|
||||
};
|
||||
|
||||
const changeRuleFilter = () => {
|
||||
cacheFilterValues(ruleFilterStorageKey, selectedRuleFilters.value);
|
||||
selects.value = [];
|
||||
return searchWithReset();
|
||||
};
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
<span>{{ $t('firewall.' + operation + 'FirewallHelper') }}</span>
|
||||
</template>
|
||||
</DockerRestart>
|
||||
<TaskLog ref="taskLogRef" @close="handleInitializationTaskClose" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -189,6 +190,8 @@ import { computed, nextTick, ref } from 'vue';
|
||||
import { loadDockerStatus } from '@/api/modules/container';
|
||||
import { WarningFilled } from '@element-plus/icons-vue';
|
||||
import { routerToName, routerToNameWithQuery } from '@/utils/router';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { newUUID } from '@/utils/id';
|
||||
|
||||
const props = defineProps({
|
||||
currentTab: String,
|
||||
@@ -218,6 +221,7 @@ const operation = ref('restart');
|
||||
const dockerStatus = ref();
|
||||
const withDockerRestart = ref(false);
|
||||
const familyRetrying = ref(false);
|
||||
const taskLogRef = ref();
|
||||
const backendName = computed(() => baseInfo.value.backend || baseInfo.value.name);
|
||||
const backendUnavailable = computed(() => baseInfo.value.reason === 'backend_not_installed' || !baseInfo.value.isExist);
|
||||
const isServiceBackend = computed(() => backendName.value === 'firewalld' || backendName.value === 'ufw');
|
||||
@@ -360,13 +364,27 @@ const onInit = async () => {
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
const initializer =
|
||||
props.currentTab === 'forward' ? enableForwarding() : operateFilterChain(chainName, 'init-' + props.currentTab);
|
||||
await initializer;
|
||||
if (props.currentTab === 'base') {
|
||||
const result = (await operateFilterChain(chainName, 'init-' + props.currentTab, newUUID())).data;
|
||||
if (result.queued && result.taskID) {
|
||||
taskLogRef.value?.openWithTaskID(result.taskID, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const result = (await enableForwarding(newUUID())).data;
|
||||
if (result.queued && result.taskID) {
|
||||
taskLogRef.value?.openWithTaskID(result.taskID, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
await loadBaseInfo(true);
|
||||
};
|
||||
|
||||
const handleInitializationTaskClose = () => {
|
||||
loadBaseInfo(true);
|
||||
};
|
||||
|
||||
const onBind = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(i18n.global.t('firewall.bindHelper'), i18n.global.t('commons.button.bind'), {
|
||||
@@ -386,7 +404,11 @@ const onRetryFamilyIssues = async () => {
|
||||
familyRetrying.value = true;
|
||||
try {
|
||||
if (isDirectForward.value) {
|
||||
await enableForwarding();
|
||||
const result = (await enableForwarding(newUUID())).data;
|
||||
if (result.queued && result.taskID) {
|
||||
taskLogRef.value?.openWithTaskID(result.taskID, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
await operateFilterChain('1PANEL_BASIC', 'bind-base');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user