Files
1Panel/agent/init/firewall/firewall.go
ssongliu 7915230121 refactor: rebuild firewall management (#13628)
* refactor(firewall): rebuild rule management foundation

* refactor(firewall): streamline rule checks and inventory

* feat(firewall): improve native rule inventory

* refactor(firewall): refine rule management

* feat: add Docker port guard

* feat(firewall): support native nftables

* feat(firewall): add configurable firewall selection

* feat(firewall): support nftables docker port guard

* refactor(firewall): complete v2 rule management and migration

* refactor(firewall): align state and API contracts

* refactor(firewall): unify rule management operations

* feat: refine firewall v2 rules and forwarding

* fix(firewall): harden dual-stack rule management

* refactor(firewall): consolidate rule validation and persistence
2026-08-24 12:51:34 +08:00

167 lines
4.8 KiB
Go

package firewall
import (
"context"
"fmt"
"os"
"time"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/app/service"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
migrationutils "github.com/1Panel-dev/1Panel/agent/init/migration/migrations/utils"
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/iptables_helper"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/nftables_helper"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/ping"
)
func Init() {
ctx := context.Background()
client, err := service.NewSelectedSystemFirewallClient()
if err != nil {
global.LOG.Errorf("select system firewall provider failed, err: %v", err)
return
}
clientName := client.Name()
if err := migrationutils.TransferHostFirewall(ctx, clientName); err != nil {
global.LOG.Errorf("transfer legacy host firewall records failed, err: %v", err)
return
}
if err := migrationutils.TransferFirewallForwarding(ctx); err != nil {
global.LOG.Errorf("transfer legacy forwarding rules failed, err: %v", err)
return
}
if !needInit() {
repairIptablesIPv6BaseChains(clientName)
return
}
defer initDockerPortGuard(ctx)
InitPingStatus()
global.LOG.Info("initializing firewall settings...")
if err := initForwardingRules(ctx); err != nil {
global.LOG.Errorf("restore forwarding rules failed, err: %v", err)
return
}
if clientName == "nftables" {
if err := nftables_helper.Restore(); err != nil {
global.LOG.Errorf("restore nftables rules failed, err: %v", err)
}
status, _ := repo.NewISettingRepo().GetValueByKey("IptablesStatus")
if status == constant.StatusEnable {
if err := nftables_helper.Bind(); err != nil {
global.LOG.Errorf("bind nftables base chains failed, err: %v", err)
}
}
return
}
if clientName != "iptables" {
return
}
settingRepo := repo.NewISettingRepo()
panelPort := service.LoadPanelPort()
if len(panelPort) == 0 {
global.LOG.Errorf("find 1panel service port failed")
return
}
if err := iptables_helper.RestoreBaseChains(panelPort); err != nil {
global.LOG.Errorf("restore iptables base chains failed, err: %v", err)
return
}
global.LOG.Infof("loaded iptables rules for basic from file successfully")
firewallService := service.NewIFirewallService()
iptablesStatus, _ := settingRepo.GetValueByKey("IptablesStatus")
if iptablesStatus == constant.StatusEnable {
if err := firewallService.OperateFilterChain(dto.FilterChainOperation{Operate: string(firewall.BaseOperationBindWithoutInit)}); err != nil {
global.LOG.Errorf("bind base chains failed, err: %v", err)
return
}
}
}
func repairIptablesIPv6BaseChains(clientName string) {
if clientName != constant.FirewallProviderIptables {
return
}
settingRepo := repo.NewISettingRepo()
status, _ := settingRepo.GetValueByKey("IptablesStatus")
if status != constant.StatusEnable {
return
}
initialized, bound, err := iptables_helper.LoadFamilyInitStatus(constant.FirewallFamilyIPv6, "base")
if err == nil && initialized && bound {
return
}
panelPort := service.LoadPanelPort()
if err := iptables_helper.RepairIPv6BaseChains(panelPort); 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) {
const (
attempts = 12
delay = 5 * time.Second
)
var restoreErr error
for attempt := 1; attempt <= attempts; attempt++ {
restoreErr = service.ReconcileDockerPortGuard(ctx)
if restoreErr == nil {
return
}
if attempt == attempts {
break
}
timer := time.NewTimer(delay)
select {
case <-ctx.Done():
timer.Stop()
global.LOG.Warnf("restore Docker port guard on startup canceled, err: %v", ctx.Err())
return
case <-timer.C:
}
}
global.LOG.Warnf("restore Docker port guard on startup failed after %d attempts, err: %v", attempts, restoreErr)
}
func needInit() bool {
file, err := os.OpenFile("/run/1panel_boot_mark", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
if os.IsExist(err) {
return false
}
global.LOG.Errorf("check boot mark file failed: %v", err)
return true
}
defer file.Close()
fmt.Fprintf(file, "Boot Mark for 1panel\n")
return true
}
func InitPingStatus() {
global.LOG.Info("initializing ban ping status from settings...")
status := ping.LoadStatus()
statusInDB, _ := repo.NewISettingRepo().GetValueByKey("BanPing")
if statusInDB == status {
return
}
enable := "1"
if statusInDB == constant.StatusDisable {
enable = "0"
}
if err := ping.UpdateStatus(enable); err != nil {
global.LOG.Errorf("initialize ping status failed: %v", err)
}
}
func initForwardingRules(ctx context.Context) error {
return service.NewIForwardingService().Restore(ctx)
}