优化Firewalld添加端口方法,自动聚合连续的端口号

This commit is contained in:
刘祥超
2022-07-21 11:53:23 +08:00
parent 25c11f3d69
commit 62f9d1f09a
4 changed files with 156 additions and 37 deletions

View File

@@ -75,6 +75,24 @@ func (this *Firewalld) AllowPort(port int, protocol string) error {
return nil
}
func (this *Firewalld) AllowPortRangesPermanently(portRanges [][2]int, protocol string) error {
for _, portRange := range portRanges {
var port = this.PortRangeString(portRange, protocol)
{
var cmd = exec.Command(this.exe, "--add-port="+port, "--permanent")
this.pushCmd(cmd)
}
{
var cmd = exec.Command(this.exe, "--add-port="+port)
this.pushCmd(cmd)
}
}
return nil
}
func (this *Firewalld) RemovePort(port int, protocol string) error {
if !this.isReady {
return nil
@@ -84,6 +102,30 @@ func (this *Firewalld) RemovePort(port int, protocol string) error {
return nil
}
func (this *Firewalld) RemovePortRangePermanently(portRange [2]int, protocol string) error {
var port = this.PortRangeString(portRange, protocol)
{
var cmd = exec.Command(this.exe, "--remove-port="+port, "--permanent")
this.pushCmd(cmd)
}
{
var cmd = exec.Command(this.exe, "--remove-port="+port)
this.pushCmd(cmd)
}
return nil
}
func (this *Firewalld) PortRangeString(portRange [2]int, protocol string) string {
if portRange[0] == portRange[1] {
return types.String(portRange[0]) + "/" + protocol
} else {
return types.String(portRange[0]) + "-" + types.String(portRange[1]) + "/" + protocol
}
}
func (this *Firewalld) RejectSourceIP(ip string, timeoutSeconds int) error {
if !this.isReady {
return nil

View File

@@ -5,11 +5,14 @@ import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeNode/internal/firewalls"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"net/url"
"os/exec"
"regexp"
@@ -31,15 +34,19 @@ type ListenerManager struct {
retryListenerMap map[string]*Listener // 需要重试的监听器 addr => Listener
ticker *time.Ticker
firewalld *firewalls.Firewalld
lastPortStrings string
lastTCPPortRanges [][2]int
lastUDPPortRanges [][2]int
}
// NewListenerManager 获取新对象
func NewListenerManager() *ListenerManager {
manager := &ListenerManager{
var manager = &ListenerManager{
listenersMap: map[string]*Listener{},
retryListenerMap: map[string]*Listener{},
ticker: time.NewTicker(1 * time.Minute),
firewalld: firewalls.NewFirewalld(),
}
// 提升测试效率
@@ -147,7 +154,7 @@ func (this *ListenerManager) Start(node *nodeconfigs.NodeConfig) error {
}
// 加入到firewalld
this.addToFirewalld(groupAddrs)
go this.addToFirewalld(groupAddrs)
return nil
}
@@ -226,8 +233,14 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
return
}
if this.firewalld == nil || !this.firewalld.IsReady() {
return
}
// 组合端口号
var ports = []string{}
var portStrings = []string{}
var udpPorts = []int{}
var tcpPorts = []int{}
for _, addr := range groupAddrs {
var protocol = "tcp"
if strings.HasPrefix(addr, "udp") {
@@ -237,52 +250,72 @@ func (this *ListenerManager) addToFirewalld(groupAddrs []string) {
var lastIndex = strings.LastIndex(addr, ":")
if lastIndex > 0 {
var portString = addr[lastIndex+1:]
ports = append(ports, portString+"/"+protocol)
portStrings = append(portStrings, portString+"/"+protocol)
switch protocol {
case "tcp":
tcpPorts = append(tcpPorts, types.Int(portString))
case "udp":
udpPorts = append(udpPorts, types.Int(portString))
}
}
if len(ports) == 0 {
}
if len(portStrings) == 0 {
return
}
// 检查是否有变化
sort.Strings(ports)
var newPortStrings = strings.Join(ports, ",")
sort.Strings(portStrings)
var newPortStrings = strings.Join(portStrings, ",")
if newPortStrings == this.lastPortStrings {
return
}
this.lastPortStrings = newPortStrings
firewallCmd, err := exec.LookPath("firewall-cmd")
if err != nil || len(firewallCmd) == 0 {
return
remotelogs.Println("FIREWALLD", "opening ports automatically ...")
defer func() {
remotelogs.Println("FIREWALLD", "open ports successfully")
}()
// 合并端口
var tcpPortRanges = utils.MergePorts(tcpPorts)
var udpPortRanges = utils.MergePorts(udpPorts)
defer func() {
this.lastTCPPortRanges = tcpPortRanges
this.lastUDPPortRanges = udpPortRanges
}()
// 删除老的不存在的端口
var tcpPortRangesMap = map[string]bool{}
var udpPortRangesMap = map[string]bool{}
for _, portRange := range tcpPortRanges {
tcpPortRangesMap[this.firewalld.PortRangeString(portRange, "tcp")] = true
}
for _, portRange := range udpPortRanges {
udpPortRangesMap[this.firewalld.PortRangeString(portRange, "udp")] = true
}
// 检查状态
err = exec.Command(firewallCmd, "--state").Run()
if err != nil {
return
for _, portRange := range this.lastTCPPortRanges {
var s = this.firewalld.PortRangeString(portRange, "tcp")
_, ok := tcpPortRangesMap[s]
if ok {
continue
}
remotelogs.Println("FIREWALLD", "remove port '"+s+"'")
_ = this.firewalld.RemovePortRangePermanently(portRange, "tcp")
}
for _, portRange := range this.lastUDPPortRanges {
var s = this.firewalld.PortRangeString(portRange, "udp")
_, ok := udpPortRangesMap[s]
if ok {
continue
}
remotelogs.Println("FIREWALLD", "remove port '"+s+"'")
_ = this.firewalld.RemovePortRangePermanently(portRange, "udp")
}
remotelogs.Println("FIREWALLD", "open ports automatically")
for _, port := range ports {
{
// TODO 需要支持sudo
var cmd = exec.Command(firewallCmd, "--add-port="+port, "--permanent")
err = cmd.Run()
if err != nil {
remotelogs.Warn("FIREWALLD", "'"+cmd.String()+"': "+err.Error())
return
}
}
{
// TODO 需要支持sudo
var cmd = exec.Command(firewallCmd, "--add-port="+port)
err = cmd.Run()
if err != nil {
remotelogs.Warn("FIREWALLD", "'"+cmd.String()+"': "+err.Error())
return
}
}
}
// 添加新的
_ = this.firewalld.AllowPortRangesPermanently(tcpPortRanges, "tcp")
_ = this.firewalld.AllowPortRangesPermanently(udpPortRanges, "udp")
}

View File

@@ -7,6 +7,7 @@ import (
"context"
"github.com/iwind/TeaGo/logs"
"net"
"sort"
"syscall"
)
@@ -38,3 +39,34 @@ func ParseAddrHost(addr string) string {
}
return host
}
// MergePorts 聚合端口
// 返回 [ [fromPort, toPort], ... ]
func MergePorts(ports []int) [][2]int {
if len(ports) == 0 {
return nil
}
sort.Ints(ports)
var result = [][2]int{}
var lastRange = [2]int{0, 0}
var lastPort = -1
for _, port := range ports {
if port <= 0 /** 只处理有效的端口 **/ || port == lastPort /** 去重 **/ {
continue
}
if lastPort < 0 || port != lastPort+1 {
lastRange = [2]int{port, port}
result = append(result, lastRange)
} else { // 如果是连续的
lastRange[1] = port
result[len(result)-1] = lastRange
}
lastPort = port
}
return result
}

View File

@@ -12,3 +12,15 @@ func TestParseAddrHost(t *testing.T) {
t.Log(addr + " => " + utils.ParseAddrHost(addr))
}
}
func TestMergePorts(t *testing.T) {
for _, ports := range [][]int{
{},
{80},
{80, 83, 85},
{80, 81, 83, 85, 86, 87, 88, 90},
{0, 0, 1, 1, 2, 2, 2, 3, 3, 3},
} {
t.Log(ports, "=>", utils.MergePorts(ports))
}
}