mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
refactor: simplify firewall rule management and whitelist updates (#13758)
This commit is contained in:
@@ -452,7 +452,7 @@ func normalizeFirewallRuleUUID(c *gin.Context, value *string) bool {
|
||||
|
||||
func handleFirewallRuleError(c *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, filter.ErrLockoutRisk), errors.Is(err, filter.ErrProtectedRule):
|
||||
case errors.Is(err, filter.ErrProtectedRule):
|
||||
helper.ErrorWithBusinessCode(c, http.StatusBadRequest, "FW_LOCKOUT_RISK", "ErrInvalidParams", err)
|
||||
case errors.Is(err, filter.ErrRuleStale):
|
||||
helper.ErrorWithBusinessCode(c, http.StatusConflict, "FW_RULE_STALE", "ErrInvalidParams", err)
|
||||
@@ -463,7 +463,7 @@ func handleFirewallRuleError(c *gin.Context, err error) {
|
||||
case errors.Is(err, filter.ErrUnsupportedScope), errors.Is(err, filter.ErrInvalidScope),
|
||||
errors.Is(err, filter.ErrProviderUnavailable), errors.Is(err, filter.ErrAdapterUnavailable):
|
||||
helper.ErrorWithBusinessCode(c, http.StatusBadRequest, "FW_SCOPE_UNSUPPORTED", "ErrInvalidParams", err)
|
||||
case errors.Is(err, filter.ErrInvalidRule), errors.Is(err, filter.ErrRuleOperation),
|
||||
case errors.Is(err, filter.ErrInvalidRule), errors.Is(err, filter.ErrRuleOperation), errors.Is(err, filter.ErrRuleConflict),
|
||||
errors.Is(err, repo.ErrFirewallPersistenceInvalid):
|
||||
helper.ErrorWithBusinessCode(c, http.StatusBadRequest, "FW_RULE_UNSUPPORTED", "ErrInvalidParams", err)
|
||||
case errors.Is(err, filter.ErrVerificationFailed):
|
||||
|
||||
@@ -35,7 +35,7 @@ type FirewallService struct {
|
||||
forwardingSync firewallDatabaseSyncAdapter
|
||||
dockerSync firewallDatabaseSyncAdapter
|
||||
selectedProvider func(context.Context) (filter.Provider, error)
|
||||
protectedPorts func() ([]firewall.PortWhitelist, error)
|
||||
requiredPorts func() ([]firewall.PortWhitelist, error)
|
||||
iptablesHelper *iptables_helper.Manager
|
||||
cleanupBackend func(string) error
|
||||
cleanupInactiveBackend func(string) error
|
||||
@@ -83,7 +83,7 @@ func newFirewallService() *FirewallService {
|
||||
forwardingSync: newForwardingService(),
|
||||
dockerSync: newDockerPortGuardService(),
|
||||
selectedProvider: firewallRuleSelectedProvider,
|
||||
protectedPorts: loadFirewallPortWhiteList,
|
||||
requiredPorts: LoadRequiredFirewallPortWhiteList,
|
||||
iptablesHelper: newIptablesHelperManager(),
|
||||
cleanupBackend: cleanupSystemBackend,
|
||||
cleanupInactiveBackend: cleanupInactiveSystemBackend,
|
||||
@@ -468,13 +468,6 @@ func restoreFirewalldDependents(
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (s *FirewallService) loadProtectedPorts() ([]firewall.PortWhitelist, error) {
|
||||
if s.protectedPorts == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return s.protectedPorts()
|
||||
}
|
||||
|
||||
func (s *FirewallService) Inventory(ctx context.Context, request dto.FirewallRuleInventory) (dto.FirewallRuleInventoryResponse, error) {
|
||||
requestedScopes := request.Scopes
|
||||
if len(requestedScopes) == 0 && request.Scope.Provider != "" {
|
||||
@@ -807,7 +800,6 @@ func (s *FirewallService) Check(
|
||||
request dto.FirewallRuleCheck,
|
||||
) (dto.FirewallRuleCheckResponse, error) {
|
||||
response := dto.FirewallRuleCheckResponse{Items: make([]dto.FirewallRuleCheckResult, 0, len(request.Items))}
|
||||
var protectedPorts []firewall.PortWhitelist
|
||||
var selectedProvider filter.Provider
|
||||
createStateLoaded := false
|
||||
var desiredByScope map[string][]filter.DesiredRule
|
||||
@@ -819,6 +811,7 @@ func (s *FirewallService) Check(
|
||||
managedRevision string
|
||||
}
|
||||
states := make(map[string]checkState)
|
||||
pending := make([]filter.FirewallRule, 0, len(request.Items))
|
||||
for _, item := range request.Items {
|
||||
if ruleUUID := strings.TrimSpace(item.UUID); ruleUUID != "" {
|
||||
result, updateErr := s.checkUpdate(ctx, clientIP, ruleUUID, item.Rule)
|
||||
@@ -830,10 +823,6 @@ func (s *FirewallService) Check(
|
||||
}
|
||||
if !createStateLoaded {
|
||||
var err error
|
||||
protectedPorts, err = s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
return dto.FirewallRuleCheckResponse{}, err
|
||||
}
|
||||
selectedProvider, err = s.selectedProvider(ctx)
|
||||
if err != nil {
|
||||
return dto.FirewallRuleCheckResponse{}, err
|
||||
@@ -896,10 +885,28 @@ func (s *FirewallService) Check(
|
||||
state = checkState{snapshot: snapshot, desired: desiredByScope[scopeKey], managedRevision: managedRevision}
|
||||
states[scopeKey] = state
|
||||
}
|
||||
checked, checkErr := filter.CheckCreate(state.snapshot, rule, state.desired, clientIP, protectedPorts...)
|
||||
checked, checkErr := filter.CheckCreate(state.snapshot, rule, state.desired)
|
||||
if checkErr != nil {
|
||||
return dto.FirewallRuleCheckResponse{}, checkErr
|
||||
}
|
||||
if checked.Decision == filter.CheckDecisionReady {
|
||||
for _, previous := range pending {
|
||||
if collision := filter.CheckRuleCollision(rule, previous); collision != nil {
|
||||
if errors.Is(collision, filter.ErrRuleConflict) {
|
||||
checked.Decision, checked.Classification, checked.Reason = filter.CheckDecisionBlocked, filter.CheckClassificationConflict, "exact_rule_conflict"
|
||||
} else if errors.Is(collision, filter.ErrRuleOperation) {
|
||||
checked.Decision, checked.Classification, checked.Reason = filter.CheckDecisionNoChange, filter.CheckClassificationExactManaged, "equivalent_batch_rule"
|
||||
} else {
|
||||
return dto.FirewallRuleCheckResponse{}, collision
|
||||
}
|
||||
checked.AllowedActions = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
if checked.Decision == filter.CheckDecisionReady {
|
||||
pending = append(pending, rule)
|
||||
}
|
||||
}
|
||||
checkFlag, signErr := signFirewallRuleCheck(checked, state.snapshot, state.managedRevision)
|
||||
if signErr != nil {
|
||||
return dto.FirewallRuleCheckResponse{}, signErr
|
||||
@@ -998,6 +1005,13 @@ func (s *FirewallService) create(
|
||||
firewallRuleMutationMu.Lock()
|
||||
defer firewallRuleMutationMu.Unlock()
|
||||
|
||||
return s.createLocked(ctx, request)
|
||||
}
|
||||
|
||||
func (s *FirewallService) createLocked(
|
||||
ctx context.Context,
|
||||
request dto.FirewallRuleCreate,
|
||||
) (dto.FirewallRuleCreateResponse, error) {
|
||||
prepared, failedIndex, err := s.prepareCreate(ctx, request.Items)
|
||||
if err != nil {
|
||||
return firewallCreatePrepareFailure(request.Items, failedIndex, err), err
|
||||
@@ -1117,6 +1131,11 @@ func (s *FirewallService) prepareCreate(
|
||||
if sourceKind == "" {
|
||||
sourceKind = constant.FirewallRuleSourceUser
|
||||
}
|
||||
for _, previous := range prepared {
|
||||
if err := filter.CheckRuleCollision(rule, previous.request.Rule); err != nil {
|
||||
return nil, index, err
|
||||
}
|
||||
}
|
||||
request.Rule = rule
|
||||
request.SourceKind = sourceKind
|
||||
prepared = append(prepared, preparedFirewallRuleCreate{
|
||||
@@ -1173,10 +1192,10 @@ func (s *FirewallService) createNativeRuleBatch(ctx context.Context, prepared []
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
identities := make(map[string]struct{}, len(stored)+len(prepared))
|
||||
identities := make(firewallRuleIdentityIndex, len(stored)+len(prepared))
|
||||
var maximumSequence int64
|
||||
for _, record := range stored {
|
||||
identities[record.PolicyKey()] = struct{}{}
|
||||
identities.add(record)
|
||||
if record.Sequence != nil && *record.Sequence > maximumSequence {
|
||||
maximumSequence = *record.Sequence
|
||||
}
|
||||
@@ -1194,14 +1213,16 @@ func (s *FirewallService) createNativeRuleBatch(ctx context.Context, prepared []
|
||||
record.Sequence = &sequence
|
||||
nextSequence += model.FirewallRuleSequenceStep
|
||||
}
|
||||
key := record.PolicyKey()
|
||||
if _, exists := identities[key]; exists {
|
||||
return s.cleanupFirewallBatchRecords(ctx, created, fmt.Errorf("%w: equivalent managed rule already exists", filter.ErrRuleOperation))
|
||||
if err := identities.check(record); err != nil {
|
||||
return s.cleanupFirewallBatchRecords(ctx, created, err)
|
||||
}
|
||||
if err := filter.CheckObservedRuleCollisions(snapshot, domainRule, nil); err != nil {
|
||||
return s.cleanupFirewallBatchRecords(ctx, created, err)
|
||||
}
|
||||
if recordErr = s.rules.Create(ctx, &record); recordErr != nil {
|
||||
return s.cleanupFirewallBatchRecords(ctx, created, recordErr)
|
||||
}
|
||||
identities[key] = struct{}{}
|
||||
identities.add(record)
|
||||
domainRule.UUID = record.UUID
|
||||
created = append(created, createdFirewallBatchRule{record: record, rule: domainRule})
|
||||
}
|
||||
@@ -1548,6 +1569,11 @@ func (s *FirewallService) createRule(
|
||||
authorization firewallRuleCreateAuthorization,
|
||||
) error {
|
||||
domainRule := request.Rule
|
||||
if authorization.Operation == filter.ChangeCreate {
|
||||
if err := filter.CheckObservedRuleCollisions(snapshot, domainRule, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
appendRule := false
|
||||
if authorization.Operation == filter.ChangeCreate && domainRule.Scope.Provider == filter.ProviderUFW && domainRule.OrderIndex == nil {
|
||||
appendPosition, err := runtime.AppendPosition(ctx, snapshot, domainRule)
|
||||
@@ -1803,11 +1829,7 @@ func (s *FirewallService) reorderRule(ctx context.Context, clientIP, ruleUUID st
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
protectedPorts, err := s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := filter.GuardMutation(observed, after, clientIP, protectedPorts...); err != nil {
|
||||
if err := filter.GuardMutation(observed); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.executeManagedMutation(ctx, managedMutationRequest{
|
||||
@@ -1884,11 +1906,10 @@ func (s *FirewallService) prepareManagedUpdate(
|
||||
}
|
||||
}
|
||||
}
|
||||
protectedPorts, err := s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
if err := filter.GuardMutation(observed); err != nil {
|
||||
return preparedManagedUpdate{}, err
|
||||
}
|
||||
if err := filter.GuardMutation(observed, after, clientIP, protectedPorts...); err != nil {
|
||||
if err := filter.CheckObservedRuleCollisions(snapshot, after, &observed.Locator); err != nil {
|
||||
return preparedManagedUpdate{}, err
|
||||
}
|
||||
return preparedManagedUpdate{
|
||||
@@ -1969,6 +1990,9 @@ func (s *FirewallService) selectedProviderForStoredRule(
|
||||
|
||||
func (s *FirewallService) executeManagedMutation(ctx context.Context, request managedMutationRequest) error {
|
||||
before, after := request.Before, request.After
|
||||
if err := filter.CheckObservedRuleCollisions(request.Snapshot, after, &request.Locator); err != nil {
|
||||
return err
|
||||
}
|
||||
semantic, err := model.FirewallRuleFromDomain(after)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2044,14 +2068,39 @@ func (s *FirewallService) ensureFirewallRuleIdentityAvailable(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestedKey := requested.PolicyKey()
|
||||
identities := make(firewallRuleIdentityIndex, len(stored))
|
||||
for _, candidate := range stored {
|
||||
if candidate.UUID == excludedUUID {
|
||||
continue
|
||||
if candidate.UUID != excludedUUID {
|
||||
identities.add(candidate)
|
||||
}
|
||||
if candidate.PolicyKey() == requestedKey {
|
||||
}
|
||||
return identities.check(requested)
|
||||
}
|
||||
|
||||
type firewallRuleIdentityIndex map[string][]filter.Action
|
||||
|
||||
func firewallRuleComparisonKey(rule model.FirewallRule) string {
|
||||
rule.Action = ""
|
||||
priority := 0
|
||||
if rule.Priority != nil {
|
||||
priority = *rule.Priority
|
||||
}
|
||||
return rule.PolicyKey() + "/" + strconv.Itoa(priority)
|
||||
}
|
||||
|
||||
func (index firewallRuleIdentityIndex) add(rule model.FirewallRule) {
|
||||
key := firewallRuleComparisonKey(rule)
|
||||
index[key] = append(index[key], filter.Action(rule.Action))
|
||||
}
|
||||
|
||||
func (index firewallRuleIdentityIndex) check(rule model.FirewallRule) error {
|
||||
for _, action := range index[firewallRuleComparisonKey(rule)] {
|
||||
if action == filter.Action(rule.Action) {
|
||||
return fmt.Errorf("%w: equivalent managed rule already exists", filter.ErrRuleOperation)
|
||||
}
|
||||
if filter.OppositeActions(action, filter.Action(rule.Action)) {
|
||||
return filter.ErrRuleConflict
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2182,6 +2231,9 @@ func (s *FirewallService) prepareSystemPortCreate(ctx context.Context, port dto.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if check.Decision == filter.CheckDecisionNoChange {
|
||||
return nil, nil
|
||||
}
|
||||
create := dto.FirewallRuleCreateItem{
|
||||
Rule: check.RequestedRule,
|
||||
CheckFlag: check.CheckFlag,
|
||||
@@ -2217,32 +2269,19 @@ func (s *FirewallService) prepareSystemPortCreate(ctx context.Context, port dto.
|
||||
}
|
||||
|
||||
func (s *FirewallService) deleteSystemPort(ctx context.Context, port dto.FirewallSystemPort) error {
|
||||
for {
|
||||
stored, err := s.systemPortRecords(ctx, port)
|
||||
if err != nil {
|
||||
stored, err := s.systemPortRecords(ctx, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, rule := range stored {
|
||||
if err := s.deleteProtectedSystemPortRule(ctx, rule.UUID); err != nil {
|
||||
if errors.Is(err, filter.ErrProtectedRule) && ctx.Value(panelPortWhitelistKey{}) != nil {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
if len(stored) == 0 {
|
||||
adopted, err := s.adoptExternalSystemPort(ctx, port)
|
||||
if err != nil || !adopted {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
deleted := false
|
||||
for _, rule := range stored {
|
||||
if err := s.deleteProtectedSystemPortRule(ctx, rule.UUID); err != nil {
|
||||
if errors.Is(err, filter.ErrProtectedRule) && ctx.Value(panelPortWhitelistKey{}) != nil {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
deleted = true
|
||||
}
|
||||
if !deleted {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FirewallService) deleteProtectedSystemPortRule(ctx context.Context, ruleUUID string) error {
|
||||
@@ -2284,36 +2323,6 @@ func isProtectedSystemFirewallRule(rule model.FirewallRule) bool {
|
||||
return strings.HasPrefix(rule.Owner, ownerPrefix)
|
||||
}
|
||||
|
||||
func (s *FirewallService) adoptExternalSystemPort(ctx context.Context, port dto.FirewallSystemPort) (bool, error) {
|
||||
provider, err := s.selectedProvider(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
check, err := s.checkRule(ctx, "", dto.FirewallRuleCheckItem{Rule: systemPortRule(provider, port)})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if check.Classification != filter.CheckClassificationExactExternal || len(check.Candidates) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
create := dto.FirewallRuleCreateItem{
|
||||
Rule: check.RequestedRule,
|
||||
CheckFlag: check.CheckFlag,
|
||||
AdoptInstanceKey: check.Candidates[0].InstanceKey,
|
||||
SourceKind: constant.FirewallRuleSourceSecurity,
|
||||
SourceID: constant.FirewallSystemAcceptedPortSourcePrefix + systemPortKey(port),
|
||||
}
|
||||
if len(check.Candidates) == 1 {
|
||||
create.Action = filter.CheckActionAdopt
|
||||
} else {
|
||||
create.Action = filter.CheckActionSelectAdopt
|
||||
}
|
||||
if err := s.createFirewallRuleItem(ctx, create); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func systemPortRule(provider filter.Provider, port dto.FirewallSystemPort) filter.FirewallRule {
|
||||
return firewall.RuleForSystemPort(provider, firewall.SystemPort(port))
|
||||
}
|
||||
@@ -2802,36 +2811,11 @@ func (s *FirewallService) SyncSystemPorts(ctx context.Context, previous, current
|
||||
}
|
||||
}
|
||||
|
||||
removed := make([]dto.FirewallSystemPort, 0)
|
||||
deleteUUIDs := make([]string, 0)
|
||||
for _, key := range sortedSystemPortKeys(previousSet) {
|
||||
if _, exists := currentSet[key]; exists {
|
||||
continue
|
||||
}
|
||||
port := previousSet[key]
|
||||
removed = append(removed, port)
|
||||
stored, listErr := s.systemPortRecords(ctx, port)
|
||||
if listErr != nil {
|
||||
return listErr
|
||||
}
|
||||
for _, rule := range stored {
|
||||
deleteUUIDs = append(deleteUUIDs, rule.UUID)
|
||||
}
|
||||
}
|
||||
if len(deleteUUIDs) > 0 {
|
||||
result, batchErr := s.Delete(ctx, dto.FirewallRuleDelete{UUIDs: deleteUUIDs})
|
||||
if batchErr != nil {
|
||||
return batchErr
|
||||
}
|
||||
if result.Failed > 0 {
|
||||
if len(result.Errors) > 0 {
|
||||
return fmt.Errorf("batch delete accepted firewall ports: %s", result.Errors[0].Error)
|
||||
}
|
||||
return fmt.Errorf("batch delete accepted firewall ports failed")
|
||||
}
|
||||
}
|
||||
for _, port := range removed {
|
||||
if err := s.deleteSystemPort(ctx, port); err != nil {
|
||||
if err := s.deleteSystemPort(ctx, previousSet[key]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -2880,34 +2864,62 @@ func loadRequiredFirewallPorts(panelPort string) ([]firewall.PortWhitelist, erro
|
||||
return firewall.NormalizeRequiredPorts(ports)
|
||||
}
|
||||
|
||||
func ReleaseFirewallPortWhitelistAfterUpdate(oldValue string) error {
|
||||
ports, err := loadConfiguredFirewallPortWhiteList()
|
||||
func (s *FirewallService) updatePortWhitelist(ctx context.Context, value string) error {
|
||||
firewallRuleMutationMu.Lock()
|
||||
defer firewallRuleMutationMu.Unlock()
|
||||
|
||||
ports, err := firewall.ParsePortWhitelist(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldValue, err := settingRepo.GetValueByKey(constant.FirewallPortWhiteList)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
oldValue = constant.FirewallPortWhiteListValue
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
oldPorts, err := firewall.ParsePortWhitelist(oldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
required, err := LoadRequiredFirewallPortWhiteList()
|
||||
required, err := s.requiredPorts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
removed := excludeFirewallPorts(oldPorts, ports)
|
||||
removed = excludeFirewallPorts(removed, required)
|
||||
return newFirewallService().releaseSystemPorts(context.Background(), systemPorts(removed))
|
||||
ctx = context.WithValue(ctx, panelPortWhitelistKey{}, firewall.NormalizePortWhitelist(append(oldPorts, required...)))
|
||||
added := excludeFirewallPorts(excludeFirewallPorts(ports, oldPorts), required)
|
||||
items := make([]dto.FirewallRuleCreateItem, 0, len(added))
|
||||
for _, port := range systemPorts(added) {
|
||||
item, err := s.prepareSystemPortCreate(ctx, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if item != nil {
|
||||
items = append(items, *item)
|
||||
}
|
||||
}
|
||||
if len(items) > 0 {
|
||||
if _, err := s.createLocked(ctx, dto.FirewallRuleCreate{Items: items}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
removed := excludeFirewallPorts(excludeFirewallPorts(oldPorts, ports), required)
|
||||
return global.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
txCtx := context.WithValue(ctx, constant.DB, tx)
|
||||
if err := s.releaseSystemPorts(txCtx, systemPorts(removed)); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Where("key = ?", constant.FirewallPortWhiteList).
|
||||
Assign(map[string]interface{}{"value": value}).
|
||||
FirstOrCreate(&model.Setting{Key: constant.FirewallPortWhiteList}).Error
|
||||
})
|
||||
}
|
||||
|
||||
// releaseSystemPorts only removes whitelist ownership from persisted rules. It
|
||||
// deliberately leaves the active native rules unchanged so users can delete
|
||||
// them explicitly from the firewall rule list.
|
||||
func (s *FirewallService) releaseSystemPorts(ctx context.Context, ports []dto.FirewallSystemPort) error {
|
||||
portSet, err := normalizeSystemPorts(ports)
|
||||
if err != nil || len(portSet) == 0 {
|
||||
return err
|
||||
}
|
||||
firewallRuleMutationMu.Lock()
|
||||
defer firewallRuleMutationMu.Unlock()
|
||||
|
||||
owners := make(map[string]struct{}, len(portSet)*2)
|
||||
for _, port := range portSet {
|
||||
|
||||
@@ -67,8 +67,6 @@ func (s *FirewallService) UpdatePanelPort(ctx context.Context, oldPort, port uin
|
||||
return err
|
||||
}
|
||||
}
|
||||
cleanup := *s
|
||||
cleanup.protectedPorts = func() ([]firewall.PortWhitelist, error) { return protected, nil }
|
||||
ctx = context.WithValue(ctx, panelPortWhitelistKey{}, protected)
|
||||
for index := range ports {
|
||||
ports[index].Port = strconv.Itoa(int(oldPort))
|
||||
@@ -86,7 +84,7 @@ func (s *FirewallService) UpdatePanelPort(ctx context.Context, oldPort, port uin
|
||||
if panelPortStillRequired(port, protected) {
|
||||
continue
|
||||
}
|
||||
if err := cleanup.deleteSystemPort(ctx, port); err != nil {
|
||||
if err := s.deleteSystemPort(ctx, port); err != nil {
|
||||
warnPanelPortCleanupFailure(oldPort, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"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/docker_guard"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
filterruntime "github.com/1Panel-dev/1Panel/agent/utils/firewall/filter/runtime"
|
||||
@@ -641,23 +640,12 @@ func (s *FirewallService) classifyFirewallRuleSyncCandidate(
|
||||
case filter.InventoryMatchExact:
|
||||
return firewallRuleSyncExisting, "rule already matches database policy"
|
||||
case filter.InventoryMatchMissing:
|
||||
protectedPorts, err := s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
return firewallRuleSyncBlocked, err.Error()
|
||||
}
|
||||
if filter.RuleBlocksManagementConnection(entry.rule, clientIP, protectedPorts...) {
|
||||
return firewallRuleSyncBlocked, "rule may block the current management connection"
|
||||
}
|
||||
return firewallRuleSyncReady, "rule is missing from target backend"
|
||||
case filter.InventoryMatchChanged:
|
||||
if item.Observed == nil {
|
||||
return firewallRuleSyncBlocked, filter.ErrRuleStale.Error()
|
||||
}
|
||||
protectedPorts, err := s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
return firewallRuleSyncBlocked, err.Error()
|
||||
}
|
||||
if err := filter.GuardMutation(*item.Observed, entry.rule, clientIP, protectedPorts...); err != nil {
|
||||
if err := filter.GuardMutation(*item.Observed); err != nil {
|
||||
return firewallRuleSyncBlocked, err.Error()
|
||||
}
|
||||
return firewallRuleSyncReady, "target rule differs from database policy"
|
||||
@@ -693,18 +681,9 @@ func (s *FirewallService) executeFirewallSystemSyncPlan(
|
||||
clientIP string,
|
||||
plan firewallSystemSyncPlan,
|
||||
) dto.FirewallRuleSyncResult {
|
||||
protectedPorts, err := s.loadProtectedPorts()
|
||||
if err != nil {
|
||||
for _, entry := range plan.entries {
|
||||
if entry.item.Status == firewallRuleSyncReady {
|
||||
entry.fail(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, scopePlan := range plan.scopes {
|
||||
reconciler := firewallScopeReconciler{
|
||||
ctx: ctx, clientIP: clientIP, protectedPorts: protectedPorts,
|
||||
ctx: ctx,
|
||||
runtime: scopePlan.runtime, snapshot: scopePlan.snapshot, entries: scopePlan.entries,
|
||||
}
|
||||
reconciler.reconcile()
|
||||
@@ -1097,12 +1076,10 @@ func buildDockerDatabaseSyncPlan(
|
||||
}
|
||||
|
||||
type firewallScopeReconciler struct {
|
||||
ctx context.Context
|
||||
clientIP string
|
||||
protectedPorts []firewall.PortWhitelist
|
||||
runtime *filterruntime.Engine
|
||||
snapshot filter.Snapshot
|
||||
entries []*firewallRuleSyncEntry
|
||||
ctx context.Context
|
||||
runtime *filterruntime.Engine
|
||||
snapshot filter.Snapshot
|
||||
entries []*firewallRuleSyncEntry
|
||||
}
|
||||
|
||||
func (r *firewallScopeReconciler) reconcile() {
|
||||
@@ -1177,7 +1154,7 @@ func (r *firewallScopeReconciler) apply(entries []*firewallRuleSyncEntry) {
|
||||
changes := make([]filter.DesiredChange, 0, len(entries))
|
||||
active := make([]*firewallRuleSyncEntry, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
change, changed, err := firewallRuleSyncChange(r.snapshot, r.entries, entry, r.clientIP, r.protectedPorts)
|
||||
change, changed, err := firewallRuleSyncChange(r.snapshot, r.entries, entry)
|
||||
if err != nil {
|
||||
entry.fail(err)
|
||||
continue
|
||||
@@ -1297,8 +1274,6 @@ func firewallRuleSyncChange(
|
||||
snapshot filter.Snapshot,
|
||||
entries []*firewallRuleSyncEntry,
|
||||
entry *firewallRuleSyncEntry,
|
||||
clientIP string,
|
||||
protectedPorts []firewall.PortWhitelist,
|
||||
) (filter.DesiredChange, bool, error) {
|
||||
if entry.remove != nil {
|
||||
for index := range snapshot.Rules {
|
||||
@@ -1328,9 +1303,6 @@ func firewallRuleSyncChange(
|
||||
case filter.InventoryMatchExact:
|
||||
return filter.DesiredChange{}, false, nil
|
||||
case filter.InventoryMatchMissing:
|
||||
if filter.RuleBlocksManagementConnection(entry.rule, clientIP, protectedPorts...) {
|
||||
return filter.DesiredChange{}, false, filter.ErrLockoutRisk
|
||||
}
|
||||
change.Operation = filter.ChangeCreate
|
||||
if position := firewallRuleSyncInsertionPosition(snapshot, entries, entry); position != nil {
|
||||
if entry.rule.Scope.Provider == filter.ProviderUFW && *position > maxObservedFirewallPosition(snapshot) {
|
||||
@@ -1346,7 +1318,7 @@ func firewallRuleSyncChange(
|
||||
if item.Observed == nil {
|
||||
return filter.DesiredChange{}, false, filter.ErrRuleStale
|
||||
}
|
||||
if err := filter.GuardMutation(*item.Observed, entry.rule, clientIP, protectedPorts...); err != nil {
|
||||
if err := filter.GuardMutation(*item.Observed); err != nil {
|
||||
return filter.DesiredChange{}, false, err
|
||||
}
|
||||
before := firewallsync.ObservedRule(*item.Observed)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -18,7 +19,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/ssh"
|
||||
terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai"
|
||||
"github.com/jinzhu/copier"
|
||||
@@ -125,22 +125,10 @@ func (u *SettingService) GetWebsiteDir() string {
|
||||
}
|
||||
|
||||
func (u *SettingService) Update(key, value string) error {
|
||||
oldValue := constant.FirewallPortWhiteListValue
|
||||
if key == constant.FirewallPortWhiteList {
|
||||
if _, err := firewall.ParsePortWhitelist(value); err != nil {
|
||||
return err
|
||||
}
|
||||
if val, err := settingRepo.GetValueByKey(key); err == nil {
|
||||
oldValue = val
|
||||
}
|
||||
return newFirewallService().updatePortWhitelist(context.Background(), value)
|
||||
}
|
||||
if err := settingRepo.UpdateOrCreate(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
if key == constant.FirewallPortWhiteList {
|
||||
return ReleaseFirewallPortWhitelistAfterUpdate(oldValue)
|
||||
}
|
||||
return nil
|
||||
return settingRepo.UpdateOrCreate(key, value)
|
||||
}
|
||||
|
||||
func (u *SettingService) UpdateTerminalAI(req dto.TerminalAIInfo) error {
|
||||
|
||||
@@ -41,7 +41,7 @@ func Init() {
|
||||
global.LOG.Warnf("restore forwarding rules failed, manual synchronization is available, err: %v", err)
|
||||
}
|
||||
if !needInit() {
|
||||
repairIptablesIPv6BaseChains(clientName)
|
||||
repairIptablesBaseChains(clientName)
|
||||
return
|
||||
}
|
||||
defer initDockerPortGuard(ctx)
|
||||
@@ -90,7 +90,7 @@ func Init() {
|
||||
|
||||
}
|
||||
|
||||
func repairIptablesIPv6BaseChains(clientName string) {
|
||||
func repairIptablesBaseChains(clientName string) {
|
||||
if clientName != constant.FirewallProviderIptables {
|
||||
return
|
||||
}
|
||||
@@ -99,21 +99,13 @@ func repairIptablesIPv6BaseChains(clientName string) {
|
||||
if status != constant.StatusEnable {
|
||||
return
|
||||
}
|
||||
initialized, bound, err := iptables_helper.LoadFamilyInitStatus(constant.FirewallFamilyIPv6, "base")
|
||||
if err == nil && initialized && bound {
|
||||
return
|
||||
manager := iptables_helper.Manager{
|
||||
PanelPort: service.LoadPanelPort,
|
||||
LoadRequiredPorts: service.LoadRequiredFirewallPortWhiteList,
|
||||
}
|
||||
panelPort := service.LoadPanelPort()
|
||||
requiredPorts, err := service.LoadRequiredFirewallPortWhiteList()
|
||||
if err != nil {
|
||||
global.LOG.Warnf("load required firewall ports for IPv6 repair failed, err: %v", err)
|
||||
return
|
||||
if err := manager.RepairBaseChains(); err != nil {
|
||||
global.LOG.Warnf("repair iptables base chains failed, err: %v", err)
|
||||
}
|
||||
if err := iptables_helper.RepairIPv6BaseChains(panelPort, requiredPorts); err != nil {
|
||||
global.LOG.Warnf("repair IPv6 iptables base chains failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
global.LOG.Info("repaired IPv6 iptables base chains successfully")
|
||||
}
|
||||
|
||||
func initDockerPortGuard(ctx context.Context) {
|
||||
|
||||
@@ -130,8 +130,6 @@ var mutationMu sync.Mutex
|
||||
|
||||
func NewManager() *Manager { return &Manager{runner: commandRunner{}} }
|
||||
|
||||
func NewManagerWithRunner(runner Runner) *Manager { return &Manager{runner: runner} }
|
||||
|
||||
func (m *Manager) Initialize(policies []Policy) error {
|
||||
mutationMu.Lock()
|
||||
defer mutationMu.Unlock()
|
||||
|
||||
@@ -22,10 +22,6 @@ type NftablesManager struct {
|
||||
|
||||
func NewNftablesManager() *NftablesManager { return &NftablesManager{runner: commandRunner{}} }
|
||||
|
||||
func NewNftablesManagerWithRunner(runner Runner) *NftablesManager {
|
||||
return &NftablesManager{runner: runner}
|
||||
}
|
||||
|
||||
func (m *NftablesManager) Initialize(policies []Policy) error {
|
||||
mutationMu.Lock()
|
||||
defer mutationMu.Unlock()
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRuleConflict = errors.New("firewall rule has identical conditions and an opposing action")
|
||||
ErrRuleStale = errors.New("firewall rule state is stale")
|
||||
ErrRuleOperation = errors.New("firewall rule operation is not allowed")
|
||||
ErrRuleCheckRequired = errors.New("firewall rule must be checked again")
|
||||
@@ -58,8 +59,6 @@ func CheckCreate(
|
||||
snapshot Snapshot,
|
||||
requested FirewallRule,
|
||||
desired []DesiredRule,
|
||||
clientIP string,
|
||||
protectedPorts ...PortWhitelist,
|
||||
) (RuleCheckResult, error) {
|
||||
normalized, err := NormalizeRule(requested)
|
||||
if err != nil {
|
||||
@@ -79,11 +78,9 @@ func CheckCreate(
|
||||
RequestedRule: normalized,
|
||||
RequestedRuleKey: ruleKey,
|
||||
}
|
||||
if RuleBlocksManagementConnection(normalized, clientIP, protectedPorts...) {
|
||||
result.Decision = CheckDecisionBlocked
|
||||
result.Classification = CheckClassificationProtected
|
||||
result.Reason = "current_management_connection"
|
||||
return finishCheck(result)
|
||||
matchKey, err := RuleMatchKey(normalized)
|
||||
if err != nil {
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
|
||||
for _, owned := range desired {
|
||||
@@ -91,7 +88,18 @@ func CheckCreate(
|
||||
if err != nil {
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
if ownedKey != ruleKey || (owned.Origin != RuleOriginCreated && owned.Origin != RuleOriginAdopted) {
|
||||
ownedMatchKey, err := RuleMatchKey(owned.Rule)
|
||||
if err != nil {
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
if ownedMatchKey != matchKey || (owned.Origin != RuleOriginCreated && owned.Origin != RuleOriginAdopted) {
|
||||
continue
|
||||
}
|
||||
if OppositeActions(normalized.Action, owned.Rule.Action) {
|
||||
result.Decision, result.Classification, result.Reason = CheckDecisionBlocked, CheckClassificationConflict, "exact_rule_conflict"
|
||||
return finishCheck(result)
|
||||
}
|
||||
if normalized.Action != owned.Rule.Action {
|
||||
continue
|
||||
}
|
||||
owned.RuleKey = ownedKey
|
||||
@@ -109,18 +117,12 @@ func CheckCreate(
|
||||
}
|
||||
|
||||
exact := make([]ObservedRule, 0)
|
||||
equivalentExternal := false
|
||||
for _, observed := range snapshot.Rules {
|
||||
if observed.ParseStatus != ParseStatusSupported {
|
||||
if hydrated, ok := hydrateOwnedPartialRule(observed, desired); ok {
|
||||
observed = hydrated
|
||||
} else {
|
||||
if observed.Rule.Scope.Provider == ProviderFirewalld && observed.Rule.NativeKind == NativeKindZoneService {
|
||||
continue
|
||||
}
|
||||
result.Decision = CheckDecisionBlocked
|
||||
result.Classification = CheckClassificationUnsupported
|
||||
result.Reason = "opaque_rule_in_target_scope"
|
||||
result.Candidates = append(result.Candidates, observed)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -129,12 +131,26 @@ func CheckCreate(
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
observed.Rule = observedRule
|
||||
observedKey, err := RuleKey(observedRule)
|
||||
observedKey, err := RuleMatchKey(observedRule)
|
||||
if err != nil {
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
if observedKey == ruleKey {
|
||||
exact = append(exact, observed)
|
||||
if observedKey != matchKey {
|
||||
continue
|
||||
}
|
||||
if OppositeActions(normalized.Action, observedRule.Action) {
|
||||
result.Decision, result.Classification, result.Reason = CheckDecisionBlocked, CheckClassificationConflict, "exact_rule_conflict"
|
||||
return finishCheck(result)
|
||||
}
|
||||
if normalized.Action == observedRule.Action {
|
||||
equivalentExternal = true
|
||||
key, err := RuleKey(observedRule)
|
||||
if err != nil {
|
||||
return RuleCheckResult{}, err
|
||||
}
|
||||
if key == ruleKey {
|
||||
exact = append(exact, observed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +177,10 @@ func CheckCreate(
|
||||
result.Reason = "multiple_equivalent_external_rules"
|
||||
result.Candidates = exact
|
||||
result.AllowedActions = []CheckAction{CheckActionSelectAdopt, CheckActionCancel}
|
||||
case result.Classification == CheckClassificationUnsupported:
|
||||
case equivalentExternal:
|
||||
result.Decision = CheckDecisionNoChange
|
||||
result.Classification = CheckClassificationExactExternal
|
||||
result.Reason = "equivalent_external_rule"
|
||||
default:
|
||||
result.AllowedActions = []CheckAction{CheckActionCreate}
|
||||
}
|
||||
@@ -241,52 +260,6 @@ func containsProtectedRule(rules []ObservedRule) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func RuleBlocksManagementConnection(
|
||||
rule FirewallRule,
|
||||
clientIP string,
|
||||
protectedPorts ...PortWhitelist,
|
||||
) bool {
|
||||
if rule.Action == ActionAccept {
|
||||
return false
|
||||
}
|
||||
targetAddress := rule.SourceAddress
|
||||
if targetAddress != "" {
|
||||
client, err := netip.ParseAddr(strings.TrimSpace(clientIP))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if rule.Scope.Family == FamilyIPv4 {
|
||||
client = client.Unmap()
|
||||
if !client.Is4() {
|
||||
return false
|
||||
}
|
||||
} else if rule.Scope.Family == FamilyIPv6 && (!client.Is6() || client.Is4In6()) {
|
||||
return false
|
||||
}
|
||||
prefix, err := netip.ParsePrefix(targetAddress)
|
||||
if err != nil || !prefix.Contains(client) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if rule.DestinationPort == "" {
|
||||
return true
|
||||
}
|
||||
for _, protected := range protectedPorts {
|
||||
family := strings.ToLower(strings.TrimSpace(protected.Family))
|
||||
if family != "" && rule.Scope.Family != FamilyInet && string(rule.Scope.Family) != family {
|
||||
continue
|
||||
}
|
||||
protocol := strings.ToLower(strings.TrimSpace(protected.Protocol))
|
||||
if rule.Protocol != "all" && rule.Protocol != protocol {
|
||||
continue
|
||||
}
|
||||
if portsOverlap(rule.DestinationPort, protected.Port) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func FindCandidate(candidates []ObservedRule, selected string) (ObservedRule, error) {
|
||||
matched := make([]ObservedRule, 0, 1)
|
||||
for _, candidate := range candidates {
|
||||
@@ -354,24 +327,6 @@ func protocolsOverlap(left, right string) bool {
|
||||
return left == "all" || right == "all" || left == right
|
||||
}
|
||||
|
||||
func addressCovers(existing, requested string) bool {
|
||||
if existing == "" {
|
||||
return true
|
||||
}
|
||||
if requested == "" {
|
||||
return false
|
||||
}
|
||||
existingPrefix, err := netip.ParsePrefix(existing)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
requestedPrefix, err := netip.ParsePrefix(requested)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return existingPrefix.Bits() <= requestedPrefix.Bits() && existingPrefix.Contains(requestedPrefix.Addr())
|
||||
}
|
||||
|
||||
func addressesOverlap(left, right string) bool {
|
||||
if left == "" || right == "" {
|
||||
return true
|
||||
|
||||
@@ -44,6 +44,56 @@ func RuleKey(rule FirewallRule) (string, error) {
|
||||
return normalizedRuleKey(normalized)
|
||||
}
|
||||
|
||||
func RuleMatchKey(rule FirewallRule) (string, error) {
|
||||
normalized, err := NormalizeRule(rule)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
normalized.Action, normalized.NativeKind, normalized.OrderBucket = "", "", ""
|
||||
if normalized.Priority != nil && *normalized.Priority == 0 {
|
||||
normalized.Priority = nil
|
||||
}
|
||||
return normalizedRuleKey(normalized)
|
||||
}
|
||||
|
||||
func OppositeActions(left, right Action) bool {
|
||||
return left == ActionAccept && (right == ActionDrop || right == ActionReject) ||
|
||||
right == ActionAccept && (left == ActionDrop || left == ActionReject)
|
||||
}
|
||||
|
||||
func CheckRuleCollision(requested, existing FirewallRule) error {
|
||||
wanted, err := RuleMatchKey(requested)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actual, err := RuleMatchKey(existing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wanted != actual {
|
||||
return nil
|
||||
}
|
||||
if requested.Action == existing.Action {
|
||||
return fmt.Errorf("%w: equivalent rule already exists", ErrRuleOperation)
|
||||
}
|
||||
if OppositeActions(requested.Action, existing.Action) {
|
||||
return ErrRuleConflict
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckObservedRuleCollisions(snapshot Snapshot, requested FirewallRule, excluded *Locator) error {
|
||||
for _, observed := range snapshot.Rules {
|
||||
if observed.ParseStatus != ParseStatusSupported || excluded != nil && SameLocator(observed.Locator, *excluded) {
|
||||
continue
|
||||
}
|
||||
if err := CheckRuleCollision(requested, observed.Rule); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizedRuleKey(normalized FirewallRule) (string, error) {
|
||||
identity := ruleIdentity{
|
||||
Scope: normalized.Scope.Key(),
|
||||
|
||||
@@ -2,8 +2,6 @@ package filter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
@@ -48,12 +46,6 @@ type DesiredRule struct {
|
||||
ObservedInstanceKey string `json:"observedInstanceKey,omitempty"`
|
||||
}
|
||||
|
||||
type RuntimeUsage struct {
|
||||
Used bool `json:"used"`
|
||||
UsedBy []string `json:"usedBy,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type PositionRange struct {
|
||||
Min int `json:"min"`
|
||||
Max int `json:"max"`
|
||||
@@ -67,7 +59,6 @@ type InventoryItem struct {
|
||||
Desired *DesiredRule `json:"desired,omitempty"`
|
||||
State InventoryState `json:"state"`
|
||||
Match InventoryMatch `json:"match"`
|
||||
Usage *RuntimeUsage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type Inventory struct {
|
||||
@@ -312,89 +303,3 @@ func inventoryStateForDesired(desired DesiredRule, match InventoryMatch) Invento
|
||||
return InventoryStateManaged
|
||||
}
|
||||
}
|
||||
|
||||
func RuntimeUsageKey(rule FirewallRule) string {
|
||||
protocol := strings.ToLower(strings.TrimSpace(rule.Protocol))
|
||||
port := strings.TrimSpace(rule.DestinationPort)
|
||||
if port == "" || (protocol != "tcp" && protocol != "udp") {
|
||||
return ""
|
||||
}
|
||||
return protocol + "\x00" + port
|
||||
}
|
||||
|
||||
func AttachRuntimeUsage(items []InventoryItem, usage map[string]RuntimeUsage) []InventoryItem {
|
||||
result := make([]InventoryItem, len(items))
|
||||
copy(result, items)
|
||||
for index := range result {
|
||||
value, exists := runtimeUsageForRule(result[index].Rule, usage)
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
value.UsedBy = normalizedUsageOwners(value.UsedBy)
|
||||
value.Used = value.Used || len(value.UsedBy) > 0
|
||||
result[index].Usage = &value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func runtimeUsageForRule(rule FirewallRule, usage map[string]RuntimeUsage) (RuntimeUsage, bool) {
|
||||
key := RuntimeUsageKey(rule)
|
||||
if key == "" {
|
||||
return RuntimeUsage{}, false
|
||||
}
|
||||
if value, exists := usage[key]; exists {
|
||||
return value, true
|
||||
}
|
||||
intervals, err := portIntervals(rule.DestinationPort)
|
||||
if err != nil {
|
||||
return RuntimeUsage{}, false
|
||||
}
|
||||
protocolPrefix := strings.ToLower(strings.TrimSpace(rule.Protocol)) + "\x00"
|
||||
combined := RuntimeUsage{}
|
||||
found := false
|
||||
for usageKey, value := range usage {
|
||||
if !strings.HasPrefix(usageKey, protocolPrefix) {
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(strings.TrimPrefix(usageKey, protocolPrefix))
|
||||
if err != nil || !portInIntervals(port, intervals) {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
combined.Used = combined.Used || value.Used
|
||||
combined.UsedBy = append(combined.UsedBy, value.UsedBy...)
|
||||
if combined.Reason == "" {
|
||||
combined.Reason = value.Reason
|
||||
} else if value.Reason != "" && combined.Reason != value.Reason {
|
||||
combined.Reason = "multiple"
|
||||
}
|
||||
}
|
||||
return combined, found
|
||||
}
|
||||
|
||||
func portInIntervals(port int, intervals [][2]int) bool {
|
||||
for _, interval := range intervals {
|
||||
if port >= interval[0] && port <= interval[1] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func normalizedUsageOwners(owners []string) []string {
|
||||
seen := make(map[string]struct{}, len(owners))
|
||||
result := make([]string, 0, len(owners))
|
||||
for _, owner := range owners {
|
||||
owner = strings.TrimSpace(owner)
|
||||
if owner == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[owner]; exists {
|
||||
continue
|
||||
}
|
||||
seen[owner] = struct{}{}
|
||||
result = append(result, owner)
|
||||
}
|
||||
sort.Strings(result)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -112,7 +112,6 @@ var (
|
||||
ErrUnsupportedScope = errors.New("unsupported firewall scope")
|
||||
ErrInvalidRule = errors.New("invalid firewall rule")
|
||||
ErrProtectedRule = errors.New("protected firewall rule cannot be modified")
|
||||
ErrLockoutRisk = errors.New("firewall change may lock out management access")
|
||||
ErrCompositeRule = errors.New("firewall rule must be atomic")
|
||||
ErrExpansionLimit = errors.New("firewall rule expansion limit exceeded")
|
||||
)
|
||||
|
||||
@@ -310,9 +310,6 @@ func (a *Adapter) compileChange(snapshot filter.Snapshot, change filter.DesiredC
|
||||
if normalized.UUID == "" {
|
||||
return filter.NativeRulePlan{}, fmt.Errorf("%w: rule UUID is required", filter.ErrInvalidRule)
|
||||
}
|
||||
if (change.Operation == filter.ChangeCreate || change.Operation == filter.ChangeUpdate) && isBroadDeny(normalized) {
|
||||
return filter.NativeRulePlan{}, filter.ErrLockoutRisk
|
||||
}
|
||||
|
||||
expected := observedForRule(normalized)
|
||||
plan := filter.NativeRulePlan{RuleUUID: normalized.UUID, Operation: change.Operation, Expected: expected}
|
||||
@@ -389,11 +386,6 @@ func validateWritableRule(rule filter.FirewallRule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBroadDeny(rule filter.FirewallRule) bool {
|
||||
return (rule.Action == filter.ActionDrop || rule.Action == filter.ActionReject) &&
|
||||
rule.SourceAddress == "" && rule.DestinationAddress == "" && rule.SourcePort == "" && rule.DestinationPort == ""
|
||||
}
|
||||
|
||||
func observedForRule(rule filter.FirewallRule) filter.ObservedRule {
|
||||
canonical := nativeCanonical(rule)
|
||||
return filter.ObservedRule{
|
||||
@@ -548,7 +540,6 @@ type zoneOutput struct {
|
||||
ports string
|
||||
rich string
|
||||
services string
|
||||
active bool
|
||||
}
|
||||
|
||||
func (a *Adapter) readScope(ctx context.Context, scope filter.Scope, permanent bool) (zoneOutput, error) {
|
||||
@@ -571,9 +562,6 @@ func parseZoneOutput(output string) zoneOutput {
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
switch {
|
||||
case line == filter.FirewalldInputZone+" (active)":
|
||||
parsed.active = true
|
||||
inRichRules = false
|
||||
case strings.HasPrefix(line, "ports:"):
|
||||
parsed.ports = strings.TrimSpace(strings.TrimPrefix(line, "ports:"))
|
||||
inRichRules = false
|
||||
@@ -594,10 +582,7 @@ func parseZoneOutput(output string) zoneOutput {
|
||||
}
|
||||
|
||||
func publicZoneNotices(runtime, permanent zoneOutput) []filter.ScopeNotice {
|
||||
notices := make([]filter.ScopeNotice, 0, 2)
|
||||
if !runtime.active {
|
||||
notices = append(notices, filter.ScopeNotice{Code: filter.ScopeNoticeManagedScopeInactive})
|
||||
}
|
||||
notices := make([]filter.ScopeNotice, 0, 1)
|
||||
mismatched := make([]string, 0, 3)
|
||||
if !sameFields(runtime.ports, permanent.ports) {
|
||||
mismatched = append(mismatched, "ports")
|
||||
|
||||
@@ -429,9 +429,6 @@ func compileChange(snapshot filter.Snapshot, change filter.DesiredChange) (filte
|
||||
(normalized.Scope.Family == filter.FamilyIPv6 && normalized.Protocol == "icmp") {
|
||||
return filter.NativeRulePlan{}, fmt.Errorf("%w: protocol %q does not match %s", filter.ErrInvalidRule, normalized.Protocol, normalized.Scope.Family)
|
||||
}
|
||||
if (change.Operation == filter.ChangeCreate || change.Operation == filter.ChangeUpdate) && isBroadDeny(normalized) {
|
||||
return filter.NativeRulePlan{}, filter.ErrLockoutRisk
|
||||
}
|
||||
marker := "1panel-rule:" + normalized.UUID
|
||||
position := len(snapshot.Rules) + 1
|
||||
verb := "-I"
|
||||
@@ -692,12 +689,6 @@ func insertionPosition(snapshot filter.Snapshot, rule filter.FirewallRule) int {
|
||||
return len(snapshot.Rules) + 1
|
||||
}
|
||||
|
||||
func isBroadDeny(rule filter.FirewallRule) bool {
|
||||
return (rule.Action == filter.ActionDrop || rule.Action == filter.ActionReject) &&
|
||||
rule.SourceAddress == "" && rule.DestinationAddress == "" && rule.SourcePort == "" &&
|
||||
rule.DestinationPort == ""
|
||||
}
|
||||
|
||||
type systemBackend struct{}
|
||||
|
||||
func (systemBackend) CheckMultiport(ctx context.Context, family filter.Family) error {
|
||||
|
||||
@@ -238,9 +238,6 @@ func applyChange(snapshot filter.Snapshot, change filter.DesiredChange) ([]filte
|
||||
if normalized.Scope.Key() != snapshot.Scope.Key() || normalized.UUID == "" {
|
||||
return nil, filter.ObservedRule{}, nil, fmt.Errorf("%w: invalid nftables mutation rule", filter.ErrInvalidRule)
|
||||
}
|
||||
if (change.Operation == filter.ChangeCreate || change.Operation == filter.ChangeUpdate) && broadDeny(normalized) {
|
||||
return nil, filter.ObservedRule{}, nil, filter.ErrLockoutRisk
|
||||
}
|
||||
position := len(rules) + 1
|
||||
marker := "1panel-rule:" + normalized.UUID
|
||||
var previous *filter.ObservedRule
|
||||
@@ -316,11 +313,6 @@ func ruleUUID(change filter.DesiredChange) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func broadDeny(rule filter.FirewallRule) bool {
|
||||
return (rule.Action == filter.ActionDrop || rule.Action == filter.ActionReject) && rule.SourceAddress == "" &&
|
||||
rule.DestinationAddress == "" && rule.SourcePort == "" && rule.DestinationPort == ""
|
||||
}
|
||||
|
||||
func rebuildCommand(scope filter.Scope, rules []filter.ObservedRule) (filter.NativeCommand, error) {
|
||||
tableFamily := nftables_helper.TableFamily(scope.Family)
|
||||
chain := nativeChainName(scope)
|
||||
|
||||
@@ -315,9 +315,6 @@ func compileChange(snapshot filter.Snapshot, change filter.DesiredChange) (filte
|
||||
if normalized.UUID == "" {
|
||||
return filter.NativeRulePlan{}, fmt.Errorf("%w: rule UUID is required", filter.ErrInvalidRule)
|
||||
}
|
||||
if (change.Operation == filter.ChangeCreate || change.Operation == filter.ChangeUpdate) && isBroadDeny(normalized) {
|
||||
return filter.NativeRulePlan{}, filter.ErrLockoutRisk
|
||||
}
|
||||
marker := "1panel-rule:" + normalized.UUID
|
||||
position := insertionPosition(snapshot, normalized)
|
||||
expected := observedForRule(normalized, marker, position)
|
||||
@@ -429,11 +426,6 @@ func validateWritableRule(rule filter.FirewallRule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBroadDeny(rule filter.FirewallRule) bool {
|
||||
return (rule.Action == filter.ActionDrop || rule.Action == filter.ActionReject) && rule.Protocol == "all" &&
|
||||
rule.SourceAddress == "" && rule.DestinationAddress == "" && rule.DestinationPort == ""
|
||||
}
|
||||
|
||||
func validateMutationTarget(snapshot filter.Snapshot, change filter.DesiredChange, desired filter.FirewallRule, marker string, requireOwned bool) (filter.ObservedRule, error) {
|
||||
if change.Locator == nil || change.Locator.Position == nil {
|
||||
return filter.ObservedRule{}, fmt.Errorf("%w: ufw mutation requires a numbered locator", filter.ErrInvalidRule)
|
||||
|
||||
@@ -42,18 +42,10 @@ func ProtectSnapshot(snapshot Snapshot, ports []PortWhitelist) (Snapshot, error)
|
||||
return protected, nil
|
||||
}
|
||||
|
||||
func GuardMutation(
|
||||
target ObservedRule,
|
||||
after FirewallRule,
|
||||
clientIP string,
|
||||
protectedPorts ...PortWhitelist,
|
||||
) error {
|
||||
func GuardMutation(target ObservedRule) error {
|
||||
if target.Protected {
|
||||
return ErrProtectedRule
|
||||
}
|
||||
if RuleBlocksManagementConnection(after, clientIP, protectedPorts...) {
|
||||
return ErrLockoutRisk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,6 @@ type FilterRules struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func ReadFilterRulesByChain(chain string) ([]FilterRules, error) {
|
||||
return readFilterRulesByChain(chain, RunWithStd)
|
||||
}
|
||||
|
||||
func readFilterRulesByChain(chain string, run func(string, ...string) (string, error)) ([]FilterRules, error) {
|
||||
var rules []FilterRules
|
||||
if cmd.CheckIllegal(chain) {
|
||||
|
||||
@@ -18,26 +18,6 @@ func (m *Manager) EnsureIPv6BaseChains() error {
|
||||
return EnsureIPv6BaseChains(m.panelPort(), ports)
|
||||
}
|
||||
|
||||
func RepairIPv6BaseChains(panelPort string, ports []firewall.PortWhitelist) error {
|
||||
initialized, bound, err := LoadFamilyInitStatus(constant.FirewallFamilyIPv6, "base")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return repairIPv6BaseChains(initialized, bound, BindIPv6BaseChains, func() error {
|
||||
return EnsureIPv6BaseChains(panelPort, ports)
|
||||
})
|
||||
}
|
||||
|
||||
func repairIPv6BaseChains(initialized, bound bool, bind, ensure func() error) error {
|
||||
if initialized {
|
||||
if bound {
|
||||
return nil
|
||||
}
|
||||
return bind()
|
||||
}
|
||||
return ensure()
|
||||
}
|
||||
|
||||
func EnsureIPv6BaseChains(panelPort string, ports []firewall.PortWhitelist) error {
|
||||
commands, err := lifecycle.ResolveIptablesCommands()
|
||||
if err != nil || !commands.IPv6Available() {
|
||||
@@ -97,7 +77,7 @@ func buildIPv6BaseInitializationScript(dir, panelPort string, ports []firewall.P
|
||||
return buildBaseChainsRestoreScript(dir, panelPort, true, ports...)
|
||||
}
|
||||
}
|
||||
defaults, err := ipv6BaseDefaultRules(panelPort, ports)
|
||||
defaults, err := baseDefaultRules(panelPort, ports, constant.FirewallFamilyIPv6)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -112,14 +92,14 @@ func buildIPv6BaseInitializationScript(dir, panelPort string, ports []firewall.P
|
||||
return script.String(), nil
|
||||
}
|
||||
|
||||
func ipv6BaseDefaultRules(panelPort string, ports []firewall.PortWhitelist) ([]string, error) {
|
||||
func baseDefaultRules(panelPort string, ports []firewall.PortWhitelist, family string) ([]string, error) {
|
||||
ports, err := firewall.NormalizeRequiredPorts(append([]firewall.PortWhitelist{{Port: panelPort, Protocol: "tcp"}}, ports...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules := []string{"-A " + BasicBeforeChain + " " + IoRuleIn, "-A " + BasicBeforeChain + " " + EstablishedRule}
|
||||
for _, port := range ports {
|
||||
if port.Family == "" || port.Family == constant.FirewallFamilyIPv6 {
|
||||
if port.Family == "" || port.Family == family {
|
||||
rules = append(rules, iptablesPortRuleLine("-A", BasicBeforeChain, port.Protocol, port.Port))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,14 @@ func setBaseChainBindings(ipv6, bind bool) error {
|
||||
}
|
||||
|
||||
func buildBaseChainBindingsRestoreScript(output string, bind bool) string {
|
||||
lines := baseChainBindingCommands(output, bind)
|
||||
if len(lines) == 0 {
|
||||
return ""
|
||||
}
|
||||
return "*filter\n" + strings.Join(lines, "\n") + "\nCOMMIT\n"
|
||||
}
|
||||
|
||||
func baseChainBindingCommands(output string, bind bool) []string {
|
||||
lines := make([]string, 0, len(BasicChains())*2)
|
||||
for _, chain := range BasicChains() {
|
||||
binding := "-A " + InputChain + " -j " + chain
|
||||
@@ -217,10 +225,7 @@ func buildBaseChainBindingsRestoreScript(output string, bind bool) string {
|
||||
lines = append(lines, fmt.Sprintf("-I %s %d -j %s", InputChain, index+1, chain))
|
||||
}
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
return ""
|
||||
}
|
||||
return "*filter\n" + strings.Join(lines, "\n") + "\nCOMMIT\n"
|
||||
return lines
|
||||
}
|
||||
|
||||
func saveBaseChains() error {
|
||||
@@ -315,7 +320,7 @@ func buildBaseChainsRestoreScript(firewallDir, panelPort string, ipv6 bool, requ
|
||||
script.WriteByte('\n')
|
||||
}
|
||||
if ipv6 {
|
||||
defaults, err := ipv6BaseDefaultRules(panelPort, requiredPorts)
|
||||
defaults, err := baseDefaultRules(panelPort, requiredPorts, constant.FirewallFamilyIPv6)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
102
agent/utils/firewall/iptables_helper/repair.go
Normal file
102
agent/utils/firewall/iptables_helper/repair.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package iptables_helper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle"
|
||||
)
|
||||
|
||||
func (m *Manager) RepairBaseChains() error {
|
||||
commands, err := lifecycle.ResolveIptablesCommands()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, family := range []string{constant.FirewallFamilyIPv4, constant.FirewallFamilyIPv6} {
|
||||
ipv6 := family == constant.FirewallFamilyIPv6
|
||||
run, executable := RunWithStd, commands.Restore4
|
||||
if ipv6 {
|
||||
if !commands.IPv6Available() {
|
||||
continue
|
||||
}
|
||||
run, executable = RunIPv6WithStd, commands.Restore6
|
||||
}
|
||||
output, err := run(FilterTab, "-S")
|
||||
if ipv6 && errors.Is(err, filter.ErrFamilyUnavailable) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
script, err := buildBaseChainsRepairScript(global.Dir.FirewallDir, output, ipv6, func() ([]string, error) {
|
||||
ports, err := m.loadRequiredPorts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return baseDefaultRules(m.panelPort(), ports, family)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("prepare %s base chain repair: %w", family, err)
|
||||
}
|
||||
if script != "" {
|
||||
if err := restoreRules(executable, script); err != nil {
|
||||
return fmt.Errorf("repair %s base chains: %w", family, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildBaseChainsRepairScript(dir, output string, ipv6 bool, loadDefaults func() ([]string, error)) (string, error) {
|
||||
var chains, rules, defaults []string
|
||||
bound := true
|
||||
for _, item := range []struct{ chain, file string }{
|
||||
{BasicBeforeChain, BasicBeforeFileName},
|
||||
{BasicChain, BasicFileName},
|
||||
{BasicAfterChain, BasicAfterFileName},
|
||||
} {
|
||||
bound = bound && containsIptablesRule(output, "-A "+InputChain+" -j "+item.chain)
|
||||
if containsIptablesRule(output, "-N "+item.chain) {
|
||||
continue
|
||||
}
|
||||
chains = append(chains, "-N "+item.chain)
|
||||
fileName := item.file
|
||||
if ipv6 {
|
||||
fileName = IPv6FileName(fileName)
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(dir, fileName))
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return "", err
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
if errors.Is(err, os.ErrNotExist) && item.chain != BasicChain {
|
||||
if defaults == nil {
|
||||
defaults, err = loadDefaults()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
lines = defaults
|
||||
}
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "-A "+item.chain+" ") && !strings.ContainsAny(line, "\r\n") {
|
||||
rules = append(rules, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
lines := append(chains, rules...)
|
||||
if !bound {
|
||||
lines = append(lines, baseChainBindingCommands(output, true)...)
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
return "*filter\n" + strings.Join(lines, "\n") + "\nCOMMIT\n", nil
|
||||
}
|
||||
@@ -79,11 +79,6 @@ func validatePortWhitelist(rules []PortWhitelist) ([]PortWhitelist, error) {
|
||||
if _, ok := exists[key]; ok {
|
||||
continue
|
||||
}
|
||||
for _, current := range result {
|
||||
if current.Family == rule.Family && current.Protocol == rule.Protocol && whitelistPortsOverlap(current.Port, rule.Port) {
|
||||
return nil, fmt.Errorf("overlapping firewall port whitelist rules: %s and %s", current.Port, rule.Port)
|
||||
}
|
||||
}
|
||||
exists[key] = struct{}{}
|
||||
result = append(result, rule)
|
||||
}
|
||||
@@ -131,21 +126,6 @@ func parseWhitelistPort(value string) (int, error) {
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func whitelistPortsOverlap(left, right string) bool {
|
||||
parseRange := func(value string) (int, int) {
|
||||
parts := strings.Split(value, "-")
|
||||
start, _ := strconv.Atoi(parts[0])
|
||||
if len(parts) == 1 {
|
||||
return start, start
|
||||
}
|
||||
end, _ := strconv.Atoi(parts[1])
|
||||
return start, end
|
||||
}
|
||||
leftStart, leftEnd := parseRange(left)
|
||||
rightStart, rightEnd := parseRange(right)
|
||||
return leftStart <= rightEnd && rightStart <= leftEnd
|
||||
}
|
||||
|
||||
func NormalizePortWhitelist(items []PortWhitelist) []PortWhitelist {
|
||||
ports := make([]PortWhitelist, 0, len(items))
|
||||
for _, item := range items {
|
||||
|
||||
@@ -160,12 +160,6 @@ export namespace Firewall {
|
||||
observedInstanceKey?: string;
|
||||
}
|
||||
|
||||
export interface RuntimeUsage {
|
||||
used: boolean;
|
||||
usedBy?: string[];
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface PositionRange {
|
||||
min: number;
|
||||
max: number;
|
||||
@@ -179,7 +173,6 @@ export namespace Firewall {
|
||||
desired?: DesiredRule;
|
||||
state: InventoryState;
|
||||
match: InventoryMatch;
|
||||
usage?: RuntimeUsage;
|
||||
}
|
||||
|
||||
export type ScopeNoticeCode =
|
||||
@@ -370,11 +363,6 @@ export namespace Firewall {
|
||||
rule: Rule;
|
||||
}
|
||||
|
||||
export interface ReorderRequest {
|
||||
targetPosition?: number;
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
export interface DockerGuardBase {
|
||||
name: string;
|
||||
version: string;
|
||||
|
||||
@@ -72,26 +72,12 @@ export const updateFirewallRule = (uuid: string, request: Firewall.UpdateRequest
|
||||
return http.post('/hosts/firewall/rules/update', { ...request, uuid }, TimeoutEnum.T_60S);
|
||||
};
|
||||
|
||||
export const reorderFirewallRule = (uuid: string, request: Firewall.ReorderRequest) => {
|
||||
return http.post('/hosts/firewall/rules/reorder', { ...request, uuid }, TimeoutEnum.T_60S);
|
||||
};
|
||||
|
||||
export const loadDockerPortGuard = () =>
|
||||
http.get<Firewall.DockerGuardList>('/hosts/firewall/docker/ports', {}, { timeout: TimeoutEnum.T_40S });
|
||||
|
||||
export const loadDockerPublishedPorts = () =>
|
||||
http.get<Firewall.DockerGuardContainer[]>('/hosts/firewall/docker/endpoints', {}, { timeout: TimeoutEnum.T_40S });
|
||||
|
||||
export const syncDockerPortGuard = () =>
|
||||
http.postWithConfig(
|
||||
'/hosts/firewall/docker/sync',
|
||||
{},
|
||||
{
|
||||
timeout: TimeoutEnum.T_60S,
|
||||
skipErrorMessage: true,
|
||||
},
|
||||
);
|
||||
|
||||
export const operateDockerPortGuard = (operation: 'initialize' | 'bind' | 'unbind', taskID?: string) =>
|
||||
http.postWithConfig<Firewall.FilterChainOperationResult>(
|
||||
'/hosts/firewall/docker/operate',
|
||||
|
||||
@@ -4097,10 +4097,8 @@ const message = {
|
||||
batchRuleLimit: 'A maximum of {0} rules can be created at a time',
|
||||
resolution_adopt: 'Take over management',
|
||||
adoptRuleConfirm: 'After takeover, 1Panel can maintain and delete this existing rule. Continue?',
|
||||
plan_equivalent_external_rule:
|
||||
'An identical external rule already exists. Take it over instead of creating a duplicate.',
|
||||
plan_multiple_equivalent_external_rules: 'Multiple identical external rules exist. Select one to take over.',
|
||||
plan_equivalent_managed_rule: 'An identical rule is already managed by 1Panel. No duplicate is needed.',
|
||||
plan_exact_rule_conflict:
|
||||
'A rule with identical matching conditions and priority has an opposing allow or deny action.',
|
||||
allRulesAlreadyExist: 'All {0} checked rules already exist. There are no new rules to create.',
|
||||
ruleCheckResult: 'Rule check results',
|
||||
ruleCheckStatus_creatable: 'Creatable',
|
||||
@@ -4108,7 +4106,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Error',
|
||||
ruleCheckExistingHelper: 'An identical rule already exists and will be skipped.',
|
||||
ruleCheckReadyHelper: 'The check passed. This rule can be created.',
|
||||
ruleCheckExternalExists: 'An identical external rule already exists and will be skipped automatically.',
|
||||
ruleCheckBlockedHelper: 'Rules with errors cannot be submitted. Go back, edit them, and check again.',
|
||||
plan_managed_rule_drifted:
|
||||
'The 1Panel management record differs from the live firewall rule. Check the system rule.',
|
||||
@@ -4119,7 +4116,6 @@ const message = {
|
||||
plan_protected_rule: 'This rule is protected and cannot be taken over, changed, or deleted.',
|
||||
plan_blocked: 'This rule cannot be applied safely. Refresh the rules and try again.',
|
||||
scopeDefaultMismatch: 'The system default zone is {0}; this page manages only the public zone.',
|
||||
scopeInactive: 'The managed scope is inactive. New rules may not affect current traffic.',
|
||||
scopeMissing: 'Managed scope {0} is missing and will be created safely when the first rule is applied.',
|
||||
scopeUnmanagedActive: 'Other active scopes were detected: {0}. 1Panel will not modify their rules.',
|
||||
scopeRuntimeMismatch: 'The active and permanent firewalld configurations differ. Restart the firewall.',
|
||||
@@ -4173,13 +4169,11 @@ const message = {
|
||||
managedOnlyInTarget: 'The managed rule exists only in the target firewall.',
|
||||
managedRuntimeCannotRemove: 'The managed runtime rule cannot be removed safely.',
|
||||
managedOrderBlocked: 'Managed rules cannot be reordered across external, unrecognized, or protected rules.',
|
||||
mayBlockManagement: 'The rule may block the current management connection.',
|
||||
missingFromTarget: 'The rule is missing from the target firewall.',
|
||||
targetDiffers: 'The target rule differs from the database policy.',
|
||||
alreadyExistsInTarget: 'The rule already exists in the target firewall.',
|
||||
onlyInTarget: 'The rule exists only in the target firewall.',
|
||||
stale: 'The firewall rule state is outdated. Refresh and try again.',
|
||||
lockoutRisk: 'This firewall change may block management access.',
|
||||
protectedRule: 'This protected firewall rule cannot be modified.',
|
||||
dockerAcceptReadOnly:
|
||||
'This ACCEPT rule is read-only and will be preserved while other rules are synchronized. To remove it, delete it manually on the host.',
|
||||
@@ -4228,7 +4222,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'No active Docker forwarding rule or proxy process was found for this port. Start or restart the container, then refresh. If the issue persists, check the Docker network configuration.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Access path pending',
|
||||
dockerInputPolicyNotEffective:
|
||||
'The host receives this port directly, so the existing container port protection rule does not apply. Configure it in the host firewall instead.',
|
||||
dockerInputUseHostFirewall: 'Configure access for this port in the host firewall.',
|
||||
@@ -4301,7 +4294,7 @@ const message = {
|
||||
'Unbind - When unbound, all added firewall rules will become invalid. Proceed with caution. Confirm?',
|
||||
portWhiteList: 'Port allowlist',
|
||||
portWhiteListAlter:
|
||||
'Saving does not change the current firewall rules immediately. New ports are opened the next time the firewall is initialized or started. To close a removed port, delete its existing rule manually from the rule list.',
|
||||
'Whitelist changes take effect immediately when saved. Added ports are allowed automatically; removing a port only removes whitelist protection. To close it, delete its allow rule from the rule list.',
|
||||
portWhiteListHelper: 'Supports IPv4/IPv6, TCP/UDP, single ports, and port ranges such as 8000-8100.',
|
||||
chain: 'Chain',
|
||||
sourceIP: 'Source IP',
|
||||
|
||||
@@ -4143,10 +4143,8 @@ const message = {
|
||||
batchRuleLimit: 'Se pueden crear como máximo {0} reglas a la vez',
|
||||
resolution_adopt: 'Asumir la gestión',
|
||||
adoptRuleConfirm: 'Después de asumirla, 1Panel podrá mantener y eliminar esta regla existente. ¿Continuar?',
|
||||
plan_equivalent_external_rule: 'Ya existe una regla externa idéntica. Puedes asumir su gestión sin duplicarla.',
|
||||
plan_multiple_equivalent_external_rules:
|
||||
'Existen varias reglas externas idénticas. Selecciona una para gestionarla.',
|
||||
plan_equivalent_managed_rule: '1Panel ya gestiona una regla idéntica. No es necesario duplicarla.',
|
||||
plan_exact_rule_conflict:
|
||||
'Ya existe una regla con las mismas condiciones y prioridad, pero con una acción opuesta de permitir o denegar.',
|
||||
allRulesAlreadyExist: 'Las {0} reglas comprobadas ya existen. No hay reglas nuevas que crear.',
|
||||
ruleCheckResult: 'Resultados de la comprobación de reglas',
|
||||
ruleCheckStatus_creatable: 'Se puede crear',
|
||||
@@ -4154,7 +4152,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Error',
|
||||
ruleCheckExistingHelper: 'Ya existe una regla idéntica y se omitirá.',
|
||||
ruleCheckReadyHelper: 'La comprobación se superó. Esta regla se puede crear.',
|
||||
ruleCheckExternalExists: 'Ya existe una regla externa idéntica y se omitirá automáticamente.',
|
||||
ruleCheckBlockedHelper:
|
||||
'Las reglas con errores no se pueden enviar. Vuelve, modifícalas y compruébalas de nuevo.',
|
||||
plan_managed_rule_drifted:
|
||||
@@ -4165,7 +4162,6 @@ const message = {
|
||||
plan_protected_rule: 'Esta regla está protegida y no se puede asumir, modificar ni eliminar.',
|
||||
plan_blocked: 'La regla no puede aplicarse de forma segura. Actualiza la lista e inténtalo de nuevo.',
|
||||
scopeDefaultMismatch: 'La zona predeterminada es {0}; esta página solo gestiona la zona public.',
|
||||
scopeInactive: 'El ámbito gestionado está inactivo. Las reglas nuevas podrían no afectar al tráfico actual.',
|
||||
scopeMissing: 'Falta el ámbito gestionado {0}; se creará de forma segura al aplicar la primera regla.',
|
||||
scopeUnmanagedActive: 'Se detectaron otros ámbitos activos: {0}. 1Panel no modificará sus reglas.',
|
||||
scopeRuntimeMismatch:
|
||||
@@ -4223,13 +4219,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'La regla activa gestionada no se puede eliminar de forma segura.',
|
||||
managedOrderBlocked:
|
||||
'Las reglas gestionadas no se pueden reordenar por encima de reglas externas, no reconocidas o protegidas.',
|
||||
mayBlockManagement: 'La regla puede bloquear la conexión de administración actual.',
|
||||
missingFromTarget: 'La regla no existe en el firewall de destino.',
|
||||
targetDiffers: 'La regla de destino difiere de la política de la base de datos.',
|
||||
alreadyExistsInTarget: 'La regla ya existe en el firewall de destino.',
|
||||
onlyInTarget: 'La regla solo existe en el firewall de destino.',
|
||||
stale: 'El estado de la regla está desactualizado. Actualiza e inténtalo de nuevo.',
|
||||
lockoutRisk: 'Este cambio puede bloquear el acceso de administración.',
|
||||
protectedRule: 'Esta regla protegida del firewall no se puede modificar.',
|
||||
dockerAcceptReadOnly:
|
||||
'Esta regla ACCEPT es de solo lectura y se conservará al sincronizar las demás reglas. Para eliminarla, bórrela manualmente en el host.',
|
||||
@@ -4278,7 +4272,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'No se encontró una regla de reenvío de Docker activa ni un proceso proxy para este puerto. Inicia o reinicia el contenedor y actualiza la página. Si continúa, comprueba la red de Docker.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Ruta de acceso pendiente',
|
||||
dockerInputPolicyNotEffective:
|
||||
'El host recibe este puerto directamente, por lo que la regla de protección del puerto del contenedor no se aplica. Configúralo en el firewall del host.',
|
||||
dockerInputUseHostFirewall: 'Configure el acceso a este puerto en el firewall del host.',
|
||||
@@ -4355,7 +4348,7 @@ const message = {
|
||||
'Desvincular: al desvincular, todas las reglas de firewall agregadas se volverán inválidas. Proceda con precaución. ¿Confirmar?',
|
||||
portWhiteList: 'Lista blanca de puertos',
|
||||
portWhiteListAlter:
|
||||
'Guardar no cambia inmediatamente las reglas actuales del firewall. Los puertos nuevos se abrirán la próxima vez que se inicialice o inicie el firewall. Para cerrar un puerto eliminado, borre manualmente su regla existente en la lista de reglas.',
|
||||
'Los cambios se aplican al guardar. Los puertos añadidos se permiten automáticamente; quitar un puerto solo elimina su protección. Para cerrarlo, elimine su regla de permiso en la lista de reglas.',
|
||||
portWhiteListHelper: 'Admite IPv4/IPv6, TCP/UDP, puertos individuales y rangos como 8000-8100.',
|
||||
chain: 'Cadena',
|
||||
sourceIP: 'IP de Origen',
|
||||
|
||||
@@ -4056,9 +4056,7 @@ const message = {
|
||||
batchRuleLimit: 'در هر بار حداکثر میتوان {0} قانون ایجاد کرد',
|
||||
resolution_adopt: 'واگذاری مدیریت',
|
||||
adoptRuleConfirm: 'پس از واگذاری، 1Panel میتواند این قانون موجود را نگهداری و حذف کند. ادامه میدهید؟',
|
||||
plan_equivalent_external_rule: 'یک قانون خارجی یکسان وجود دارد. بهجای ایجاد تکراری، مدیریت آن را واگذار کنید.',
|
||||
plan_multiple_equivalent_external_rules: 'چند قانون خارجی یکسان وجود دارد. یکی را برای مدیریت انتخاب کنید.',
|
||||
plan_equivalent_managed_rule: 'یک قانون یکسان از قبل توسط 1Panel مدیریت میشود و نیازی به تکرار نیست.',
|
||||
plan_exact_rule_conflict: 'قانونی با شرایط تطبیق و اولویت یکسان، اما با اقدام مخالفِ اجازه یا رد وجود دارد.',
|
||||
allRulesAlreadyExist: 'هر {0} قانون بررسیشده از قبل وجود دارند. قانون جدیدی برای ایجاد وجود ندارد.',
|
||||
ruleCheckResult: 'نتایج بررسی قوانین',
|
||||
ruleCheckStatus_creatable: 'قابل ایجاد',
|
||||
@@ -4066,7 +4064,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'خطا',
|
||||
ruleCheckExistingHelper: 'یک قانون یکسان از قبل وجود دارد و نادیده گرفته خواهد شد.',
|
||||
ruleCheckReadyHelper: 'بررسی با موفقیت انجام شد. این قانون قابل ایجاد است.',
|
||||
ruleCheckExternalExists: 'یک قانون خارجی یکسان از قبل وجود دارد و بهصورت خودکار نادیده گرفته میشود.',
|
||||
ruleCheckBlockedHelper: 'قوانین دارای خطا قابل ارسال نیستند. بازگردید، آنها را ویرایش و دوباره بررسی کنید.',
|
||||
plan_managed_rule_drifted: 'قانون مدیریتشده با دیوارهٔ آتش فعال یکسان نیست. ابتدا ناهمگامی را رفع کنید.',
|
||||
plan_opaque_rule_in_target_scope: 'در محدودهٔ هدف قانونی وجود دارد که تحلیل امن آن ممکن نیست. عملیات متوقف شد.',
|
||||
@@ -4074,7 +4071,6 @@ const message = {
|
||||
plan_protected_rule: 'این قانون محافظتشده است و نمیتوان آن را مدیریت، تغییر یا حذف کرد.',
|
||||
plan_blocked: 'این قانون با ایمنی قابل اعمال نیست. فهرست را تازهسازی و دوباره تلاش کنید.',
|
||||
scopeDefaultMismatch: 'ناحیهٔ پیشفرض سامانه {0} است؛ این صفحه فقط ناحیهٔ public را مدیریت میکند.',
|
||||
scopeInactive: 'محدودهٔ مدیریتشده فعال نیست. قوانین جدید ممکن است بر ترافیک فعلی اثر نگذارند.',
|
||||
scopeMissing: 'محدودهٔ مدیریتشدهٔ {0} وجود ندارد و هنگام اعمال نخستین قانون بهصورت امن ایجاد میشود.',
|
||||
scopeUnmanagedActive: 'محدودههای فعال دیگری یافت شد: {0}. 1Panel قوانین آنها را تغییر نمیدهد.',
|
||||
scopeRuntimeMismatch: 'پیکربندیهای فعال و دائمی firewalld متفاوتاند. دیواره آتش را مجدداً راهاندازی کنید.',
|
||||
@@ -4129,13 +4125,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'قانون فعال مدیریتشده را نمیتوان با ایمنی حذف کرد.',
|
||||
managedOrderBlocked:
|
||||
'قوانین مدیریتشده را نمیتوان از میان قوانین خارجی، ناشناخته یا محافظتشده جابهجا کرد.',
|
||||
mayBlockManagement: 'این قانون ممکن است اتصال مدیریتی فعلی را مسدود کند.',
|
||||
missingFromTarget: 'این قانون در فایروال مقصد وجود ندارد.',
|
||||
targetDiffers: 'قانون مقصد با سیاست پایگاه داده متفاوت است.',
|
||||
alreadyExistsInTarget: 'این قانون از قبل در فایروال مقصد وجود دارد.',
|
||||
onlyInTarget: 'این قانون فقط در فایروال مقصد وجود دارد.',
|
||||
stale: 'وضعیت قانون فایروال قدیمی است. صفحه را تازه کنید و دوباره تلاش کنید.',
|
||||
lockoutRisk: 'این تغییر ممکن است دسترسی مدیریتی را مسدود کند.',
|
||||
protectedRule: 'این قانون محافظتشدهٔ فایروال قابل تغییر نیست.',
|
||||
dockerAcceptReadOnly:
|
||||
'این قانون ACCEPT فقط خواندنی است و هنگام همگامسازی سایر قوانین حفظ میشود. برای حذف آن، قانون را بهصورت دستی از میزبان پاک کنید.',
|
||||
@@ -4186,7 +4180,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'برای این پورت قانون هدایت فعال داکر یا پردازش پراکسی یافت نشد. کانتینر را راهاندازی یا مجدداً راهاندازی کرده و صفحه را تازهسازی کنید. اگر مشکل ادامه داشت، شبکه داکر را بررسی کنید.',
|
||||
},
|
||||
dockerTrafficPathPending: 'مسیر دسترسی نامشخص',
|
||||
dockerInputPolicyNotEffective:
|
||||
'این پورت مستقیماً توسط میزبان دریافت میشود، بنابراین قانون فعلی محافظت پورت کانتینر اعمال نمیشود. آن را در فایروال میزبان تنظیم کنید.',
|
||||
dockerInputUseHostFirewall: 'دسترسی این پورت را در فایروال میزبان پیکربندی کنید.',
|
||||
@@ -4258,7 +4251,7 @@ const message = {
|
||||
'قطع اتصال - در صورت قطع اتصال، همه قوانین دیواره آتش اضافه شده بیاثر میشوند. با احتیاط ادامه دهید. تأیید میکنید؟',
|
||||
portWhiteList: 'لیست سفید پورت',
|
||||
portWhiteListAlter:
|
||||
'ذخیرهسازی قوانین فعلی دیواره آتش را فوراً تغییر نمیدهد. پورتهای جدید هنگام مقداردهی اولیه یا راهاندازی بعدی باز میشوند. برای بستن پورتی که حذف کردهاید، قانون موجود آن را بهصورت دستی از فهرست قوانین حذف کنید.',
|
||||
'تغییرات فهرست مجاز بلافاصله پس از ذخیره اعمال میشوند. پورتهای جدید خودکار مجاز میشوند؛ حذف پورت فقط حفاظت آن را برمیدارد. برای بستن پورت، قانون اجازه آن را از فهرست قوانین حذف کنید.',
|
||||
portWhiteListHelper: 'از IPv4/IPv6، TCP/UDP، پورت تکی و بازههایی مانند 8000-8100 پشتیبانی میکند.',
|
||||
chain: 'زنجیره',
|
||||
sourceIP: 'IP مبدأ',
|
||||
|
||||
@@ -4081,10 +4081,7 @@ const message = {
|
||||
batchRuleLimit: '一度に作成できるルールは最大 {0} 件です',
|
||||
resolution_adopt: '管理対象にする',
|
||||
adoptRuleConfirm: '管理対象にすると、1Panel がこの既存ルールの保守と削除を行えるようになります。続行しますか?',
|
||||
plan_equivalent_external_rule: '同じ外部ルールが既にあります。重複作成せず管理対象にできます。',
|
||||
plan_multiple_equivalent_external_rules:
|
||||
'同じ外部ルールが複数あります。管理対象にするルールを選択してください。',
|
||||
plan_equivalent_managed_rule: '同じルールは既に 1Panel の管理対象です。重複作成は不要です。',
|
||||
plan_exact_rule_conflict: '一致条件と優先度が同じで、許可・拒否の動作が逆のルールが存在します。',
|
||||
allRulesAlreadyExist: '確認した {0} 件のルールはすべて既に存在します。新しく作成するルールはありません。',
|
||||
ruleCheckResult: 'ルール確認結果',
|
||||
ruleCheckStatus_creatable: '作成可能',
|
||||
@@ -4092,7 +4089,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'エラー',
|
||||
ruleCheckExistingHelper: '同じルールが既に存在するため、今回はスキップします。',
|
||||
ruleCheckReadyHelper: '確認に合格しました。このルールは作成できます。',
|
||||
ruleCheckExternalExists: '同じ外部ルールが既に存在するため、自動的にスキップされます。',
|
||||
ruleCheckBlockedHelper: 'エラーのあるルールは送信できません。戻って修正し、もう一度確認してください。',
|
||||
plan_managed_rule_drifted:
|
||||
'管理対象ルールが実際のファイアウォールと一致しません。先に不整合を解消してください。',
|
||||
@@ -4101,7 +4097,6 @@ const message = {
|
||||
plan_protected_rule: 'このルールは保護されており、管理対象化、変更、削除はできません。',
|
||||
plan_blocked: 'このルールは安全に適用できません。ルールを更新して再試行してください。',
|
||||
scopeDefaultMismatch: 'システムの既定 zone は {0} です。このページでは public zone のみ管理します。',
|
||||
scopeInactive: '管理対象の範囲が有効ではありません。新しいルールが現在の通信に適用されない場合があります。',
|
||||
scopeMissing: '管理対象スコープ {0} がありません。最初のルール適用時に安全に作成されます。',
|
||||
scopeUnmanagedActive: '他の有効な範囲が見つかりました:{0}。1Panel はそのルールを変更しません。',
|
||||
scopeRuntimeMismatch:
|
||||
@@ -4159,13 +4154,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: '管理対象の実行中ルールを安全に削除できません。',
|
||||
managedOrderBlocked:
|
||||
'外部、認識不能、または保護されたルールを越えて管理対象ルールを並べ替えることはできません。',
|
||||
mayBlockManagement: 'このルールにより現在の管理接続が遮断される可能性があります。',
|
||||
missingFromTarget: '対象ファイアウォールにこのルールがありません。',
|
||||
targetDiffers: '対象ルールがデータベースポリシーと異なります。',
|
||||
alreadyExistsInTarget: '対象ファイアウォールにこのルールは既に存在します。',
|
||||
onlyInTarget: 'このルールは対象ファイアウォールにのみ存在します。',
|
||||
stale: 'ファイアウォールルールの状態が古くなっています。更新して再試行してください。',
|
||||
lockoutRisk: 'この変更により管理アクセスが遮断される可能性があります。',
|
||||
protectedRule: '保護されたファイアウォールルールは変更できません。',
|
||||
dockerAcceptReadOnly:
|
||||
'この ACCEPT ルールは読み取り専用で、他のルールを同期しても保持されます。削除する場合は、ホスト上で手動で削除してください。',
|
||||
@@ -4214,7 +4207,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'このポートに有効な Docker 転送ルールまたはプロキシプロセスが見つかりません。対象のコンテナを起動または再起動してから更新してください。解決しない場合は Docker ネットワーク設定を確認してください。',
|
||||
},
|
||||
dockerTrafficPathPending: 'アクセス経路を確認中',
|
||||
dockerInputPolicyNotEffective:
|
||||
'このポートはホストが直接受信するため、既存のコンテナポート保護ルールは適用されません。ホストファイアウォールで設定してください。',
|
||||
dockerInputUseHostFirewall: 'このポートのアクセスはホストファイアウォールで設定してください。',
|
||||
@@ -4286,7 +4278,7 @@ const message = {
|
||||
'アンバインド - アンバインドすると、追加されたすべてのファイアウォールルールが無効になります。注意して操作してください。確認しますか?',
|
||||
portWhiteList: 'ポートホワイトリスト',
|
||||
portWhiteListAlter:
|
||||
'保存しても現在のファイアウォールルールはすぐに変更されません。新しいポートは、次回の初期化または起動時に許可されます。削除したポートを閉じるには、ルール一覧から既存のルールを手動で削除してください。',
|
||||
'変更は保存時に即座に反映されます。追加したポートは自動的に許可されます。削除したポートは保護のみ解除されるため、閉じるにはルール一覧から許可ルールを削除してください。',
|
||||
portWhiteListHelper: 'IPv4/IPv6、TCP/UDP、単一ポート、8000-8100 のようなポート範囲に対応します。',
|
||||
chain: 'チェーン',
|
||||
sourceIP: '送信元 IP',
|
||||
|
||||
@@ -4008,10 +4008,7 @@ const message = {
|
||||
resolution_adopt: '관리 대상으로 전환',
|
||||
adoptRuleConfirm:
|
||||
'관리 대상으로 전환하면 1Panel이 이 기존 규칙을 유지하고 삭제할 수 있습니다. 계속하시겠습니까?',
|
||||
plan_equivalent_external_rule:
|
||||
'동일한 외부 규칙이 이미 있습니다. 중복 생성 대신 관리 대상으로 전환할 수 있습니다.',
|
||||
plan_multiple_equivalent_external_rules: '동일한 외부 규칙이 여러 개 있습니다. 관리할 규칙을 선택하세요.',
|
||||
plan_equivalent_managed_rule: '동일한 규칙을 1Panel이 이미 관리하고 있습니다. 중복 생성할 필요가 없습니다.',
|
||||
plan_exact_rule_conflict: '일치 조건과 우선순위가 같지만 허용 또는 거부 동작이 반대인 규칙이 이미 있습니다.',
|
||||
allRulesAlreadyExist: '확인한 규칙 {0}개가 모두 이미 존재합니다. 새로 생성할 규칙이 없습니다.',
|
||||
ruleCheckResult: '규칙 검사 결과',
|
||||
ruleCheckStatus_creatable: '생성 가능',
|
||||
@@ -4019,7 +4016,6 @@ const message = {
|
||||
ruleCheckStatus_error: '오류',
|
||||
ruleCheckExistingHelper: '동일한 규칙이 이미 존재하므로 이번 작업에서는 건너뜁니다.',
|
||||
ruleCheckReadyHelper: '검사를 통과했습니다. 이 규칙을 생성할 수 있습니다.',
|
||||
ruleCheckExternalExists: '동일한 외부 규칙이 이미 존재하며 자동으로 건너뜁니다.',
|
||||
ruleCheckBlockedHelper: '오류가 있는 규칙은 제출할 수 없습니다. 돌아가서 수정한 후 다시 검사하세요.',
|
||||
plan_managed_rule_drifted: '관리 규칙이 실제 방화벽과 일치하지 않습니다. 먼저 불일치를 해결하세요.',
|
||||
plan_opaque_rule_in_target_scope: '대상 범위에 안전하게 분석할 수 없는 규칙이 있어 작업을 중지했습니다.',
|
||||
@@ -4027,7 +4023,6 @@ const message = {
|
||||
plan_protected_rule: '이 규칙은 보호되어 관리 전환, 변경 또는 삭제할 수 없습니다.',
|
||||
plan_blocked: '이 규칙을 안전하게 적용할 수 없습니다. 목록을 새로 고친 후 다시 시도하세요.',
|
||||
scopeDefaultMismatch: '시스템 기본 zone은 {0}이며 이 페이지는 public zone만 관리합니다.',
|
||||
scopeInactive: '관리 범위가 비활성 상태입니다. 새 규칙이 현재 트래픽에 적용되지 않을 수 있습니다.',
|
||||
scopeMissing: '관리 범위 {0}이(가) 없으며 첫 규칙을 적용할 때 안전하게 생성됩니다.',
|
||||
scopeUnmanagedActive: '다른 활성 범위가 감지되었습니다: {0}. 1Panel은 해당 규칙을 변경하지 않습니다.',
|
||||
scopeRuntimeMismatch: 'firewalld의 실행 중 구성과 영구 구성이 다릅니다. 방화벽을 재시작하세요.',
|
||||
@@ -4081,13 +4076,11 @@ const message = {
|
||||
managedOnlyInTarget: '관리 규칙이 대상 방화벽에만 존재합니다.',
|
||||
managedRuntimeCannotRemove: '관리 중인 런타임 규칙을 안전하게 삭제할 수 없습니다.',
|
||||
managedOrderBlocked: '외부, 인식할 수 없거나 보호된 규칙을 넘어 관리 규칙의 순서를 변경할 수 없습니다.',
|
||||
mayBlockManagement: '이 규칙은 현재 관리 연결을 차단할 수 있습니다.',
|
||||
missingFromTarget: '대상 방화벽에 이 규칙이 없습니다.',
|
||||
targetDiffers: '대상 규칙이 데이터베이스 정책과 다릅니다.',
|
||||
alreadyExistsInTarget: '대상 방화벽에 이 규칙이 이미 존재합니다.',
|
||||
onlyInTarget: '이 규칙은 대상 방화벽에만 존재합니다.',
|
||||
stale: '방화벽 규칙 상태가 오래되었습니다. 새로 고친 후 다시 시도하세요.',
|
||||
lockoutRisk: '이 방화벽 변경으로 관리 접근이 차단될 수 있습니다.',
|
||||
protectedRule: '보호된 방화벽 규칙은 수정할 수 없습니다.',
|
||||
dockerAcceptReadOnly:
|
||||
'이 ACCEPT 규칙은 읽기 전용이며 다른 규칙을 동기화할 때 그대로 유지됩니다. 제거하려면 호스트에서 수동으로 삭제하세요.',
|
||||
@@ -4136,7 +4129,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'이 포트에 활성 Docker 전달 규칙이나 프록시 프로세스가 없습니다. 해당 컨테이너를 시작하거나 다시 시작한 후 새로 고침하세요. 문제가 계속되면 Docker 네트워크 설정을 확인하세요.',
|
||||
},
|
||||
dockerTrafficPathPending: '접근 경로 확인 대기',
|
||||
dockerInputPolicyNotEffective:
|
||||
'이 포트는 호스트가 직접 수신하므로 기존 컨테이너 포트 보호 규칙이 적용되지 않습니다. 호스트 방화벽에서 설정하세요.',
|
||||
dockerInputUseHostFirewall: '이 포트의 접근 규칙은 호스트 방화벽에서 설정하세요.',
|
||||
@@ -4206,7 +4198,7 @@ const message = {
|
||||
'바인딩 해제 - 바인딩 해제 시 추가된 모든 방화벽 규칙이 무효화됩니다. 주의하여 진행하세요. 확인하시겠습니까?',
|
||||
portWhiteList: '포트 화이트리스트',
|
||||
portWhiteListAlter:
|
||||
'저장해도 현재 방화벽 규칙은 즉시 변경되지 않습니다. 새 포트는 다음 초기화 또는 시작 시 허용됩니다. 제거한 포트를 닫으려면 규칙 목록에서 기존 규칙을 수동으로 삭제하세요.',
|
||||
'변경 사항은 저장 즉시 적용됩니다. 추가한 포트는 자동으로 허용됩니다. 포트를 제거하면 보호만 해제됩니다. 포트를 닫으려면 규칙 목록에서 허용 규칙을 삭제하세요.',
|
||||
portWhiteListHelper: 'IPv4/IPv6, TCP/UDP, 단일 포트 및 8000-8100과 같은 포트 범위를 지원합니다.',
|
||||
chain: '체인',
|
||||
sourceIP: '소스 IP',
|
||||
|
||||
@@ -3978,9 +3978,7 @@ const message = {
|
||||
batchRuleLimit: 'ສາມາດສ້າງກົດໄດ້ສູງສຸດ {0} ລາຍການຕໍ່ຄັ້ງ',
|
||||
resolution_adopt: 'ຮັບເຂົ້າຈັດການ',
|
||||
adoptRuleConfirm: 'ຫຼັງຈາກຮັບເຂົ້າແລ້ວ 1Panel ຈະສາມາດຮັກສາແລະລຶບກົດນີ້ໄດ້. ສືບຕໍ່ບໍ?',
|
||||
plan_equivalent_external_rule: 'ມີກົດພາຍນອກທີ່ຄືກັນແລ້ວ. ສາມາດຮັບເຂົ້າຈັດການແທນການສ້າງຊ້ຳ.',
|
||||
plan_multiple_equivalent_external_rules: 'ມີກົດພາຍນອກທີ່ຄືກັນຫຼາຍກົດ. ກະລຸນາເລືອກໜຶ່ງກົດ.',
|
||||
plan_equivalent_managed_rule: 'ກົດທີ່ຄືກັນຖືກ 1Panel ຈັດການແລ້ວ ບໍ່ຕ້ອງສ້າງຊ້ຳ.',
|
||||
plan_exact_rule_conflict: 'ມີກົດທີ່ມີເງື່ອນໄຂແລະລຳດັບຄວາມສຳຄັນຄືກັນ ແຕ່ການອະນຸຍາດຫຼືປະຕິເສດກົງກັນຂ້າມ.',
|
||||
allRulesAlreadyExist: 'ກົດທັງໝົດ {0} ລາຍການທີ່ກວດສອບມີຢູ່ແລ້ວ. ບໍ່ມີກົດໃໝ່ທີ່ຕ້ອງສ້າງ.',
|
||||
ruleCheckResult: 'ຜົນການກວດສອບກົດ',
|
||||
ruleCheckStatus_creatable: 'ສາມາດສ້າງໄດ້',
|
||||
@@ -3988,7 +3986,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'ຂໍ້ຜິດພາດ',
|
||||
ruleCheckExistingHelper: 'ມີກົດທີ່ຄືກັນຢູ່ແລ້ວ ແລະ ຈະຖືກຂ້າມ.',
|
||||
ruleCheckReadyHelper: 'ການກວດສອບຜ່ານ. ສາມາດສ້າງກົດນີ້ໄດ້.',
|
||||
ruleCheckExternalExists: 'ມີກົດພາຍນອກທີ່ຄືກັນຢູ່ແລ້ວ ແລະຈະຖືກຂ້າມອັດຕະໂນມັດ.',
|
||||
ruleCheckBlockedHelper: 'ບໍ່ສາມາດສົ່ງກົດທີ່ມີຂໍ້ຜິດພາດໄດ້. ກັບໄປແກ້ໄຂ ແລະກວດສອບໃໝ່.',
|
||||
plan_managed_rule_drifted: 'ກົດທີ່ຈັດການບໍ່ກົງກັບໄຟວໍທີ່ໃຊ້ງານ. ກະລຸນາແກ້ໄຂກ່ອນ.',
|
||||
plan_opaque_rule_in_target_scope: 'ມີກົດໃນຂອບເຂດທີ່ບໍ່ສາມາດວິເຄາະໄດ້ຢ່າງປອດໄພ. ການດຳເນີນງານຖືກຢຸດ.',
|
||||
@@ -3996,7 +3993,6 @@ const message = {
|
||||
plan_protected_rule: 'ກົດນີ້ຖືກປົກປ້ອງ ແລະບໍ່ສາມາດຮັບເຂົ້າ, ແກ້ໄຂ ຫຼືລຶບໄດ້.',
|
||||
plan_blocked: 'ບໍ່ສາມາດນຳໃຊ້ກົດນີ້ໄດ້ຢ່າງປອດໄພ. ກະລຸນາໂຫຼດໃໝ່ແລ້ວລອງອີກຄັ້ງ.',
|
||||
scopeDefaultMismatch: 'zone ຄ່າເລີ່ມຕົ້ນແມ່ນ {0}; ໜ້ານີ້ຈັດການສະເພາະ public zone.',
|
||||
scopeInactive: 'ຂອບເຂດທີ່ຈັດການບໍ່ໄດ້ເປີດໃຊ້. ກົດໃໝ່ອາດບໍ່ມີຜົນຕໍ່ການຈະລາຈອນປັດຈຸບັນ.',
|
||||
scopeMissing: 'ບໍ່ພົບຂອບເຂດຈັດການ {0}; ລະບົບຈະສ້າງຢ່າງປອດໄພເມື່ອນຳໃຊ້ກົດທຳອິດ.',
|
||||
scopeUnmanagedActive: 'ພົບຂອບເຂດອື່ນທີ່ໃຊ້ງານ: {0}. 1Panel ຈະບໍ່ແກ້ໄຂກົດເຫຼົ່ານັ້ນ.',
|
||||
scopeRuntimeMismatch: 'ການຕັ້ງຄ່າ firewalld ທີ່ກຳລັງໃຊ້ງານ ແລະ ແບບຖາວອນບໍ່ກົງກັນ. ກະລຸນາເລີ່ມຕົ້ນໄຟວໍໃໝ່.',
|
||||
@@ -4049,13 +4045,11 @@ const message = {
|
||||
managedOnlyInTarget: 'ກົດທີ່ຈັດການມີຢູ່ສະເພາະໃນໄຟວໍເປົ້າໝາຍ.',
|
||||
managedRuntimeCannotRemove: 'ບໍ່ສາມາດລຶບກົດທີ່ກຳລັງໃຊ້ງານໄດ້ຢ່າງປອດໄພ.',
|
||||
managedOrderBlocked: 'ບໍ່ສາມາດຈັດລຳດັບກົດທີ່ຈັດການຂ້າມກົດພາຍນອກ, ກົດທີ່ບໍ່ຮູ້ຈັກ ຫຼືກົດທີ່ຖືກປົກປ້ອງ.',
|
||||
mayBlockManagement: 'ກົດນີ້ອາດຂັດຂວາງການເຊື່ອມຕໍ່ຈັດການປັດຈຸບັນ.',
|
||||
missingFromTarget: 'ບໍ່ມີກົດນີ້ໃນໄຟວໍເປົ້າໝາຍ.',
|
||||
targetDiffers: 'ກົດເປົ້າໝາຍແຕກຕ່າງຈາກນະໂຍບາຍໃນຖານຂໍ້ມູນ.',
|
||||
alreadyExistsInTarget: 'ກົດນີ້ມີຢູ່ແລ້ວໃນໄຟວໍເປົ້າໝາຍ.',
|
||||
onlyInTarget: 'ກົດນີ້ມີຢູ່ສະເພາະໃນໄຟວໍເປົ້າໝາຍ.',
|
||||
stale: 'ສະຖານະກົດໄຟວໍເກົ່າແລ້ວ. ກະລຸນາໂຫຼດໃໝ່ແລ້ວລອງອີກຄັ້ງ.',
|
||||
lockoutRisk: 'ການປ່ຽນແປງນີ້ອາດຂັດຂວາງການເຂົ້າເຖິງຈັດການ.',
|
||||
protectedRule: 'ກົດໄຟວໍທີ່ຖືກປົກປ້ອງນີ້ບໍ່ສາມາດແກ້ໄຂໄດ້.',
|
||||
dockerAcceptReadOnly:
|
||||
'ກົດ ACCEPT ນີ້ເປັນແບບອ່ານຢ່າງດຽວ ແລະຈະຖືກເກັບໄວ້ເມື່ອຊິງກົດອື່ນ. ຫາກຕ້ອງການລຶບ ໃຫ້ລຶບດ້ວຍຕົນເອງໃນໂຮສ.',
|
||||
@@ -4102,7 +4096,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'ບໍ່ພົບກົດສົ່ງຕໍ່ Docker ຫຼືໂປຣເຊສ proxy ທີ່ເຮັດວຽກສຳລັບພອດນີ້. ເລີ່ມ ຫຼືເລີ່ມຄອນເທນເນີໃໝ່ ແລ້ວໂຫຼດໃໝ່. ຖ້າຍັງມີບັນຫາ ໃຫ້ກວດສອບເຄືອຂ່າຍ Docker.',
|
||||
},
|
||||
dockerTrafficPathPending: 'ລໍຖ້າກວດສອບເສັ້ນທາງ',
|
||||
dockerInputPolicyNotEffective:
|
||||
'ພອດນີ້ຖືກຮັບໂດຍໂຮສໂດຍກົງ ດັ່ງນັ້ນກົດປ້ອງກັນພອດຄອນເທນເນີຈຶ່ງບໍ່ມີຜົນ. ກະລຸນາຕັ້ງຄ່າໃນໄຟວໍຂອງໂຮສ.',
|
||||
dockerInputUseHostFirewall: 'ກະລຸນາຕັ້ງຄ່າການເຂົ້າເຖິງພອດນີ້ໃນໄຟວໍຂອງໂຮສ.',
|
||||
@@ -4170,7 +4163,7 @@ const message = {
|
||||
'ຍົກເລີກການຜູກມັດ - ເມື່ອຍົກເລີກ, ກົດລະບຽບໄຟວໍທັງໝົດຈະບໍ່ມີຜົນ. ກະລຸນາເຮັດດ້ວຍຄວາມລະມັດລະວັງ. ຢືນຢັນ?',
|
||||
portWhiteList: 'ພອດທີ່ອະນຸຍາດ',
|
||||
portWhiteListAlter:
|
||||
'ການບັນທຶກຈະບໍ່ປ່ຽນກົດໄຟວໍປັດຈຸບັນທັນທີ. ພອດໃໝ່ຈະຖືກເປີດໃນການເລີ່ມຕົ້ນຄັ້ງຕໍ່ໄປ. ເພື່ອປິດພອດທີ່ລຶບອອກ ໃຫ້ລຶບກົດທີ່ມີຢູ່ຈາກລາຍການກົດດ້ວຍຕົນເອງ.',
|
||||
'ການປ່ຽນແປງມີຜົນທັນທີເມື່ອບັນທຶກ. ພອດທີ່ເພີ່ມຈະຖືກອະນຸຍາດອັດຕະໂນມັດ; ການລຶບພອດອອກຈະຍົກເລີກພຽງການປ້ອງກັນ. ເພື່ອປິດພອດ ໃຫ້ລຶບກົດອະນຸຍາດໃນລາຍການກົດ.',
|
||||
portWhiteListHelper: 'ຮອງຮັບ IPv4/IPv6, TCP/UDP, ພອດດຽວ ແລະ ຊ່ວງພອດເຊັ່ນ 8000-8100.',
|
||||
chain: 'Chain',
|
||||
sourceIP: 'IP ຕົ້ນທາງ',
|
||||
|
||||
@@ -4164,10 +4164,8 @@ const message = {
|
||||
resolution_adopt: 'Ambil alih pengurusan',
|
||||
adoptRuleConfirm:
|
||||
'Selepas diambil alih, 1Panel boleh menyelenggara dan memadam peraturan sedia ada ini. Teruskan?',
|
||||
plan_equivalent_external_rule: 'Peraturan luaran yang sama sudah wujud. Ambil alih tanpa mencipta pendua.',
|
||||
plan_multiple_equivalent_external_rules:
|
||||
'Terdapat beberapa peraturan luaran yang sama. Pilih satu untuk diurus.',
|
||||
plan_equivalent_managed_rule: 'Peraturan yang sama sudah diurus oleh 1Panel. Pendua tidak diperlukan.',
|
||||
plan_exact_rule_conflict:
|
||||
'Peraturan dengan syarat padanan dan keutamaan yang sama mempunyai tindakan benarkan atau sekat yang bertentangan.',
|
||||
allRulesAlreadyExist: 'Kesemua {0} peraturan yang diperiksa sudah wujud. Tiada peraturan baharu untuk dicipta.',
|
||||
ruleCheckResult: 'Keputusan semakan peraturan',
|
||||
ruleCheckStatus_creatable: 'Boleh dicipta',
|
||||
@@ -4175,7 +4173,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Ralat',
|
||||
ruleCheckExistingHelper: 'Peraturan yang sama sudah wujud dan akan dilangkau.',
|
||||
ruleCheckReadyHelper: 'Semakan lulus. Peraturan ini boleh dicipta.',
|
||||
ruleCheckExternalExists: 'Peraturan luaran yang sama sudah wujud dan akan dilangkau secara automatik.',
|
||||
ruleCheckBlockedHelper: 'Peraturan yang mempunyai ralat tidak boleh dihantar. Kembali, edit dan semak semula.',
|
||||
plan_managed_rule_drifted:
|
||||
'Peraturan terurus tidak sepadan dengan tembok api aktif. Selesaikan perbezaan dahulu.',
|
||||
@@ -4185,7 +4182,6 @@ const message = {
|
||||
plan_protected_rule: 'Peraturan ini dilindungi dan tidak boleh diambil alih, diubah atau dipadam.',
|
||||
plan_blocked: 'Peraturan ini tidak dapat digunakan dengan selamat. Muat semula senarai dan cuba lagi.',
|
||||
scopeDefaultMismatch: 'Zon lalai sistem ialah {0}; halaman ini hanya mengurus zon public.',
|
||||
scopeInactive: 'Skop terurus tidak aktif. Peraturan baharu mungkin tidak mempengaruhi trafik semasa.',
|
||||
scopeMissing: 'Skop terurus {0} tiada dan akan dicipta dengan selamat apabila peraturan pertama digunakan.',
|
||||
scopeUnmanagedActive: 'Skop aktif lain dikesan: {0}. 1Panel tidak akan mengubah peraturannya.',
|
||||
scopeRuntimeMismatch: 'Konfigurasi firewalld aktif dan kekal tidak sepadan. Mulakan semula firewall.',
|
||||
@@ -4243,13 +4239,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'Peraturan aktif terurus tidak dapat dipadam dengan selamat.',
|
||||
managedOrderBlocked:
|
||||
'Peraturan terurus tidak boleh disusun semula merentasi peraturan luaran, tidak dikenali atau dilindungi.',
|
||||
mayBlockManagement: 'Peraturan mungkin menyekat sambungan pengurusan semasa.',
|
||||
missingFromTarget: 'Peraturan tiada dalam tembok api sasaran.',
|
||||
targetDiffers: 'Peraturan sasaran berbeza daripada dasar pangkalan data.',
|
||||
alreadyExistsInTarget: 'Peraturan sudah wujud dalam tembok api sasaran.',
|
||||
onlyInTarget: 'Peraturan hanya wujud dalam tembok api sasaran.',
|
||||
stale: 'Keadaan peraturan tembok api sudah lapuk. Muat semula dan cuba lagi.',
|
||||
lockoutRisk: 'Perubahan ini mungkin menyekat akses pengurusan.',
|
||||
protectedRule: 'Peraturan tembok api yang dilindungi ini tidak boleh diubah.',
|
||||
dockerAcceptReadOnly:
|
||||
'Peraturan ACCEPT ini adalah baca sahaja dan akan dikekalkan semasa peraturan lain disegerakkan. Untuk membuangnya, padam secara manual pada hos.',
|
||||
@@ -4297,7 +4291,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'Tiada peraturan pemajuan Docker aktif atau proses proksi ditemui untuk port ini. Mulakan atau mulakan semula bekas, kemudian muat semula. Jika masalah berterusan, semak konfigurasi rangkaian Docker.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Laluan akses belum ditentukan',
|
||||
dockerInputPolicyNotEffective:
|
||||
'Port ini diterima terus oleh hos, jadi peraturan perlindungan port bekas sedia ada tidak digunakan. Tetapkannya dalam firewall hos.',
|
||||
dockerInputUseHostFirewall: 'Konfigurasikan akses port ini dalam tembok api hos.',
|
||||
@@ -4368,7 +4361,7 @@ const message = {
|
||||
'Nyahikat - Apabila tidak terikat, semua peraturan firewall yang ditambah akan menjadi tidak sah. Teruskan dengan berhati-hati. Sahkan?',
|
||||
portWhiteList: 'Senarai putih port',
|
||||
portWhiteListAlter:
|
||||
'Menyimpan tidak mengubah peraturan firewall semasa dengan serta-merta. Port baharu akan dibuka pada pemulaan atau pengaktifan seterusnya. Untuk menutup port yang dialih keluar, padam peraturan sedia ada secara manual daripada senarai peraturan.',
|
||||
'Perubahan berkuat kuasa serta-merta apabila disimpan. Port baharu dibenarkan secara automatik; mengalih keluar port hanya membuang perlindungannya. Untuk menutupnya, padam peraturan kebenaran dalam senarai peraturan.',
|
||||
portWhiteListHelper: 'Menyokong IPv4/IPv6, TCP/UDP, port tunggal dan julat seperti 8000-8100.',
|
||||
chain: 'Rantai',
|
||||
sourceIP: 'IP Sumber',
|
||||
|
||||
@@ -4182,11 +4182,8 @@ const message = {
|
||||
batchRuleLimit: 'É possível criar no máximo {0} regras por vez',
|
||||
resolution_adopt: 'Assumir gerenciamento',
|
||||
adoptRuleConfirm: 'Depois disso, o 1Panel poderá manter e excluir esta regra existente. Continuar?',
|
||||
plan_equivalent_external_rule:
|
||||
'Já existe uma regra externa idêntica. Assuma seu gerenciamento sem criar uma duplicata.',
|
||||
plan_multiple_equivalent_external_rules:
|
||||
'Existem várias regras externas idênticas. Selecione uma para gerenciar.',
|
||||
plan_equivalent_managed_rule: 'Uma regra idêntica já é gerenciada pelo 1Panel. Não é necessário duplicá-la.',
|
||||
plan_exact_rule_conflict:
|
||||
'Já existe uma regra com as mesmas condições e prioridade, mas com uma ação oposta de permitir ou negar.',
|
||||
allRulesAlreadyExist: 'Todas as {0} regras verificadas já existem. Não há novas regras para criar.',
|
||||
ruleCheckResult: 'Resultados da verificação de regras',
|
||||
ruleCheckStatus_creatable: 'Pode ser criada',
|
||||
@@ -4194,7 +4191,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Erro',
|
||||
ruleCheckExistingHelper: 'Uma regra idêntica já existe e será ignorada.',
|
||||
ruleCheckReadyHelper: 'A verificação foi aprovada. Esta regra pode ser criada.',
|
||||
ruleCheckExternalExists: 'Uma regra externa idêntica já existe e será ignorada automaticamente.',
|
||||
ruleCheckBlockedHelper: 'Regras com erros não podem ser enviadas. Volte, edite-as e verifique novamente.',
|
||||
plan_managed_rule_drifted:
|
||||
'A regra gerenciada não corresponde ao firewall ativo. Resolva a divergência primeiro.',
|
||||
@@ -4204,7 +4200,6 @@ const message = {
|
||||
plan_protected_rule: 'Esta regra está protegida e não pode ser assumida, alterada ou excluída.',
|
||||
plan_blocked: 'A regra não pode ser aplicada com segurança. Atualize a lista e tente novamente.',
|
||||
scopeDefaultMismatch: 'A zona padrão do sistema é {0}; esta página gerencia apenas a zona public.',
|
||||
scopeInactive: 'O escopo gerenciado está inativo. Novas regras podem não afetar o tráfego atual.',
|
||||
scopeMissing: 'O escopo gerenciado {0} não existe e será criado com segurança ao aplicar a primeira regra.',
|
||||
scopeUnmanagedActive: 'Outros escopos ativos foram detectados: {0}. O 1Panel não modificará suas regras.',
|
||||
scopeRuntimeMismatch: 'As configurações ativa e permanente do firewalld não coincidem. Reinicie o firewall.',
|
||||
@@ -4261,13 +4256,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'A regra ativa gerenciada não pode ser removida com segurança.',
|
||||
managedOrderBlocked:
|
||||
'As regras gerenciadas não podem ser reordenadas através de regras externas, não reconhecidas ou protegidas.',
|
||||
mayBlockManagement: 'A regra pode bloquear a conexão de gerenciamento atual.',
|
||||
missingFromTarget: 'A regra não existe no firewall de destino.',
|
||||
targetDiffers: 'A regra de destino difere da política do banco de dados.',
|
||||
alreadyExistsInTarget: 'A regra já existe no firewall de destino.',
|
||||
onlyInTarget: 'A regra existe apenas no firewall de destino.',
|
||||
stale: 'O estado da regra está desatualizado. Atualize e tente novamente.',
|
||||
lockoutRisk: 'Esta alteração pode bloquear o acesso de gerenciamento.',
|
||||
protectedRule: 'Esta regra protegida do firewall não pode ser modificada.',
|
||||
dockerAcceptReadOnly:
|
||||
'Esta regra ACCEPT é somente leitura e será preservada durante a sincronização das outras regras. Para removê-la, exclua-a manualmente no host.',
|
||||
@@ -4317,7 +4310,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'Nenhuma regra de encaminhamento do Docker ativa ou processo proxy foi encontrado para esta porta. Inicie ou reinicie o contêiner e atualize a página. Se o problema continuar, verifique a rede do Docker.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Caminho de acesso pendente',
|
||||
dockerInputPolicyNotEffective:
|
||||
'O host recebe esta porta diretamente, portanto a regra de proteção da porta do contêiner não se aplica. Configure-a no firewall do host.',
|
||||
dockerInputUseHostFirewall: 'Configure o acesso a esta porta no firewall do host.',
|
||||
@@ -4391,7 +4383,7 @@ const message = {
|
||||
'Desvincular - Quando desvinculado, todas as regras de firewall adicionadas se tornarão inválidas. Prossiga com cautela. Confirmar?',
|
||||
portWhiteList: 'Lista branca de portas',
|
||||
portWhiteListAlter:
|
||||
'Salvar não altera imediatamente as regras atuais do firewall. Novas portas serão abertas na próxima inicialização ou ativação. Para fechar uma porta removida, exclua manualmente a regra existente na lista de regras.',
|
||||
'As alterações entram em vigor ao salvar. As portas adicionadas são liberadas automaticamente; remover uma porta apenas retira sua proteção. Para fechá-la, exclua a regra de permissão na lista de regras.',
|
||||
portWhiteListHelper: 'Suporta IPv4/IPv6, TCP/UDP, portas únicas e intervalos como 8000-8100.',
|
||||
chain: 'Cadeia',
|
||||
sourceIP: 'IP de Origem',
|
||||
|
||||
@@ -4149,11 +4149,8 @@ const message = {
|
||||
batchRuleLimit: 'За один раз можно создать не более {0} правил',
|
||||
resolution_adopt: 'Взять под управление',
|
||||
adoptRuleConfirm: 'После этого 1Panel сможет обслуживать и удалять существующее правило. Продолжить?',
|
||||
plan_equivalent_external_rule:
|
||||
'Такое внешнее правило уже существует. Возьмите его под управление без создания дубликата.',
|
||||
plan_multiple_equivalent_external_rules:
|
||||
'Существует несколько одинаковых внешних правил. Выберите одно для управления.',
|
||||
plan_equivalent_managed_rule: 'Такое правило уже управляется 1Panel. Дубликат не требуется.',
|
||||
plan_exact_rule_conflict:
|
||||
'Уже существует правило с теми же условиями и приоритетом, но с противоположным действием разрешения или запрета.',
|
||||
allRulesAlreadyExist: 'Все проверенные правила ({0}) уже существуют. Новых правил для создания нет.',
|
||||
ruleCheckResult: 'Результаты проверки правил',
|
||||
ruleCheckStatus_creatable: 'Можно создать',
|
||||
@@ -4161,7 +4158,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Ошибка',
|
||||
ruleCheckExistingHelper: 'Такое же правило уже существует и будет пропущено.',
|
||||
ruleCheckReadyHelper: 'Проверка пройдена. Это правило можно создать.',
|
||||
ruleCheckExternalExists: 'Идентичное внешнее правило уже существует и будет автоматически пропущено.',
|
||||
ruleCheckBlockedHelper: 'Правила с ошибками нельзя отправить. Вернитесь, исправьте их и повторите проверку.',
|
||||
plan_managed_rule_drifted:
|
||||
'Управляемое правило не совпадает с активным межсетевым экраном. Сначала устраните расхождение.',
|
||||
@@ -4171,7 +4167,6 @@ const message = {
|
||||
plan_protected_rule: 'Правило защищено: его нельзя взять под управление, изменить или удалить.',
|
||||
plan_blocked: 'Правило нельзя безопасно применить. Обновите список и повторите попытку.',
|
||||
scopeDefaultMismatch: 'Системная зона по умолчанию — {0}; на этой странице управляется только зона public.',
|
||||
scopeInactive: 'Управляемая область не активна. Новые правила могут не влиять на текущий трафик.',
|
||||
scopeMissing: 'Управляемая область {0} отсутствует и будет безопасно создана при применении первого правила.',
|
||||
scopeUnmanagedActive: 'Обнаружены другие активные области: {0}. 1Panel не будет изменять их правила.',
|
||||
scopeRuntimeMismatch: 'Текущая и постоянная конфигурации firewalld не совпадают. Перезапустите брандмауэр.',
|
||||
@@ -4228,13 +4223,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'Активное управляемое правило нельзя безопасно удалить.',
|
||||
managedOrderBlocked:
|
||||
'Управляемые правила нельзя перемещать через внешние, нераспознанные или защищённые правила.',
|
||||
mayBlockManagement: 'Правило может заблокировать текущее соединение управления.',
|
||||
missingFromTarget: 'Правило отсутствует в целевом брандмауэре.',
|
||||
targetDiffers: 'Целевое правило отличается от политики базы данных.',
|
||||
alreadyExistsInTarget: 'Правило уже существует в целевом брандмауэре.',
|
||||
onlyInTarget: 'Правило существует только в целевом брандмауэре.',
|
||||
stale: 'Состояние правила устарело. Обновите данные и повторите попытку.',
|
||||
lockoutRisk: 'Это изменение может заблокировать доступ к управлению.',
|
||||
protectedRule: 'Это защищённое правило брандмауэра нельзя изменить.',
|
||||
dockerAcceptReadOnly:
|
||||
'Это правило ACCEPT доступно только для чтения и будет сохранено при синхронизации остальных правил. Чтобы удалить его, сделайте это вручную на хосте.',
|
||||
@@ -4283,7 +4276,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'Для этого порта не найдено активное правило перенаправления Docker или процесс прокси. Запустите или перезапустите контейнер, затем обновите страницу. Если проблема сохраняется, проверьте сеть Docker.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Путь доступа не определён',
|
||||
dockerInputPolicyNotEffective:
|
||||
'Хост принимает этот порт напрямую, поэтому существующее правило защиты порта контейнера не применяется. Настройте его в межсетевом экране хоста.',
|
||||
dockerInputUseHostFirewall: 'Настройте доступ к этому порту в межсетевом экране хоста.',
|
||||
@@ -4357,7 +4349,7 @@ const message = {
|
||||
'Отвязать - При отвязке все добавленные правила брандмауэра станут недействительными. Действуйте осторожно. Подтвердить?',
|
||||
portWhiteList: 'Белый список портов',
|
||||
portWhiteListAlter:
|
||||
'Сохранение не изменяет текущие правила брандмауэра сразу. Новые порты будут открыты при следующей инициализации или запуске. Чтобы закрыть удалённый из списка порт, вручную удалите существующее правило в списке правил.',
|
||||
'Изменения применяются сразу при сохранении. Добавленные порты разрешаются автоматически. Удаление порта из списка только снимает защиту. Чтобы закрыть порт, удалите разрешающее правило из списка правил.',
|
||||
portWhiteListHelper: 'Поддерживает IPv4/IPv6, TCP/UDP, отдельные порты и диапазоны, например 8000-8100.',
|
||||
chain: 'Цепочка',
|
||||
sourceIP: 'Исходный IP',
|
||||
|
||||
@@ -4167,9 +4167,8 @@ const message = {
|
||||
batchRuleLimit: 'Bir seferde en fazla {0} kural oluşturulabilir',
|
||||
resolution_adopt: 'Yönetimi devral',
|
||||
adoptRuleConfirm: 'Devraldıktan sonra 1Panel bu mevcut kuralı yönetebilir ve silebilir. Devam edilsin mi?',
|
||||
plan_equivalent_external_rule: 'Aynı harici kural zaten var. Kopya oluşturmak yerine yönetimi devralın.',
|
||||
plan_multiple_equivalent_external_rules: 'Birden fazla aynı harici kural var. Yönetilecek kuralı seçin.',
|
||||
plan_equivalent_managed_rule: 'Aynı kural zaten 1Panel tarafından yönetiliyor. Kopya gerekmez.',
|
||||
plan_exact_rule_conflict:
|
||||
'Aynı eşleşme koşullarına ve önceliğe sahip, ancak izin verme veya reddetme eylemi zıt olan bir kural zaten var.',
|
||||
allRulesAlreadyExist: 'Kontrol edilen {0} kuralın tümü zaten mevcut. Oluşturulacak yeni kural yok.',
|
||||
ruleCheckResult: 'Kural kontrol sonuçları',
|
||||
ruleCheckStatus_creatable: 'Oluşturulabilir',
|
||||
@@ -4177,7 +4176,6 @@ const message = {
|
||||
ruleCheckStatus_error: 'Hata',
|
||||
ruleCheckExistingHelper: 'Aynı kural zaten mevcut ve atlanacak.',
|
||||
ruleCheckReadyHelper: 'Kontrol başarılı. Bu kural oluşturulabilir.',
|
||||
ruleCheckExternalExists: 'Aynı harici kural zaten mevcut ve otomatik olarak atlanacak.',
|
||||
ruleCheckBlockedHelper: 'Hatalı kurallar gönderilemez. Geri dönüp düzenleyin ve yeniden kontrol edin.',
|
||||
plan_managed_rule_drifted: 'Yönetilen kural etkin güvenlik duvarıyla eşleşmiyor. Önce farkı giderin.',
|
||||
plan_opaque_rule_in_target_scope: 'Hedef kapsamda güvenle ayrıştırılamayan bir kural var. İşlem durduruldu.',
|
||||
@@ -4185,7 +4183,6 @@ const message = {
|
||||
plan_protected_rule: 'Bu kural korumalıdır; yönetimi devralınamaz, değiştirilemez veya silinemez.',
|
||||
plan_blocked: 'Bu kural güvenle uygulanamıyor. Listeyi yenileyip tekrar deneyin.',
|
||||
scopeDefaultMismatch: 'Sistemin varsayılan zone değeri {0}; bu sayfa yalnızca public zone alanını yönetir.',
|
||||
scopeInactive: 'Yönetilen kapsam etkin değil. Yeni kurallar mevcut trafiği etkilemeyebilir.',
|
||||
scopeMissing: 'Yönetilen {0} kapsamı eksik ve ilk kural uygulanırken güvenli şekilde oluşturulacak.',
|
||||
scopeUnmanagedActive: 'Başka etkin kapsamlar algılandı: {0}. 1Panel bunların kurallarını değiştirmez.',
|
||||
scopeRuntimeMismatch:
|
||||
@@ -4243,13 +4240,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: 'Yönetilen etkin kural güvenli bir şekilde kaldırılamıyor.',
|
||||
managedOrderBlocked:
|
||||
'Yönetilen kurallar harici, tanınmayan veya korunan kuralların üzerinden yeniden sıralanamaz.',
|
||||
mayBlockManagement: 'Kural mevcut yönetim bağlantısını engelleyebilir.',
|
||||
missingFromTarget: 'Kural hedef güvenlik duvarında bulunmuyor.',
|
||||
targetDiffers: 'Hedef kural veritabanı ilkesinden farklı.',
|
||||
alreadyExistsInTarget: 'Kural hedef güvenlik duvarında zaten mevcut.',
|
||||
onlyInTarget: 'Kural yalnızca hedef güvenlik duvarında mevcut.',
|
||||
stale: 'Güvenlik duvarı kuralının durumu güncel değil. Yenileyip tekrar deneyin.',
|
||||
lockoutRisk: 'Bu değişiklik yönetim erişimini engelleyebilir.',
|
||||
protectedRule: 'Bu korumalı güvenlik duvarı kuralı değiştirilemez.',
|
||||
dockerAcceptReadOnly:
|
||||
'Bu ACCEPT kuralı salt okunurdur ve diğer kurallar eşitlenirken korunur. Kaldırmak için ana makinede manuel olarak silin.',
|
||||
@@ -4299,7 +4294,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'Bu port için etkin bir Docker yönlendirme kuralı veya proxy işlemi bulunamadı. Konteyneri başlatın ya da yeniden başlatıp sayfayı yenileyin. Sorun sürerse Docker ağ yapılandırmasını kontrol edin.',
|
||||
},
|
||||
dockerTrafficPathPending: 'Erişim yolu bekleniyor',
|
||||
dockerInputPolicyNotEffective:
|
||||
'Bu port doğrudan ana makine tarafından alındığından mevcut konteyner port koruma kuralı uygulanmaz. Ana makine güvenlik duvarında yapılandırın.',
|
||||
dockerInputUseHostFirewall: 'Bu bağlantı noktasına erişimi ana makine güvenlik duvarında yapılandırın.',
|
||||
@@ -4371,7 +4365,7 @@ const message = {
|
||||
'Bağlantıyı Kaldır - Bağlantı kaldırıldığında, eklenen tüm güvenlik duvarı kuralları geçersiz olacaktır. Dikkatli ilerleyin. Onaylıyor musunuz?',
|
||||
portWhiteList: 'Port beyaz listesi',
|
||||
portWhiteListAlter:
|
||||
'Kaydetmek mevcut güvenlik duvarı kurallarını hemen değiştirmez. Yeni portlar bir sonraki başlatma veya etkinleştirmede açılır. Listeden kaldırılan bir portu kapatmak için mevcut kuralı kurallar listesinden elle silin.',
|
||||
'Değişiklikler kaydedildiğinde hemen uygulanır. Eklenen portlara otomatik olarak izin verilir. Portu listeden çıkarmak yalnızca korumasını kaldırır. Portu kapatmak için kural listesinden izin kuralını silin.',
|
||||
portWhiteListHelper: 'IPv4/IPv6, TCP/UDP, tek portlar ve 8000-8100 gibi port aralıklarını destekler.',
|
||||
chain: 'Zincir',
|
||||
sourceIP: 'Kaynak IP',
|
||||
|
||||
@@ -3827,9 +3827,7 @@ const message = {
|
||||
batchRuleLimit: '單次最多可建立 {0} 條規則',
|
||||
resolution_adopt: '納管',
|
||||
adoptRuleConfirm: '納入管理後,1Panel 將負責維護及刪除這條現有規則,是否繼續?',
|
||||
plan_equivalent_external_rule: '系統中已有相同的外部規則,可將它納入管理,無需重複建立。',
|
||||
plan_multiple_equivalent_external_rules: '系統中有多條相同的外部規則,請選擇其中一條納入管理。',
|
||||
plan_equivalent_managed_rule: '相同規則已由 1Panel 管理,無需重複建立。',
|
||||
plan_exact_rule_conflict: '已存在比對條件和優先級相同、但允許與拒絕動作相反的規則。',
|
||||
allRulesAlreadyExist: '本次檢查的 {0} 條規則均已存在,沒有需要建立的新規則。',
|
||||
ruleCheckResult: '規則檢查結果',
|
||||
ruleCheckStatus_creatable: '可建立',
|
||||
@@ -3837,7 +3835,6 @@ const message = {
|
||||
ruleCheckStatus_error: '錯誤',
|
||||
ruleCheckExistingHelper: '系統中已存在相同規則,本次將自動略過。',
|
||||
ruleCheckReadyHelper: '檢查通過,可以建立此規則。',
|
||||
ruleCheckExternalExists: '系統中已有相同的外部規則,本次將自動略過。',
|
||||
ruleCheckBlockedHelper: '存在錯誤規則,無法提交。請返回修改後重新檢查。',
|
||||
plan_managed_rule_drifted: '1Panel 管理記錄與系統實際規則不一致,請檢查系統規則。',
|
||||
plan_opaque_rule_in_target_scope: '目標範圍內有無法安全解析的規則,本次操作已停止。',
|
||||
@@ -3845,7 +3842,6 @@ const message = {
|
||||
plan_protected_rule: '此規則受到保護,不能認領、修改或刪除。',
|
||||
plan_blocked: '目前規則無法安全套用,請重新整理規則後再試。',
|
||||
scopeDefaultMismatch: '系統預設 zone 為 {0},目前頁面僅管理 public zone。',
|
||||
scopeInactive: '目前託管範圍未啟用,新增規則可能不會作用於現有流量。',
|
||||
scopeMissing: '託管範圍 {0} 尚未建立,套用第一條規則時將以安全方式建立。',
|
||||
scopeUnmanagedActive: '偵測到其他使用中範圍:{0},1Panel 不會修改其中的規則。',
|
||||
scopeRuntimeMismatch: 'firewalld 執行中設定與永久設定不一致,請重新啟動防火牆。',
|
||||
@@ -3899,13 +3895,11 @@ const message = {
|
||||
managedOnlyInTarget: '此受管規則僅存在於目標防火牆中。',
|
||||
managedRuntimeCannotRemove: '無法安全刪除此受管執行中規則。',
|
||||
managedOrderBlocked: '受管規則的排序不能跨越外部、無法識別或受保護的規則。',
|
||||
mayBlockManagement: '此規則可能會阻斷目前的管理連線。',
|
||||
missingFromTarget: '目標防火牆中缺少此規則。',
|
||||
targetDiffers: '目標規則與資料庫策略不一致。',
|
||||
alreadyExistsInTarget: '目標防火牆中已存在此規則。',
|
||||
onlyInTarget: '此規則僅存在於目標防火牆中。',
|
||||
stale: '防火牆規則狀態已過期,請重新整理後再試。',
|
||||
lockoutRisk: '此次防火牆變更可能會阻斷管理存取。',
|
||||
protectedRule: '此防火牆規則受保護,無法修改。',
|
||||
dockerAcceptReadOnly:
|
||||
'此 ACCEPT 規則為唯讀、不可同步;同步其他規則時將保留此規則。如需移除,請在主機上手動刪除。',
|
||||
@@ -3949,7 +3943,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'未找到此連接埠生效的 Docker 轉送規則或代理程序,請啟動或重新啟動對應容器後重新整理;若仍異常,請檢查 Docker 網路設定。',
|
||||
},
|
||||
dockerTrafficPathPending: '存取方式待確認',
|
||||
dockerInputPolicyNotEffective: '此連接埠由主機直接接收,現有容器連接埠防護規則不會生效,請改用主機防火牆設定。',
|
||||
dockerInputUseHostFirewall: '此連接埠需要透過主機防火牆設定存取規則,請前往主機防火牆進行設定。',
|
||||
dockerInputNotProtected: '主機 INPUT 規則無法直接保護此 Docker 發佈連接埠,點擊前往容器連接埠防護。',
|
||||
@@ -4011,7 +4004,7 @@ const message = {
|
||||
unbindHelper: '解除綁定 解除綁定時,已新增的所有防火牆規則將失效,請謹慎操作,是否確認?',
|
||||
portWhiteList: '埠白名單',
|
||||
portWhiteListAlter:
|
||||
'儲存後不會立即變更目前的防火牆規則。新增的埠將在下次初始化或啟動防火牆時自動放行;若要關閉已移出的埠,請前往規則清單手動刪除現有規則。',
|
||||
'白名單修改在儲存後立即生效。新增連接埠自動放行;移出連接埠僅解除白名單保護,如需關閉,請前往規則清單手動刪除放行規則。',
|
||||
portWhiteListHelper: '支援 IPv4/IPv6、TCP/UDP、單一連接埠以及 8000-8100 格式的連接埠範圍。',
|
||||
chain: '鏈',
|
||||
sourceIP: '來源 IP',
|
||||
|
||||
@@ -3873,9 +3873,7 @@ const message = {
|
||||
batchRuleLimit: '单次最多可创建 {0} 条规则',
|
||||
resolution_adopt: '纳管',
|
||||
adoptRuleConfirm: '纳入管理后,1Panel 将负责维护和删除这条现有规则,是否继续?',
|
||||
plan_equivalent_external_rule: '系统中已有相同的外部规则,可以将它纳入管理,无需重复创建。',
|
||||
plan_multiple_equivalent_external_rules: '系统中有多条相同的外部规则,请选择其中一条纳入管理。',
|
||||
plan_equivalent_managed_rule: '相同规则已由 1Panel 管理,无需重复创建。',
|
||||
plan_exact_rule_conflict: '已存在匹配条件和优先级相同、但允许与拒绝动作相反的规则。',
|
||||
allRulesAlreadyExist: '本次检查的 {0} 条规则均已存在,没有需要创建的新规则。',
|
||||
ruleCheckResult: '规则检查结果',
|
||||
ruleCheckStatus_creatable: '可创建',
|
||||
@@ -3883,7 +3881,6 @@ const message = {
|
||||
ruleCheckStatus_error: '错误',
|
||||
ruleCheckExistingHelper: '系统中已存在相同规则,本次将自动跳过。',
|
||||
ruleCheckReadyHelper: '检查通过,可以创建该规则。',
|
||||
ruleCheckExternalExists: '系统中已有相同的外部规则,本次将自动跳过。',
|
||||
ruleCheckBlockedHelper: '存在错误规则,不能提交。请返回修改后重新检查。',
|
||||
plan_managed_rule_drifted:
|
||||
'这条规则在 1Panel 中的记录与防火墙实际状态不一致,请先刷新规则;如仍异常,请重新同步。',
|
||||
@@ -3893,7 +3890,6 @@ const message = {
|
||||
plan_protected_rule: '该规则受到保护,不能认领、修改或删除。',
|
||||
plan_blocked: '暂时无法处理这条规则,本次操作未生效。请刷新后重试;如仍失败,请检查规则状态。',
|
||||
scopeDefaultMismatch: '系统默认 zone 为 {0},当前页面仅管理 public zone。',
|
||||
scopeInactive: '当前托管范围未激活,新增规则可能不会作用于现有流量。',
|
||||
scopeMissing: '托管范围 {0} 尚未创建,应用首条规则时将以安全方式创建。',
|
||||
scopeUnmanagedActive: '检测到其他活动范围:{0},1Panel 不会修改其中的规则。',
|
||||
scopeRuntimeMismatch: 'firewalld 运行配置与永久配置不一致,请重启防火墙。',
|
||||
@@ -3948,13 +3944,11 @@ const message = {
|
||||
managedRuntimeCannotRemove: '该规则仅在当前运行中生效,1Panel 无法确认删除后的影响,因此本次不会删除。',
|
||||
managedOrderBlocked:
|
||||
'调整规则顺序时会跨过外部规则、无法识别的规则或系统保护规则,为避免改变现有访问,本次不会调整。',
|
||||
mayBlockManagement: '该规则可能导致当前 1Panel 管理页面无法访问。',
|
||||
missingFromTarget: '防火墙中缺少该规则,本次将补充。',
|
||||
targetDiffers: '防火墙中的规则与 1Panel 保存的设置不一致,本次将修复。',
|
||||
alreadyExistsInTarget: '防火墙中已存在相同规则,无需重复添加。',
|
||||
onlyInTarget: '该规则只存在于当前防火墙中。',
|
||||
stale: '检查后防火墙状态已发生变化,请刷新后重试。',
|
||||
lockoutRisk: '执行后可能导致当前 1Panel 管理页面无法访问,本次操作已停止。',
|
||||
protectedRule: '这是保证系统正常运行的必要规则,不能修改。',
|
||||
dockerAcceptReadOnly:
|
||||
'该 ACCEPT 规则为只读、不可同步;同步其他规则时会保留该规则。如需移除,请在主机上手动删除。',
|
||||
@@ -3998,7 +3992,6 @@ const message = {
|
||||
no_matching_path:
|
||||
'未找到该端口生效的 Docker 转发规则或代理进程,请启动或重启对应容器后刷新;若仍异常,请检查 Docker 网络配置。',
|
||||
},
|
||||
dockerTrafficPathPending: '访问方式待确认',
|
||||
dockerInputPolicyNotEffective: '该端口由主机直接接收,现有容器端口防护规则不会生效,请改用主机防火墙设置。',
|
||||
dockerInputUseHostFirewall: '该端口需要通过主机防火墙设置访问规则,请前往主机防火墙进行配置。',
|
||||
dockerInputNotProtected: '宿主机 INPUT 规则不能直接保护此 Docker 发布端口,点击前往容器端口防护。',
|
||||
@@ -4060,7 +4053,7 @@ const message = {
|
||||
unbindHelper: '解绑 解除绑定时,已添加的所有防火墙规则将失效,请谨慎操作,是否确认?',
|
||||
portWhiteList: '端口白名单',
|
||||
portWhiteListAlter:
|
||||
'保存后不会立即更改当前防火墙规则。新增端口将在下次初始化或启动防火墙时自动放行;如需关闭已移出的端口,请前往规则列表手动删除现有规则。',
|
||||
'白名单修改在保存后立即生效。新增端口自动放行;移出端口仅解除白名单保护,如需关闭,请前往规则列表手动删除放行规则。',
|
||||
portWhiteListHelper: '支持 IPv4/IPv6、TCP/UDP、单端口以及 8000-8100 格式的端口范围。',
|
||||
chain: '链',
|
||||
sourceIP: '源 IP',
|
||||
|
||||
@@ -490,7 +490,7 @@ const showFirewallUnavailablePrompt = computed(
|
||||
const firewallVersion = ref('');
|
||||
const selectedRuleFilters = ref<RuleFilter[]>(loadCachedFilterValues(ruleFilterStorageKey, ruleFilterOptions, []));
|
||||
const visibleIptablesChains = ref<string[]>(
|
||||
loadCachedFilterValues(chainFilterStorageKey, iptablesChains, iptablesChains),
|
||||
loadCachedFilterValues(chainFilterStorageKey, iptablesChains, ['1PANEL_BASIC']),
|
||||
);
|
||||
const searchName = ref('');
|
||||
const inventoryItems = ref<Firewall.InventoryItem[]>([]);
|
||||
@@ -861,9 +861,11 @@ const notices = computed<DisplayNotice[]>(() => {
|
||||
const unique = new Map<string, DisplayNotice>();
|
||||
scopeNotices.value.forEach((notice) => {
|
||||
if (notice.code === 'managed_scope_missing') return;
|
||||
const text = scopeNoticeText(notice);
|
||||
if (!text) return;
|
||||
const key = `${notice.code}:${(notice.values || []).join(',')}`;
|
||||
if (!unique.has(key)) {
|
||||
unique.set(key, { key, text: scopeNoticeText(notice) });
|
||||
unique.set(key, { key, text });
|
||||
}
|
||||
});
|
||||
return [...unique.values()];
|
||||
@@ -876,14 +878,14 @@ const scopeNoticeText = (notice: Firewall.ScopeNotice) => {
|
||||
return value;
|
||||
case 'default_scope_mismatch':
|
||||
return i18n.global.t('firewall.scopeDefaultMismatch', [value]);
|
||||
case 'managed_scope_inactive':
|
||||
return i18n.global.t('firewall.scopeInactive');
|
||||
case 'managed_scope_missing':
|
||||
return i18n.global.t('firewall.scopeMissing', [value]);
|
||||
case 'unmanaged_active_scopes':
|
||||
return i18n.global.t('firewall.scopeUnmanagedActive', [value]);
|
||||
case 'runtime_permanent_mismatch':
|
||||
return i18n.global.t('firewall.scopeRuntimeMismatch');
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -935,9 +937,7 @@ const ruleIssueText = (row: Firewall.InventoryItem) => {
|
||||
};
|
||||
|
||||
const openCreate = async () => {
|
||||
const unavailableScope = scopeNotices.value.find((notice) =>
|
||||
['managed_scope_inactive', 'managed_scope_missing'].includes(notice.code),
|
||||
);
|
||||
const unavailableScope = scopeNotices.value.find((notice) => notice.code === 'managed_scope_missing');
|
||||
if (unavailableScope) {
|
||||
try {
|
||||
await ElMessageBox.confirm(scopeNoticeText(unavailableScope), i18n.global.t('commons.msg.infoTitle'), {
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
class="rule-check-item-reason"
|
||||
:class="`is-${ruleCheckStatus(item.plan)}`"
|
||||
>
|
||||
{{ ruleCheckDescription(item.plan) }}
|
||||
{{ planReasonMessage(item.plan.reason) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,8 +292,7 @@ const wildcardAddressLabel = (family: Firewall.Family) =>
|
||||
const isWildcardAddress = (_family: Firewall.Family, address?: string) => !address?.trim();
|
||||
const priorityFieldLabel = computed(() => i18n.global.t('firewall.priority'));
|
||||
const showPriorityField = computed(() => {
|
||||
if (provider.value === 'ufw') return mode.value === 'edit';
|
||||
if (provider.value !== 'firewalld') return true;
|
||||
if (provider.value !== 'firewalld') return mode.value === 'edit';
|
||||
return (
|
||||
firewalldPrioritySupported.value && (mode.value === 'create' || editingRule.value?.nativeKind === 'rich_rule')
|
||||
);
|
||||
@@ -308,9 +307,7 @@ const priorityMax = computed(() => Math.min(...selectedPositionRanges.value.map(
|
||||
const showingPreview = computed(() => previewVisible.value && previewRules.value.length > 0);
|
||||
|
||||
const supportedPlanReasons = new Set([
|
||||
'equivalent_external_rule',
|
||||
'multiple_equivalent_external_rules',
|
||||
'equivalent_managed_rule',
|
||||
'exact_rule_conflict',
|
||||
'managed_rule_drifted',
|
||||
'opaque_rule_in_target_scope',
|
||||
'runtime_permanent_mismatch',
|
||||
@@ -328,12 +325,6 @@ const ruleCheckStatus = (result: Firewall.RuleCheckResult): RuleCheckDisplayStat
|
||||
return 'creatable';
|
||||
};
|
||||
|
||||
const ruleCheckDescription = (result: Firewall.RuleCheckResult) => {
|
||||
if (ruleCheckStatus(result) === 'creatable') return i18n.global.t('firewall.ruleCheckReadyHelper');
|
||||
if (result.classification === 'exact_external') return i18n.global.t('firewall.ruleCheckExternalExists');
|
||||
return planReasonMessage(result.reason);
|
||||
};
|
||||
|
||||
const ruleCheckGroupDescription = (status: RuleCheckDisplayStatus) => {
|
||||
if (status === 'error') return i18n.global.t('firewall.ruleCheckBlockedHelper');
|
||||
if (status === 'existing') return i18n.global.t('firewall.ruleCheckExistingHelper');
|
||||
@@ -458,7 +449,7 @@ const resetForm = () => {
|
||||
form.destinationAddress = '';
|
||||
form.destinationPorts = [''];
|
||||
form.action = 'accept';
|
||||
form.priority = provider.value === 'firewalld' || provider.value === 'ufw' ? undefined : priorityMax.value;
|
||||
form.priority = undefined;
|
||||
form.description = '';
|
||||
editingUUID.value = '';
|
||||
editingRule.value = undefined;
|
||||
@@ -593,10 +584,7 @@ const buildRule = (
|
||||
destinationPort,
|
||||
action,
|
||||
priority: provider.value === 'firewalld' && firewalldPrioritySupported.value ? form.priority : undefined,
|
||||
orderIndex:
|
||||
provider.value === 'firewalld' || (provider.value === 'ufw' && mode.value === 'create')
|
||||
? undefined
|
||||
: form.priority,
|
||||
orderIndex: provider.value === 'firewalld' || mode.value === 'create' ? undefined : form.priority,
|
||||
description: form.description,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ import {
|
||||
WhiteListFamily,
|
||||
WhiteListProtocol,
|
||||
WhiteListRule,
|
||||
whiteListRulesOverlap,
|
||||
whiteListRuleKey,
|
||||
} from './model';
|
||||
|
||||
interface WhiteListItem extends WhiteListRule {
|
||||
@@ -127,7 +127,7 @@ const editRow = (row: WhiteListItem) => {
|
||||
const saveRow = (row: WhiteListItem) => {
|
||||
const rule = validateRule(row);
|
||||
if (!rule) return;
|
||||
if (hasOverlap(rule, row)) {
|
||||
if (hasDuplicate(rule, row)) {
|
||||
MsgError(i18n.global.t('commons.rule.duplicate'));
|
||||
return;
|
||||
}
|
||||
@@ -163,8 +163,10 @@ const validateRule = (row: Pick<WhiteListItem, 'family' | 'protocol' | 'port'>):
|
||||
}
|
||||
};
|
||||
|
||||
const hasOverlap = (rule: WhiteListRule, row?: WhiteListItem): boolean => {
|
||||
return data.value.some((item) => item !== row && item.port !== '' && whiteListRulesOverlap(rule, item));
|
||||
const hasDuplicate = (rule: WhiteListRule, row?: WhiteListItem): boolean => {
|
||||
return data.value.some(
|
||||
(item) => item !== row && item.port !== '' && whiteListRuleKey(rule) === whiteListRuleKey(item),
|
||||
);
|
||||
};
|
||||
|
||||
const validateRules = (): WhiteListRule[] | undefined => {
|
||||
@@ -173,7 +175,7 @@ const validateRules = (): WhiteListRule[] | undefined => {
|
||||
if (!item.port) continue;
|
||||
const rule = validateRule(item);
|
||||
if (!rule) return undefined;
|
||||
if (rules.some((existing) => whiteListRulesOverlap(existing, rule))) {
|
||||
if (rules.some((existing) => whiteListRuleKey(existing) === whiteListRuleKey(rule))) {
|
||||
MsgError(i18n.global.t('commons.rule.duplicate'));
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -70,16 +70,3 @@ export const whiteListRuleCount = (value: string): number => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
export const whiteListRulesOverlap = (left: WhiteListRule, right: WhiteListRule): boolean => {
|
||||
const first = normalizeWhiteListRule(left);
|
||||
const second = normalizeWhiteListRule(right);
|
||||
if (first.family !== second.family || first.protocol !== second.protocol) return false;
|
||||
const range = (port: string) => {
|
||||
const [start, end = start] = port.split('-').map(Number);
|
||||
return { start, end };
|
||||
};
|
||||
const leftRange = range(first.port);
|
||||
const rightRange = range(second.port);
|
||||
return leftRange.start <= rightRange.end && rightRange.start <= leftRange.end;
|
||||
};
|
||||
|
||||
@@ -296,13 +296,11 @@ const syncReasonKeys: Record<string, string> = {
|
||||
'managed rule exists only in target backend': 'managedOnlyInTarget',
|
||||
'managed runtime rule cannot be safely removed': 'managedRuntimeCannotRemove',
|
||||
'managed rule order cannot cross external, opaque, or protected rules': 'managedOrderBlocked',
|
||||
'rule may block the current management connection': 'mayBlockManagement',
|
||||
'rule is missing from target backend': 'missingFromTarget',
|
||||
'target rule differs from database policy': 'targetDiffers',
|
||||
'rule already exists in target backend': 'alreadyExistsInTarget',
|
||||
'rule exists only in target backend': 'onlyInTarget',
|
||||
'firewall rule state is stale': 'stale',
|
||||
'firewall change may lock out management access': 'lockoutRisk',
|
||||
'protected firewall rule cannot be modified': 'protectedRule',
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user