mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
176 lines
5.0 KiB
Go
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
|
|
}
|