mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
fix(firewall): preserve whitelist priority and rule ordering (#13845)
This commit is contained in:
@@ -1015,7 +1015,9 @@ func (s *FirewallService) Create(
|
|||||||
return dto.FirewallRuleCreateResponse{}, err
|
return dto.FirewallRuleCreateResponse{}, err
|
||||||
}
|
}
|
||||||
taskItem.AddSubTaskWithOps(i18n.GetMsgByKey("FirewallCreateRulesStep"), func(t *task.Task) error {
|
taskItem.AddSubTaskWithOps(i18n.GetMsgByKey("FirewallCreateRulesStep"), func(t *task.Task) error {
|
||||||
_, err := s.runCreateTask(t, request)
|
firewallRuleMutationMu.Lock()
|
||||||
|
defer firewallRuleMutationMu.Unlock()
|
||||||
|
_, err := s.createRules(t.TaskCtx, request, t)
|
||||||
return err
|
return err
|
||||||
}, nil, 0, 0)
|
}, nil, 0, 0)
|
||||||
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
||||||
@@ -1031,12 +1033,6 @@ func (s *FirewallService) Create(
|
|||||||
return dto.FirewallRuleCreateResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
return dto.FirewallRuleCreateResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FirewallService) runCreateTask(t *task.Task, request dto.FirewallRuleCreate) (dto.FirewallRuleCreateResponse, error) {
|
|
||||||
firewallRuleMutationMu.Lock()
|
|
||||||
defer firewallRuleMutationMu.Unlock()
|
|
||||||
return s.createRules(t.TaskCtx, request, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallRuleCreate, t *task.Task) (result dto.FirewallRuleCreateResponse, taskErr error) {
|
func (s *FirewallService) createRules(ctx context.Context, request dto.FirewallRuleCreate, t *task.Task) (result dto.FirewallRuleCreateResponse, taskErr error) {
|
||||||
var firstFailure error
|
var firstFailure error
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1412,7 +1408,13 @@ func (s *FirewallService) Delete(ctx context.Context, request dto.FirewallRuleDe
|
|||||||
return dto.FirewallRuleDeleteResponse{}, err
|
return dto.FirewallRuleDeleteResponse{}, err
|
||||||
}
|
}
|
||||||
taskItem.AddSubTaskWithOps(taskItem.Name, func(t *task.Task) error {
|
taskItem.AddSubTaskWithOps(taskItem.Name, func(t *task.Task) error {
|
||||||
_, err := s.runDeleteTask(t, request)
|
t.Logf("rules=%d", len(request.UUIDs)+len(request.BeforeRules))
|
||||||
|
firewallRuleMutationMu.Lock()
|
||||||
|
defer firewallRuleMutationMu.Unlock()
|
||||||
|
if err := t.TaskCtx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := s.deleteRules(t.TaskCtx, request, t)
|
||||||
return err
|
return err
|
||||||
}, nil, 0, 0)
|
}, nil, 0, 0)
|
||||||
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil {
|
||||||
@@ -1428,16 +1430,6 @@ func (s *FirewallService) Delete(ctx context.Context, request dto.FirewallRuleDe
|
|||||||
return dto.FirewallRuleDeleteResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
return dto.FirewallRuleDeleteResponse{TaskID: taskItem.TaskID, Queued: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FirewallService) runDeleteTask(t *task.Task, request dto.FirewallRuleDelete) (dto.FirewallRuleDeleteResponse, error) {
|
|
||||||
t.Logf("rules=%d", len(request.UUIDs)+len(request.BeforeRules))
|
|
||||||
firewallRuleMutationMu.Lock()
|
|
||||||
defer firewallRuleMutationMu.Unlock()
|
|
||||||
if err := t.TaskCtx.Err(); err != nil {
|
|
||||||
return dto.FirewallRuleDeleteResponse{}, err
|
|
||||||
}
|
|
||||||
return s.deleteRules(t.TaskCtx, request, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FirewallService) deleteRules(ctx context.Context, request dto.FirewallRuleDelete, t *task.Task) (result dto.FirewallRuleDeleteResponse, taskErr error) {
|
func (s *FirewallService) deleteRules(ctx context.Context, request dto.FirewallRuleDelete, t *task.Task) (result dto.FirewallRuleDeleteResponse, taskErr error) {
|
||||||
var firstFailure error
|
var firstFailure error
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1619,7 +1611,7 @@ func (s *FirewallService) prepareDelete(
|
|||||||
}
|
}
|
||||||
return preparedFirewallRuleDelete{}, err
|
return preparedFirewallRuleDelete{}, err
|
||||||
}
|
}
|
||||||
if err := checkFirewallRuleWhitelistProtection(ctx, stored); err != nil {
|
if err := checkFirewallRuleWhitelistProtection(selectedProvider, stored); err != nil {
|
||||||
return preparedFirewallRuleDelete{}, err
|
return preparedFirewallRuleDelete{}, err
|
||||||
}
|
}
|
||||||
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
||||||
@@ -1754,7 +1746,11 @@ func (s *FirewallService) updateRuleDescription(ctx context.Context, ruleUUID, d
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := checkFirewallRuleWhitelistProtection(ctx, stored); err != nil {
|
selected, err := s.selectedProviderForStoredRule(ctx, stored)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkFirewallRuleWhitelistProtection(selected, stored); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
||||||
@@ -1900,7 +1896,7 @@ func (s *FirewallService) deleteRule(ctx context.Context, ruleUUID string) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := checkFirewallRuleWhitelistProtection(ctx, stored); err != nil {
|
if err := checkFirewallRuleWhitelistProtection(selected, stored); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
type appliedDelete struct {
|
type appliedDelete struct {
|
||||||
@@ -2212,9 +2208,6 @@ func (s *FirewallService) loadManagedMutation(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
||||||
}
|
}
|
||||||
if err := checkFirewallRuleWhitelistProtection(ctx, stored); err != nil {
|
|
||||||
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
|
||||||
}
|
|
||||||
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
if stored.Origin != constant.FirewallRuleOriginCreated && stored.Origin != constant.FirewallRuleOriginAdopted {
|
||||||
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil,
|
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil,
|
||||||
fmt.Errorf("%w: only created or adopted rules can be changed", filter.ErrInvalidRule)
|
fmt.Errorf("%w: only created or adopted rules can be changed", filter.ErrInvalidRule)
|
||||||
@@ -2223,6 +2216,9 @@ func (s *FirewallService) loadManagedMutation(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
||||||
}
|
}
|
||||||
|
if err := checkFirewallRuleWhitelistProtection(selected, stored); err != nil {
|
||||||
|
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
||||||
|
}
|
||||||
desiredRules, err := s.compileStoredFirewallRules(ctx, stored, selected)
|
desiredRules, err := s.compileStoredFirewallRules(ctx, stored, selected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
return model.FirewallRule{}, filter.DesiredRule{}, filter.Snapshot{}, filter.ObservedRule{}, nil, err
|
||||||
@@ -2617,16 +2613,27 @@ func (s *FirewallService) sequenceForFirewallRulePosition(
|
|||||||
byUUID := make(map[string]model.FirewallRule, len(stored))
|
byUUID := make(map[string]model.FirewallRule, len(stored))
|
||||||
for _, record := range stored {
|
for _, record := range stored {
|
||||||
byUUID[record.UUID] = record
|
byUUID[record.UUID] = record
|
||||||
|
compiled, err := s.compileStoredFirewallRules(ctx, record, snapshot.Scope.Provider)
|
||||||
|
if err != nil {
|
||||||
|
if isFirewallPolicyIncompatible(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for _, desired := range compiled {
|
||||||
|
if desired.Rule.Scope.Key() == snapshot.Scope.Key() {
|
||||||
|
byUUID[desired.Rule.UUID] = record
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var previous, next *model.FirewallRule
|
var previous, next *model.FirewallRule
|
||||||
needsRebalance := false
|
|
||||||
for _, observed := range snapshot.Rules {
|
for _, observed := range snapshot.Rules {
|
||||||
uuid := strings.TrimPrefix(observed.Marker, "1panel-rule:")
|
uuid := strings.TrimPrefix(observed.Marker, "1panel-rule:")
|
||||||
if observed.Marker == uuid || uuid == excludedUUID || observed.Locator.Position == nil {
|
if observed.Marker == uuid || uuid == excludedUUID || observed.Locator.Position == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
record, exists := byUUID[uuid]
|
record, exists := byUUID[uuid]
|
||||||
if !exists {
|
if !exists || record.UUID == excludedUUID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
position := *observed.Locator.Position
|
position := *observed.Locator.Position
|
||||||
@@ -2640,30 +2647,24 @@ func (s *FirewallService) sequenceForFirewallRulePosition(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if previous != nil && previous.Sequence == nil || next != nil && next.Sequence == nil {
|
if previous != nil && previous.Sequence == nil || next != nil && next.Sequence == nil {
|
||||||
needsRebalance = true
|
return s.rebalanceFirewallRuleSequences(ctx, snapshot, targetPosition, excludedUUID, byUUID)
|
||||||
}
|
}
|
||||||
if !needsRebalance && current != nil &&
|
if current != nil &&
|
||||||
(previous == nil || *previous.Sequence < *current) && (next == nil || *current < *next.Sequence) {
|
(previous == nil || *previous.Sequence < *current) && (next == nil || *current < *next.Sequence) {
|
||||||
return *current, nil
|
return *current, nil
|
||||||
}
|
}
|
||||||
if !needsRebalance {
|
switch {
|
||||||
switch {
|
case previous == nil && next == nil:
|
||||||
case previous == nil && next == nil:
|
return model.FirewallRuleSequenceStep, nil
|
||||||
return model.FirewallRuleSequenceStep, nil
|
case previous == nil:
|
||||||
case previous == nil:
|
return *next.Sequence - model.FirewallRuleSequenceStep, nil
|
||||||
return *next.Sequence - model.FirewallRuleSequenceStep, nil
|
case next == nil:
|
||||||
case next == nil:
|
return *previous.Sequence + model.FirewallRuleSequenceStep, nil
|
||||||
return *previous.Sequence + model.FirewallRuleSequenceStep, nil
|
case *next.Sequence-*previous.Sequence > 1:
|
||||||
case *next.Sequence-*previous.Sequence > 1:
|
return *previous.Sequence + (*next.Sequence-*previous.Sequence)/2, nil
|
||||||
return *previous.Sequence + (*next.Sequence-*previous.Sequence)/2, nil
|
default:
|
||||||
default:
|
|
||||||
needsRebalance = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if needsRebalance {
|
|
||||||
return s.rebalanceFirewallRuleSequences(ctx, snapshot, targetPosition, excludedUUID, byUUID)
|
return s.rebalanceFirewallRuleSequences(ctx, snapshot, targetPosition, excludedUUID, byUUID)
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("%w: cannot allocate firewall rule sequence", filter.ErrRuleOperation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FirewallService) rebalanceFirewallRuleSequences(
|
func (s *FirewallService) rebalanceFirewallRuleSequences(
|
||||||
@@ -2674,6 +2675,7 @@ func (s *FirewallService) rebalanceFirewallRuleSequences(
|
|||||||
byUUID map[string]model.FirewallRule,
|
byUUID map[string]model.FirewallRule,
|
||||||
) (int64, error) {
|
) (int64, error) {
|
||||||
targetSequence := int64(targetPosition) * model.FirewallRuleSequenceStep
|
targetSequence := int64(targetPosition) * model.FirewallRuleSequenceStep
|
||||||
|
updated := make(map[string]bool)
|
||||||
for _, observed := range snapshot.Rules {
|
for _, observed := range snapshot.Rules {
|
||||||
if observed.Locator.Position == nil {
|
if observed.Locator.Position == nil {
|
||||||
continue
|
continue
|
||||||
@@ -2683,9 +2685,10 @@ func (s *FirewallService) rebalanceFirewallRuleSequences(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
record, exists := byUUID[uuid]
|
record, exists := byUUID[uuid]
|
||||||
if !exists {
|
if !exists || record.UUID == excludedUUID || updated[record.UUID] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
updated[record.UUID] = true
|
||||||
position := *observed.Locator.Position
|
position := *observed.Locator.Position
|
||||||
if excludedUUID == "" && position >= targetPosition {
|
if excludedUUID == "" && position >= targetPosition {
|
||||||
position++
|
position++
|
||||||
@@ -2825,7 +2828,11 @@ func firewallRuleSnapshotPolicy(ctx context.Context, snapshot filter.Snapshot) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func firewallRuleSelectedProvider(context.Context) (filter.Provider, error) {
|
func firewallRuleSelectedProvider(context.Context) (filter.Provider, error) {
|
||||||
return selectedRuleProvider()
|
provider, err := selectedSystemFirewallProvider()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("%w: %v", filter.ErrProviderUnavailable, err)
|
||||||
|
}
|
||||||
|
return filter.Provider(provider), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rollbackFirewallPlan(ctx context.Context, runtime *filterruntime.Engine, plan filter.BackendPlan, cause error) error {
|
func rollbackFirewallPlan(ctx context.Context, runtime *filterruntime.Engine, plan filter.BackendPlan, cause error) error {
|
||||||
@@ -2838,14 +2845,6 @@ func rollbackFirewallPlan(ctx context.Context, runtime *filterruntime.Engine, pl
|
|||||||
return cause
|
return cause
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectedRuleProvider() (filter.Provider, error) {
|
|
||||||
provider, err := selectedSystemFirewallProvider()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("%w: %v", filter.ErrProviderUnavailable, err)
|
|
||||||
}
|
|
||||||
return filter.Provider(provider), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureFirewallPorts(ports []int) error {
|
func ensureFirewallPorts(ports []int) error {
|
||||||
filterruntime.InvalidateInventory()
|
filterruntime.InvalidateInventory()
|
||||||
defer filterruntime.InvalidateInventory()
|
defer filterruntime.InvalidateInventory()
|
||||||
@@ -2858,7 +2857,7 @@ func ensureFirewallPorts(ports []int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if state.Name == constant.FirewallProviderIptables || state.Name == constant.FirewallProviderNftables {
|
if state.Name == constant.FirewallProviderIptables || state.Name == constant.FirewallProviderNftables {
|
||||||
isInit, _, err := loadDirectFirewallInitStatus(state.Name)
|
isInit, _, err := loadFirewallInitStatus(state.Name, "base")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2934,10 +2933,6 @@ func newNftablesHelperManager() *nftables_helper.Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDirectFirewallInitStatus(provider string) (bool, bool, error) {
|
|
||||||
return loadFirewallInitStatus(provider, "base")
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadFirewallInitStatus(provider, tab string) (bool, bool, error) {
|
func loadFirewallInitStatus(provider, tab string) (bool, bool, error) {
|
||||||
switch provider {
|
switch provider {
|
||||||
case constant.FirewallProviderNftables:
|
case constant.FirewallProviderNftables:
|
||||||
@@ -2968,7 +2963,7 @@ func (s *FirewallService) restoreFirewallAfterStart(client lifecycle.Client) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if provider == filter.ProviderIptables || provider == filter.ProviderNftables {
|
if provider == filter.ProviderIptables || provider == filter.ProviderNftables {
|
||||||
isInit, _, err := loadDirectFirewallInitStatus(string(provider))
|
isInit, _, err := loadFirewallInitStatus(string(provider), "base")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
recordFailure("load managed chain status", err)
|
recordFailure("load managed chain status", err)
|
||||||
return errors.Join(recoveryErrors...)
|
return errors.Join(recoveryErrors...)
|
||||||
|
|||||||
@@ -137,12 +137,12 @@ func savePortWhitelist(ctx context.Context, change func([]firewall.PortWhitelist
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFirewallRuleWhitelistProtection(ctx context.Context, record model.FirewallRule) error {
|
func checkFirewallRuleWhitelistProtection(provider filter.Provider, record model.FirewallRule) error {
|
||||||
ports, err := loadFirewallPortWhiteList()
|
ports, err := loadFirewallPortWhiteList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rules, err := record.RulesForProvider(filter.ProviderIptables)
|
rules, err := record.RulesForProvider(provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ func (s *FirewallService) loadFirewallSyncRules(ctx context.Context, request dto
|
|||||||
}
|
}
|
||||||
for _, native := range desired {
|
for _, native := range desired {
|
||||||
rule := native.Rule
|
rule := native.Rule
|
||||||
|
native.Protected = filter.RuleMatchesPortWhitelist(rule, ports)
|
||||||
rules = append(rules, &firewallSyncRule{desired: native, FirewallRuleSyncItem: dto.FirewallRuleSyncItem{SourceUUID: record.UUID, Rule: &rule}})
|
rules = append(rules, &firewallSyncRule{desired: native, FirewallRuleSyncItem: dto.FirewallRuleSyncItem{SourceUUID: record.UUID, Rule: &rule}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +211,7 @@ func (s *FirewallService) loadFirewallSyncRules(ctx context.Context, request dto
|
|||||||
}
|
}
|
||||||
drifted := firewallsync.RuleOrder(snapshot, ordered)
|
drifted := firewallsync.RuleOrder(snapshot, ordered)
|
||||||
for _, rule := range scoped {
|
for _, rule := range scoped {
|
||||||
if !drifted[rule.desired.Marker] {
|
if rule.desired.Protected || !drifted[rule.desired.Marker] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if rule.Status == firewallsync.StatusExisting {
|
if rule.Status == firewallsync.StatusExisting {
|
||||||
@@ -586,7 +587,12 @@ func (s *FirewallService) syncSystemRules(
|
|||||||
return dto.FirewallRuleSyncResult{}, err
|
return dto.FirewallRuleSyncResult{}, err
|
||||||
}
|
}
|
||||||
if running.Executing {
|
if running.Executing {
|
||||||
return runningFirewallRuleSyncResult(request, running.TaskID), nil
|
return dto.FirewallRuleSyncResult{
|
||||||
|
Subsystem: firewallSyncSubsystem(request.Subsystem),
|
||||||
|
TargetProvider: request.TargetProvider,
|
||||||
|
TaskID: running.TaskID,
|
||||||
|
Queued: true,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
if firewallSyncSubsystem(request.Subsystem) != "system" {
|
if firewallSyncSubsystem(request.Subsystem) != "system" {
|
||||||
return dto.FirewallRuleSyncResult{}, fmt.Errorf("%w: firewall synchronization tasks are only available for the system firewall", filter.ErrInvalidRule)
|
return dto.FirewallRuleSyncResult{}, fmt.Errorf("%w: firewall synchronization tasks are only available for the system firewall", filter.ErrInvalidRule)
|
||||||
@@ -660,15 +666,6 @@ func currentFirewallRuleSyncTaskLocked() (dto.FirewallRuleSyncTask, error) {
|
|||||||
return dto.FirewallRuleSyncTask{TaskID: record.ID, Executing: true}, nil
|
return dto.FirewallRuleSyncTask{TaskID: record.ID, Executing: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runningFirewallRuleSyncResult(request dto.FirewallRuleSyncRequest, taskID string) dto.FirewallRuleSyncResult {
|
|
||||||
return dto.FirewallRuleSyncResult{
|
|
||||||
Subsystem: firewallSyncSubsystem(request.Subsystem),
|
|
||||||
TargetProvider: request.TargetProvider,
|
|
||||||
TaskID: taskID,
|
|
||||||
Queued: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func whitelistRules(provider filter.Provider, ports, required []firewall.SystemPort) []filter.FirewallRule {
|
func whitelistRules(provider filter.Provider, ports, required []firewall.SystemPort) []filter.FirewallRule {
|
||||||
rules := make([]filter.FirewallRule, 0, len(ports)+len(required))
|
rules := make([]filter.FirewallRule, 0, len(ports)+len(required))
|
||||||
for _, port := range required {
|
for _, port := range required {
|
||||||
@@ -747,6 +744,10 @@ func (s *FirewallService) SyncPortWhitelist(ctx context.Context) error {
|
|||||||
if len(failures) > 0 {
|
if len(failures) > 0 {
|
||||||
return errors.Join(failures...)
|
return errors.Join(failures...)
|
||||||
}
|
}
|
||||||
|
if provider == filter.ProviderUFW && len(prepared) > 0 {
|
||||||
|
return s.syncUFWPortWhitelist(ctx, prepared)
|
||||||
|
}
|
||||||
|
|
||||||
for _, item := range prepared {
|
for _, item := range prepared {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -759,6 +760,55 @@ func (s *FirewallService) SyncPortWhitelist(ctx context.Context) error {
|
|||||||
return errors.Join(failures...)
|
return errors.Join(failures...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FirewallService) syncUFWPortWhitelist(ctx context.Context, prepared []preparedFirewallRuleCreate) error {
|
||||||
|
firewallRuleMutationMu.Lock()
|
||||||
|
defer firewallRuleMutationMu.Unlock()
|
||||||
|
runtime := prepared[0].runtime
|
||||||
|
snapshots, err := runtime.ObserveScopes(ctx, filter.ManagedInputScopes(filter.ProviderUFW))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for itemIndex, item := range prepared {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rule := item.request.Rule
|
||||||
|
var snapshot *filter.Snapshot
|
||||||
|
for index := range snapshots {
|
||||||
|
if snapshots[index].Scope.Key() == rule.Scope.Key() {
|
||||||
|
snapshot = &snapshots[index]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if snapshot == nil {
|
||||||
|
return fmt.Errorf("%w: missing UFW whitelist scope %s", filter.ErrInventoryUnavailable, rule.Scope.Key())
|
||||||
|
}
|
||||||
|
for _, notice := range snapshot.Notices {
|
||||||
|
if notice.Code == filter.ScopeNoticeManagedScopeInactive || notice.Code == filter.ScopeNoticeManagedScopeMissing {
|
||||||
|
return filter.ErrProviderUnavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
added, err := s.addWhitelistRuleFromSnapshot(ctx, item, *snapshot)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("add whitelist rule %s %s/%s [%s]: %w", rule.Scope.Family, rule.DestinationPort, rule.Protocol, rule.SourceAddress, err)
|
||||||
|
}
|
||||||
|
if !added {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if itemIndex+1 < len(prepared) {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
snapshots, err = runtime.ObserveScopes(ctx, filter.ManagedInputScopes(filter.ProviderUFW))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FirewallService) addWhitelistRule(ctx context.Context, prepared preparedFirewallRuleCreate) error {
|
func (s *FirewallService) addWhitelistRule(ctx context.Context, prepared preparedFirewallRuleCreate) error {
|
||||||
firewallRuleMutationMu.Lock()
|
firewallRuleMutationMu.Lock()
|
||||||
defer firewallRuleMutationMu.Unlock()
|
defer firewallRuleMutationMu.Unlock()
|
||||||
@@ -770,38 +820,85 @@ func (s *FirewallService) addWhitelistRule(ctx context.Context, prepared prepare
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = s.addWhitelistRuleFromSnapshot(ctx, prepared, snapshot)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FirewallService) addWhitelistRuleFromSnapshot(ctx context.Context, prepared preparedFirewallRuleCreate, snapshot filter.Snapshot) (bool, error) {
|
||||||
|
rule, runtime := prepared.request.Rule, prepared.runtime
|
||||||
for _, observed := range snapshot.Rules {
|
for _, observed := range snapshot.Rules {
|
||||||
if observed.ParseStatus == filter.ParseStatusSupported {
|
if observed.ParseStatus == filter.ParseStatusSupported {
|
||||||
if same, err := filter.SameRuleContent(rule, observed.Rule); err == nil && same {
|
if same, err := filter.SameRuleContent(rule, observed.Rule); err == nil && same {
|
||||||
return nil
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := filter.CheckObservedRuleCollisions(snapshot, rule, nil); err != nil {
|
if err := filter.CheckObservedRuleCollisions(snapshot, rule, nil); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if rule.Scope.Chain == filter.BasicBeforeChain {
|
if rule.Scope.Chain == filter.BasicBeforeChain {
|
||||||
|
position := int64(1)
|
||||||
|
rule.OrderIndex = &position
|
||||||
rule.UUID = uuid.NewString()
|
rule.UUID = uuid.NewString()
|
||||||
return runtime.ExecuteCreate(ctx, snapshot, []filter.DesiredChange{{Operation: filter.ChangeCreate, After: &rule}})
|
return true, runtime.ExecuteCreate(ctx, snapshot, []filter.DesiredChange{{Operation: filter.ChangeCreate, After: &rule}})
|
||||||
}
|
}
|
||||||
stored, err := s.rules.List(ctx)
|
stored, err := s.rules.List(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
model.SortFirewallRules(stored, rule.Scope.Provider)
|
||||||
|
markers := make([]string, 0, len(stored))
|
||||||
|
var existing *filter.DesiredRule
|
||||||
|
var firstSequence *int64
|
||||||
for _, record := range stored {
|
for _, record := range stored {
|
||||||
compiled, err := s.compileStoredFirewallRules(ctx, record, rule.Scope.Provider)
|
compiled, err := s.compileStoredFirewallRules(ctx, record, rule.Scope.Provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
if isFirewallPolicyIncompatible(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
for _, candidate := range compiled {
|
for _, candidate := range compiled {
|
||||||
|
if candidate.Rule.Scope.Key() == rule.Scope.Key() && candidate.Marker != "" {
|
||||||
|
markers = append(markers, candidate.Marker)
|
||||||
|
if firstSequence == nil && record.Sequence != nil {
|
||||||
|
firstSequence = record.Sequence
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := filter.CheckRuleCollision(rule, candidate.Rule); errors.Is(err, filter.ErrRuleOperation) {
|
if err := filter.CheckRuleCollision(rule, candidate.Rule); errors.Is(err, filter.ErrRuleOperation) {
|
||||||
return runtime.ExecuteCreate(ctx, snapshot, []filter.DesiredChange{{Operation: filter.ChangeCreate, After: &candidate.Rule}})
|
copy := candidate
|
||||||
|
existing = ©
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.applyCreateRules(ctx, runtime, snapshot, stored, []preparedFirewallRuleCreate{prepared})[0]
|
if existing != nil {
|
||||||
|
existing.Rule.OrderIndex = firewallsync.InsertionPosition(snapshot, markers, existing.Marker)
|
||||||
|
return true, runtime.ExecuteCreate(ctx, snapshot, []filter.DesiredChange{{
|
||||||
|
Operation: filter.ChangeCreate, After: &existing.Rule,
|
||||||
|
Append: rule.Scope.Provider == filter.ProviderUFW && existing.Rule.OrderIndex == nil,
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
if rule.Scope.Provider != filter.ProviderFirewalld {
|
||||||
|
position := int64(1)
|
||||||
|
rule.OrderIndex = &position
|
||||||
|
record, err := firewallRuleModelForCreate(rule, prepared.request, constant.FirewallRuleOriginCreated)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sequence := model.FirewallRuleSequenceStep
|
||||||
|
if firstSequence != nil {
|
||||||
|
sequence = *firstSequence - model.FirewallRuleSequenceStep
|
||||||
|
}
|
||||||
|
record.UUID, record.Sequence = uuid.NewString(), &sequence
|
||||||
|
rule.UUID = record.UUID
|
||||||
|
if err := runtime.ExecuteCreate(ctx, snapshot, []filter.DesiredChange{{Operation: filter.ChangeCreate, After: &rule}}); err != nil {
|
||||||
|
return false, firewallCreateExecutionError(err)
|
||||||
|
}
|
||||||
|
return true, s.saveFirewallRule(ctx, &record)
|
||||||
|
}
|
||||||
|
return true, s.applyCreateRules(ctx, runtime, snapshot, stored, []preparedFirewallRuleCreate{prepared})[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
type forwardingRuleSyncCandidate struct {
|
type forwardingRuleSyncCandidate struct {
|
||||||
@@ -813,7 +910,7 @@ func (s *ForwardingService) loadRuleSyncCandidates(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
targetProvider filter.Provider,
|
targetProvider filter.Provider,
|
||||||
) (*forwarding.Manager, []forwardingRuleSyncCandidate, []forwarding.Rule, bool, error) {
|
) (*forwarding.Manager, []forwardingRuleSyncCandidate, []forwarding.Rule, bool, error) {
|
||||||
target, err := s.manager()
|
target, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, false, err
|
return nil, nil, nil, false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func (s *ForwardingService) LoadBaseInfo() (dto.FirewallSubsystemStatus, error)
|
|||||||
baseInfo := dto.FirewallSubsystemStatus{
|
baseInfo := dto.FirewallSubsystemStatus{
|
||||||
Version: "-", Name: forwardingDisplayName(selected), Backend: selected, SyncError: lastForwardingSyncError(),
|
Version: "-", Name: forwardingDisplayName(selected), Backend: selected, SyncError: lastForwardingSyncError(),
|
||||||
}
|
}
|
||||||
manager, err := s.manager()
|
manager, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, errForwardingBackendUnavailable) {
|
if errors.Is(err, errForwardingBackendUnavailable) {
|
||||||
baseInfo.Reason = constant.FirewallBackendNotInstalled
|
baseInfo.Reason = constant.FirewallBackendNotInstalled
|
||||||
@@ -124,7 +124,7 @@ func (s *ForwardingService) SearchRules(request dto.ForwardRuleSearch) (int64, [
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
manager, err := s.manager()
|
manager, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
@@ -244,7 +244,7 @@ func (s *ForwardingService) operateRules(ctx context.Context, request dto.Forwar
|
|||||||
func (s *ForwardingService) Enable() error {
|
func (s *ForwardingService) Enable() error {
|
||||||
forwardingMutationMu.Lock()
|
forwardingMutationMu.Lock()
|
||||||
defer forwardingMutationMu.Unlock()
|
defer forwardingMutationMu.Unlock()
|
||||||
manager, err := s.manager()
|
manager, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
recordForwardingSyncError(err)
|
recordForwardingSyncError(err)
|
||||||
return err
|
return err
|
||||||
@@ -283,7 +283,7 @@ func (s *ForwardingService) QueueInitialization(
|
|||||||
forwardingMutationMu.Lock()
|
forwardingMutationMu.Lock()
|
||||||
defer forwardingMutationMu.Unlock()
|
defer forwardingMutationMu.Unlock()
|
||||||
var err error
|
var err error
|
||||||
manager, err = s.manager()
|
manager, err = s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
recordForwardingSyncError(err)
|
recordForwardingSyncError(err)
|
||||||
return err
|
return err
|
||||||
@@ -329,7 +329,7 @@ func (s *ForwardingService) Restore(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
manager, err := s.manager()
|
manager, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
recordForwardingSyncError(err)
|
recordForwardingSyncError(err)
|
||||||
return err
|
return err
|
||||||
@@ -349,7 +349,7 @@ func (s *ForwardingService) Restore(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ForwardingService) reconcile(rules []forwarding.Rule) error {
|
func (s *ForwardingService) reconcile(rules []forwarding.Rule) error {
|
||||||
manager, err := s.manager()
|
manager, err := s.managerFactory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -548,10 +548,6 @@ func forwardingOperationsOnlyRemove(operations []dto.ForwardRuleOperation) bool
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ForwardingService) manager() (*forwarding.Manager, error) {
|
|
||||||
return s.managerFactory()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newForwardingManager() (*forwarding.Manager, error) {
|
func newForwardingManager() (*forwarding.Manager, error) {
|
||||||
return newForwardingManagerFor(configuredForwardingBackend())
|
return newForwardingManagerFor(configuredForwardingBackend())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,8 +336,12 @@ func compileChange(snapshot filter.Snapshot, change filter.DesiredChange) (filte
|
|||||||
return filter.NativeRulePlan{}, fmt.Errorf("%w: create target is out of range", filter.ErrInvalidRule)
|
return filter.NativeRulePlan{}, fmt.Errorf("%w: create target is out of range", filter.ErrInvalidRule)
|
||||||
}
|
}
|
||||||
command := insertCommand(position, normalized, marker)
|
command := insertCommand(position, normalized, marker)
|
||||||
if change.Append || position == maximumObservedPosition(snapshot)+1 {
|
if !change.Append && normalized.OrderIndex != nil && position == 1 {
|
||||||
|
command = filter.NativeCommand{Executable: "ufw", Args: append([]string{"prepend"}, compileRuleArgs(normalized, marker)...)}
|
||||||
|
} else if change.Append || position == maximumObservedPosition(snapshot)+1 {
|
||||||
command = commentCommand(normalized, marker)
|
command = commentCommand(normalized, marker)
|
||||||
|
}
|
||||||
|
if command.Args[0] != "insert" {
|
||||||
plan.Expected.Locator.NativeID = ""
|
plan.Expected.Locator.NativeID = ""
|
||||||
plan.Expected.Locator.Position = nil
|
plan.Expected.Locator.Position = nil
|
||||||
}
|
}
|
||||||
@@ -740,7 +744,7 @@ func validateCommand(command filter.NativeCommand) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch first {
|
switch first {
|
||||||
case "insert", "allow", "deny", "reject":
|
case "insert", "prepend", "allow", "deny", "reject":
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: unsupported ufw command %q", filter.ErrInvalidRule, first)
|
return fmt.Errorf("%w: unsupported ufw command %q", filter.ErrInvalidRule, first)
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ func RuleMatchesPortWhitelist(rule FirewallRule, ports []PortWhitelist) bool {
|
|||||||
if err != nil || rule.Action != ActionAccept || rule.SourcePort != "" || rule.DestinationAddress != "" || rule.Interface != "" || len(rule.ConnectionStates) != 0 {
|
if err != nil || rule.Action != ActionAccept || rule.SourcePort != "" || rule.DestinationAddress != "" || rule.Interface != "" || len(rule.ConnectionStates) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if rule.Scope.Provider == ProviderFirewalld && (rule.NativeKind == NativeKindZonePort ||
|
||||||
|
(rule.NativeKind == NativeKindRule && rule.Scope.Family == FamilyInet && rule.Priority == nil)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
families := []Family{rule.Scope.Family}
|
families := []Family{rule.Scope.Family}
|
||||||
if rule.Scope.Family == FamilyInet {
|
if rule.Scope.Family == FamilyInet {
|
||||||
families = []Family{FamilyIPv4, FamilyIPv6}
|
families = []Family{FamilyIPv4, FamilyIPv6}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (m *Manager) Operate(operation firewall.BaseOperation) error {
|
|||||||
|
|
||||||
func (m *Manager) enableBase(prepare bool) error {
|
func (m *Manager) enableBase(prepare bool) error {
|
||||||
if prepare {
|
if prepare {
|
||||||
if err := ensureBaseChains(); err != nil {
|
if err := ensureBaseChainsFamily(false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := m.initPreRules(); err != nil {
|
if err := m.initPreRules(); err != nil {
|
||||||
@@ -71,7 +71,7 @@ func (m *Manager) enableBase(prepare bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := bindBaseChains(); err != nil {
|
if err := setBaseChainBindings(false, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if prepare {
|
if prepare {
|
||||||
@@ -97,10 +97,6 @@ func (m *Manager) disableBase() error {
|
|||||||
return m.updateSetting("IptablesStatus", constant.StatusDisable)
|
return m.updateSetting("IptablesStatus", constant.StatusDisable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureBaseChains() error {
|
|
||||||
return ensureBaseChainsFamily(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureBaseChainsFamily(ipv6 bool) error {
|
func ensureBaseChainsFamily(ipv6 bool) error {
|
||||||
commands, err := lifecycle.ResolveIptablesCommands()
|
commands, err := lifecycle.ResolveIptablesCommands()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,10 +165,6 @@ func cleanupBaseChains(ipv6 bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindBaseChains() error {
|
|
||||||
return setBaseChainBindings(false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setBaseChainBindings(ipv6, bind bool) error {
|
func setBaseChainBindings(ipv6, bind bool) error {
|
||||||
commands, err := lifecycle.ResolveIptablesCommands()
|
commands, err := lifecycle.ResolveIptablesCommands()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -250,7 +242,7 @@ func RestoreBaseChains(requiredPorts []firewall.PortWhitelist) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ensureBaseChains(); err != nil {
|
if err := ensureBaseChainsFamily(false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
input, err := buildBaseChainsRestoreScript(global.Dir.FirewallDir, false, requiredPorts...)
|
input, err := buildBaseChainsRestoreScript(global.Dir.FirewallDir, false, requiredPorts...)
|
||||||
@@ -320,6 +312,9 @@ func buildBaseChainsRestoreScript(firewallDir string, ipv6 bool, requiredPorts .
|
|||||||
}
|
}
|
||||||
for _, rule := range defaults {
|
for _, rule := range defaults {
|
||||||
if !containsIptablesRule(script.String(), rule) {
|
if !containsIptablesRule(script.String(), rule) {
|
||||||
|
if strings.HasPrefix(rule, "-A "+BasicBeforeChain+" ") && strings.Contains(rule, " --dport ") {
|
||||||
|
rule = strings.Replace(rule, "-A "+BasicBeforeChain+" ", "-I "+BasicBeforeChain+" 1 ", 1)
|
||||||
|
}
|
||||||
script.WriteString(rule + "\n")
|
script.WriteString(rule + "\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,7 +437,7 @@ func buildRequiredPortsRestoreScript(
|
|||||||
for _, rule := range desired {
|
for _, rule := range desired {
|
||||||
line := iptablesSystemPortRuleLine(rule)
|
line := iptablesSystemPortRuleLine(rule)
|
||||||
if rule.Family == family && !containsIptablesRule(beforeRaw, line) {
|
if rule.Family == family && !containsIptablesRule(beforeRaw, line) {
|
||||||
commands = append(commands, line)
|
commands = append(commands, strings.Replace(line, "-A "+BasicBeforeChain+" ", "-I "+BasicBeforeChain+" 1 ", 1))
|
||||||
beforeRaw += "\n" + line
|
beforeRaw += "\n" + line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
@@ -113,7 +115,7 @@ func (m *Manager) ensureBaseChains() error {
|
|||||||
|
|
||||||
func requiredPortCommand(tableFamily string, rule firewall.SystemPort) []string {
|
func requiredPortCommand(tableFamily string, rule firewall.SystemPort) []string {
|
||||||
command := []string{
|
command := []string{
|
||||||
"add", "rule", tableFamily, TableName, BasicBeforeChain,
|
"insert", "rule", tableFamily, TableName, BasicBeforeChain,
|
||||||
}
|
}
|
||||||
if rule.SourceAddress != "" {
|
if rule.SourceAddress != "" {
|
||||||
command = append(command, tableFamily, "saddr", rule.SourceAddress)
|
command = append(command, tableFamily, "saddr", rule.SourceAddress)
|
||||||
@@ -174,6 +176,29 @@ func containsRequiredPortRule(output, expression string) bool {
|
|||||||
line = strings.NewReplacer("{", "", "}", "", ", ", ",", " ,", ",").Replace(line)
|
line = strings.NewReplacer("{", "", "}", "", ", ", ",", " ,", ",").Replace(line)
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
for index, field := range fields {
|
for index, field := range fields {
|
||||||
|
if index >= 2 && fields[index-2] == "ct" && fields[index-1] == "state" {
|
||||||
|
states := strings.Split(field, ",")
|
||||||
|
for i, state := range states {
|
||||||
|
value, err := strconv.ParseUint(state, 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch value {
|
||||||
|
case 1:
|
||||||
|
states[i] = "invalid"
|
||||||
|
case 2:
|
||||||
|
states[i] = "established"
|
||||||
|
case 4:
|
||||||
|
states[i] = "related"
|
||||||
|
case 8:
|
||||||
|
states[i] = "new"
|
||||||
|
case 64:
|
||||||
|
states[i] = "untracked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slices.Sort(states)
|
||||||
|
fields[index] = strings.Join(states, ",")
|
||||||
|
}
|
||||||
if prefix, err := netip.ParsePrefix(field); err == nil {
|
if prefix, err := netip.ParsePrefix(field); err == nil {
|
||||||
prefix = prefix.Masked()
|
prefix = prefix.Masked()
|
||||||
fields[index] = prefix.String()
|
fields[index] = prefix.String()
|
||||||
|
|||||||
@@ -871,12 +871,8 @@ const loadAllInventoryItems = async () => {
|
|||||||
return response.data.items || [];
|
return response.data.items || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetPagination = () => {
|
|
||||||
paginationConfig.currentPage = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const searchWithReset = () => {
|
const searchWithReset = () => {
|
||||||
resetPagination();
|
paginationConfig.currentPage = 1;
|
||||||
return searchPage();
|
return searchPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,6 @@ const familyRetrying = ref(false);
|
|||||||
const taskLogRef = ref();
|
const taskLogRef = ref();
|
||||||
const lifecycleSubmitting = ref(false);
|
const lifecycleSubmitting = ref(false);
|
||||||
const lifecycleBusy = computed(() => lifecycleSubmitting.value || !!baseInfo.value.lifecycleTaskID);
|
const lifecycleBusy = computed(() => lifecycleSubmitting.value || !!baseInfo.value.lifecycleTaskID);
|
||||||
let lifecycleTimer: ReturnType<typeof setTimeout>;
|
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
let baseInfoRequestID = 0;
|
let baseInfoRequestID = 0;
|
||||||
const backendName = computed(() => baseInfo.value.backend || baseInfo.value.name);
|
const backendName = computed(() => baseInfo.value.backend || baseInfo.value.name);
|
||||||
@@ -306,7 +305,7 @@ const initActionHelper = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const acceptParams = (): void => {
|
const acceptParams = (): void => {
|
||||||
loadBaseInfo(true);
|
loadBaseInfo();
|
||||||
loadDocker();
|
loadDocker();
|
||||||
};
|
};
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
@@ -319,14 +318,12 @@ const emit = defineEmits([
|
|||||||
'update:version',
|
'update:version',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const loadBaseInfo = async (search: boolean) => {
|
const loadBaseInfo = async () => {
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
const requestID = ++baseInfoRequestID;
|
const requestID = ++baseInfoRequestID;
|
||||||
clearTimeout(lifecycleTimer);
|
|
||||||
try {
|
try {
|
||||||
const res = await (props.currentTab === 'forward' ? loadForwardBaseInfo() : loadFireBaseInfo(props.currentTab));
|
const res = await (props.currentTab === 'forward' ? loadForwardBaseInfo() : loadFireBaseInfo(props.currentTab));
|
||||||
if (disposed || requestID !== baseInfoRequestID) return;
|
if (disposed || requestID !== baseInfoRequestID) return;
|
||||||
const lifecycleCompleted = Boolean(baseInfo.value.lifecycleTaskID) && !res.data.lifecycleTaskID;
|
|
||||||
baseInfo.value = {
|
baseInfo.value = {
|
||||||
...res.data,
|
...res.data,
|
||||||
ipv4: res.data.ipv4 || { available: true, initialized: res.data.isInit, bound: res.data.isBind },
|
ipv4: res.data.ipv4 || { available: true, initialized: res.data.isInit, bound: res.data.isBind },
|
||||||
@@ -347,7 +344,7 @@ const loadBaseInfo = async (search: boolean) => {
|
|||||||
emit('update:is-bind', isDirectManaged.value ? anyFamilyBound.value : baseInfo.value.isBind);
|
emit('update:is-bind', isDirectManaged.value ? anyFamilyBound.value : baseInfo.value.isBind);
|
||||||
emit('update:version', baseInfo.value.version);
|
emit('update:version', baseInfo.value.version);
|
||||||
|
|
||||||
if ((search || lifecycleCompleted) && !baseInfo.value.lifecycleTaskID) {
|
if (!baseInfo.value.lifecycleTaskID) {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
emit('search');
|
emit('search');
|
||||||
} else {
|
} else {
|
||||||
@@ -359,10 +356,6 @@ const loadBaseInfo = async (search: boolean) => {
|
|||||||
emit('update:is-init', false);
|
emit('update:is-init', false);
|
||||||
emit('update:name', '-');
|
emit('update:name', '-');
|
||||||
emit('update:version', '');
|
emit('update:version', '');
|
||||||
} finally {
|
|
||||||
if (!disposed && requestID === baseInfoRequestID && baseInfo.value.lifecycleTaskID) {
|
|
||||||
lifecycleTimer = setTimeout(() => loadBaseInfo(false), 3000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -413,11 +406,11 @@ const onInit = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
await loadBaseInfo(true);
|
await loadBaseInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInitializationTaskClose = () => {
|
const handleInitializationTaskClose = () => {
|
||||||
loadBaseInfo(true);
|
loadBaseInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBind = async () => {
|
const onBind = async () => {
|
||||||
@@ -431,7 +424,7 @@ const onBind = async () => {
|
|||||||
}
|
}
|
||||||
await operateFilterChain('1PANEL_BASIC', 'bind-base');
|
await operateFilterChain('1PANEL_BASIC', 'bind-base');
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
await loadBaseInfo(true);
|
await loadBaseInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRetryFamilyIssues = async () => {
|
const onRetryFamilyIssues = async () => {
|
||||||
@@ -448,7 +441,7 @@ const onRetryFamilyIssues = async () => {
|
|||||||
await operateFilterChain('1PANEL_BASIC', 'bind-base');
|
await operateFilterChain('1PANEL_BASIC', 'bind-base');
|
||||||
}
|
}
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
await loadBaseInfo(true);
|
await loadBaseInfo();
|
||||||
} finally {
|
} finally {
|
||||||
familyRetrying.value = false;
|
familyRetrying.value = false;
|
||||||
}
|
}
|
||||||
@@ -465,7 +458,7 @@ const onUnBind = async () => {
|
|||||||
}
|
}
|
||||||
await operateFilterChain('1PANEL_BASIC', 'unbind-base');
|
await operateFilterChain('1PANEL_BASIC', 'unbind-base');
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
await loadBaseInfo(true);
|
await loadBaseInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onOperate = async (op: string) => {
|
const onOperate = async (op: string) => {
|
||||||
@@ -499,13 +492,12 @@ const submitLifecycleOperation = async (restartDocker: boolean) => {
|
|||||||
baseInfo.value.lifecycleTaskID = result.taskID;
|
baseInfo.value.lifecycleTaskID = result.taskID;
|
||||||
emit('update:loading', false);
|
emit('update:loading', false);
|
||||||
openLifecycleTask();
|
openLifecycleTask();
|
||||||
await loadBaseInfo(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
await loadBaseInfo(true);
|
await loadBaseInfo();
|
||||||
} catch {
|
} catch {
|
||||||
if (!disposed) await loadBaseInfo(true);
|
if (!disposed) await loadBaseInfo();
|
||||||
} finally {
|
} finally {
|
||||||
lifecycleSubmitting.value = false;
|
lifecycleSubmitting.value = false;
|
||||||
}
|
}
|
||||||
@@ -513,7 +505,6 @@ const submitLifecycleOperation = async (restartDocker: boolean) => {
|
|||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
disposed = true;
|
disposed = true;
|
||||||
clearTimeout(lifecycleTimer);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
Reference in New Issue
Block a user