Files
1Panel/agent/app/service/firewall_setting.go
T

176 lines
5.0 KiB
Go

package service
import (
"fmt"
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
fireClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
)
type firewallPortWhitelist struct {
Port string
Protocol string
}
func loadConfiguredFirewallPortWhiteList() ([]firewallPortWhitelist, error) {
value, err := settingRepo.GetValueByKey(constant.FirewallPortWhiteList)
if err != nil {
value = constant.FirewallPortWhiteListValue
if err := settingRepo.UpdateOrCreate(constant.FirewallPortWhiteList, value); err != nil {
return nil, err
}
}
return parseFirewallPortWhiteList(value)
}
func loadFirewallPortWhiteList() ([]firewallPortWhitelist, error) {
portWhiteList, err := loadConfiguredFirewallPortWhiteList()
if err != nil {
return nil, err
}
requiredPorts, err := loadRequiredFirewallPortWhiteList()
if err != nil {
return nil, err
}
return normalizeFirewallPortWhiteList(append(portWhiteList, requiredPorts...)), nil
}
func loadRequiredFirewallPortWhiteList() ([]firewallPortWhitelist, error) {
panelPort := LoadPanelPort()
if panelPort == "" {
return nil, fmt.Errorf("find 1panel service port failed")
}
return normalizeFirewallPortWhiteList([]firewallPortWhitelist{
{Port: panelPort, Protocol: "tcp"},
{Port: loadSSHPort(), Protocol: "tcp"},
}), nil
}
func parseFirewallPortWhiteList(value string) ([]firewallPortWhitelist, error) {
items := strings.FieldsFunc(value, func(r rune) bool {
return r == ',' || r == '\n' || r == ';' || r == ' '
})
ports := make([]firewallPortWhitelist, 0, len(items))
exists := make(map[string]struct{})
for _, item := range items {
item = strings.TrimSpace(item)
if item == "" {
continue
}
port, protocol, ok := strings.Cut(item, "/")
if !ok {
protocol = "tcp"
}
port = strings.TrimSpace(port)
protocol = strings.ToLower(strings.TrimSpace(protocol))
if protocol != "tcp" && protocol != "udp" {
return nil, fmt.Errorf("invalid firewall port whitelist protocol: %s", item)
}
portNum, err := strconv.Atoi(port)
if err != nil || portNum < 1 || portNum > 65535 {
return nil, fmt.Errorf("invalid firewall port whitelist: %s", item)
}
key := fmt.Sprintf("%d/%s", portNum, protocol)
if _, ok := exists[key]; ok {
continue
}
exists[key] = struct{}{}
ports = append(ports, firewallPortWhitelist{Port: strconv.Itoa(portNum), Protocol: protocol})
}
return ports, nil
}
func normalizeFirewallPortWhiteList(portWhiteList []firewallPortWhitelist) []firewallPortWhitelist {
ports := make([]firewallPortWhitelist, 0, len(portWhiteList))
exists := make(map[string]struct{})
for _, item := range portWhiteList {
if item.Port == "" {
continue
}
key := fmt.Sprintf("%s/%s", item.Port, item.Protocol)
if _, ok := exists[key]; ok {
continue
}
exists[key] = struct{}{}
ports = append(ports, item)
}
return ports
}
func syncFirewallPortWhiteListAfterUpdate(oldValue string) error {
client, err := firewall.NewFirewallClient()
if err != nil {
return err
}
if client.Name() == "iptables" {
isInit, _ := iptables.LoadInitStatus("iptables", "base")
if !isInit {
return nil
}
oldPortWhiteList, err := parseFirewallPortWhiteList(oldValue)
if err != nil {
return err
}
return syncIptablesFirewallPortWhiteList(true, oldPortWhiteList)
}
isActive, _ := client.Status()
if !isActive {
return nil
}
portWhiteList, err := loadFirewallPortWhiteList()
if err != nil {
return err
}
oldPortWhiteList, err := parseFirewallPortWhiteList(oldValue)
if err != nil {
return err
}
requiredPorts, err := loadRequiredFirewallPortWhiteList()
if err != nil {
return err
}
oldPortWhiteList = normalizeFirewallPortWhiteList(append(oldPortWhiteList, requiredPorts...))
return syncFirewallClientPortWhiteList(client, oldPortWhiteList, portWhiteList)
}
func syncFirewallClientPortWhiteList(client firewall.FirewallClient, oldPortWhiteList, portWhiteList []firewallPortWhitelist) error {
oldPorts := firewallPortWhiteListMap(oldPortWhiteList)
newPorts := firewallPortWhiteListMap(portWhiteList)
for _, item := range oldPortWhiteList {
key := firewallPortWhiteListKey(item)
if _, ok := newPorts[key]; ok {
continue
}
if err := client.Port(fireClient.FireInfo{Port: item.Port, Protocol: item.Protocol, Strategy: "accept"}, "remove"); err != nil {
return err
}
}
for _, item := range portWhiteList {
key := firewallPortWhiteListKey(item)
if _, ok := oldPorts[key]; ok {
continue
}
if err := client.Port(fireClient.FireInfo{Port: item.Port, Protocol: item.Protocol, Strategy: "accept"}, "add"); err != nil {
return err
}
}
return client.Reload()
}
func firewallPortWhiteListMap(portWhiteList []firewallPortWhitelist) map[string]struct{} {
ports := make(map[string]struct{})
for _, item := range portWhiteList {
ports[firewallPortWhiteListKey(item)] = struct{}{}
}
return ports
}
func firewallPortWhiteListKey(item firewallPortWhitelist) string {
return item.Port + "/" + item.Protocol
}