mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-10 20:50:25 +08:00
自动尝试安装nftables
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build linux
|
//go:build linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package firewalls
|
package firewalls
|
||||||
|
|
||||||
@@ -55,19 +54,13 @@ func init() {
|
|||||||
|
|
||||||
// DDoSProtectionManager DDoS防护
|
// DDoSProtectionManager DDoS防护
|
||||||
type DDoSProtectionManager struct {
|
type DDoSProtectionManager struct {
|
||||||
nftPath string
|
|
||||||
|
|
||||||
lastAllowIPList []string
|
lastAllowIPList []string
|
||||||
lastConfig []byte
|
lastConfig []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDDoSProtectionManager 获取新对象
|
// NewDDoSProtectionManager 获取新对象
|
||||||
func NewDDoSProtectionManager() *DDoSProtectionManager {
|
func NewDDoSProtectionManager() *DDoSProtectionManager {
|
||||||
nftPath, _ := exec.LookPath("nft")
|
return &DDoSProtectionManager{}
|
||||||
|
|
||||||
return &DDoSProtectionManager{
|
|
||||||
nftPath: nftPath,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply 应用配置
|
// Apply 应用配置
|
||||||
@@ -93,7 +86,7 @@ func (this *DDoSProtectionManager) Apply(config *ddosconfigs.ProtectionConfig) e
|
|||||||
}
|
}
|
||||||
remotelogs.Println("FIREWALL", "change DDoS protection config")
|
remotelogs.Println("FIREWALL", "change DDoS protection config")
|
||||||
|
|
||||||
if len(this.nftPath) == 0 {
|
if len(this.nftExe()) == 0 {
|
||||||
return errors.New("can not find nft command")
|
return errors.New("can not find nft command")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +149,11 @@ func (this *DDoSProtectionManager) Apply(config *ddosconfigs.ProtectionConfig) e
|
|||||||
|
|
||||||
// 添加TCP规则
|
// 添加TCP规则
|
||||||
func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig) error {
|
func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig) error {
|
||||||
|
var nftExe = this.nftExe()
|
||||||
|
if len(nftExe) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 检查nft版本不能小于0.9
|
// 检查nft版本不能小于0.9
|
||||||
if len(nftablesInstance.version) > 0 && stringutil.VersionCompare("0.9", nftablesInstance.version) > 0 {
|
if len(nftablesInstance.version) > 0 && stringutil.VersionCompare("0.9", nftablesInstance.version) > 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -265,7 +263,7 @@ func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig)
|
|||||||
// 添加新规则
|
// 添加新规则
|
||||||
for _, port := range ports {
|
for _, port := range ports {
|
||||||
if maxConnections > 0 {
|
if maxConnections > 0 {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "count", "over", types.String(maxConnections), "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "maxConnections", types.String(maxConnections)}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "count", "over", types.String(maxConnections), "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "maxConnections", types.String(maxConnections)}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -275,7 +273,7 @@ func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig)
|
|||||||
|
|
||||||
// TODO 让用户选择是drop还是reject
|
// TODO 让用户选择是drop还是reject
|
||||||
if maxConnectionsPerIP > 0 {
|
if maxConnectionsPerIP > 0 {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "meter", "meter-"+protocol+"-"+types.String(port)+"-max-connections", "{ "+protocol+" saddr ct count over "+types.String(maxConnectionsPerIP)+" }", "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "maxConnectionsPerIP", types.String(maxConnectionsPerIP)}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "meter", "meter-"+protocol+"-"+types.String(port)+"-max-connections", "{ "+protocol+" saddr ct count over "+types.String(maxConnectionsPerIP)+" }", "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "maxConnectionsPerIP", types.String(maxConnectionsPerIP)}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -287,14 +285,14 @@ func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig)
|
|||||||
// TODO 让用户选择是drop还是reject
|
// TODO 让用户选择是drop还是reject
|
||||||
if newConnectionsMinutelyRate > 0 {
|
if newConnectionsMinutelyRate > 0 {
|
||||||
if newConnectionsMinutelyRateBlockTimeout > 0 {
|
if newConnectionsMinutelyRateBlockTimeout > 0 {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsMinutelyRate)+"/minute burst "+types.String(newConnectionsMinutelyRate+3)+" packets }", "add", "@deny_set", "{"+protocol+" saddr timeout "+types.String(newConnectionsMinutelyRateBlockTimeout)+"s}", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsRate", types.String(newConnectionsMinutelyRate), types.String(newConnectionsMinutelyRateBlockTimeout)}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsMinutelyRate)+"/minute burst "+types.String(newConnectionsMinutelyRate+3)+" packets }", "add", "@deny_set", "{"+protocol+" saddr timeout "+types.String(newConnectionsMinutelyRateBlockTimeout)+"s}", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsRate", types.String(newConnectionsMinutelyRate), types.String(newConnectionsMinutelyRateBlockTimeout)}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("add nftables rule '" + cmd.String() + "' failed: " + err.Error() + " (" + cmd.Stderr() + ")")
|
return errors.New("add nftables rule '" + cmd.String() + "' failed: " + err.Error() + " (" + cmd.Stderr() + ")")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsMinutelyRate)+"/minute burst "+types.String(newConnectionsMinutelyRate+3)+" packets }" /**"add", "@deny_set", "{"+protocol+" saddr}",**/, "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsRate", "0"}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsMinutelyRate)+"/minute burst "+types.String(newConnectionsMinutelyRate+3)+" packets }" /**"add", "@deny_set", "{"+protocol+" saddr}",**/, "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsRate", "0"}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -307,14 +305,14 @@ func (this *DDoSProtectionManager) addTCPRules(tcpConfig *ddosconfigs.TCPConfig)
|
|||||||
// TODO 让用户选择是drop还是reject
|
// TODO 让用户选择是drop还是reject
|
||||||
if newConnectionsSecondlyRate > 0 {
|
if newConnectionsSecondlyRate > 0 {
|
||||||
if newConnectionsSecondlyRateBlockTimeout > 0 {
|
if newConnectionsSecondlyRateBlockTimeout > 0 {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-secondly-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsSecondlyRate)+"/second burst "+types.String(newConnectionsSecondlyRate+3)+" packets }", "add", "@deny_set", "{"+protocol+" saddr timeout "+types.String(newConnectionsSecondlyRateBlockTimeout)+"s}", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsSecondlyRate", types.String(newConnectionsSecondlyRate), types.String(newConnectionsSecondlyRateBlockTimeout)}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-secondly-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsSecondlyRate)+"/second burst "+types.String(newConnectionsSecondlyRate+3)+" packets }", "add", "@deny_set", "{"+protocol+" saddr timeout "+types.String(newConnectionsSecondlyRateBlockTimeout)+"s}", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsSecondlyRate", types.String(newConnectionsSecondlyRate), types.String(newConnectionsSecondlyRateBlockTimeout)}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("add nftables rule '" + cmd.String() + "' failed: " + err.Error() + " (" + cmd.Stderr() + ")")
|
return errors.New("add nftables rule '" + cmd.String() + "' failed: " + err.Error() + " (" + cmd.Stderr() + ")")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var cmd = executils.NewTimeoutCmd(10*time.Second, this.nftPath, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-secondly-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsSecondlyRate)+"/second burst "+types.String(newConnectionsSecondlyRate+3)+" packets }" /**"add", "@deny_set", "{"+protocol+" saddr}",**/, "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsSecondlyRate", "0"}))
|
var cmd = executils.NewTimeoutCmd(10*time.Second, nftExe, "add", "rule", protocol, filter.Name, nftablesChainName, "tcp", "dport", types.String(port), "ct", "state", "new", "meter", "meter-"+protocol+"-"+types.String(port)+"-new-connections-secondly-rate", "{ "+protocol+" saddr limit rate over "+types.String(newConnectionsSecondlyRate)+"/second burst "+types.String(newConnectionsSecondlyRate+3)+" packets }" /**"add", "@deny_set", "{"+protocol+" saddr}",**/, "counter", "drop", "comment", this.encodeUserData([]string{"tcp", types.String(port), "newConnectionsSecondlyRate", "0"}))
|
||||||
cmd.WithStderr()
|
cmd.WithStderr()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -551,3 +549,8 @@ func (this *DDoSProtectionManager) updateAllowIPList(allIPList []string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *DDoSProtectionManager) nftExe() string {
|
||||||
|
path, _ := exec.LookPath("nft")
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|||||||
108
internal/firewalls/nftables/installer.go
Normal file
108
internal/firewalls/nftables/installer.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/events"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
|
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
events.On(events.EventReload, func() {
|
||||||
|
// linux only
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig, err := nodeconfigs.SharedNodeConfig()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeConfig == nil || !nodeConfig.AutoInstallNftables {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getgid() == 0 { // root user only
|
||||||
|
_, err := exec.LookPath("nft")
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
goman.New(func() {
|
||||||
|
err := NewInstaller().Install()
|
||||||
|
if err != nil {
|
||||||
|
// 不需要传到API节点
|
||||||
|
logs.Println("[NFTABLES]install nftables failed: " + err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Installer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInstaller() *Installer {
|
||||||
|
return &Installer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Installer) Install() error {
|
||||||
|
// linux only
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已经存在
|
||||||
|
_, err := exec.LookPath("nft")
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd *executils.Cmd
|
||||||
|
|
||||||
|
// check dnf
|
||||||
|
dnfExe, err := exec.LookPath("dnf")
|
||||||
|
if err == nil {
|
||||||
|
cmd = executils.NewCmd(dnfExe, "-y", "install", "nftables")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check apt
|
||||||
|
if cmd == nil {
|
||||||
|
aptExe, err := exec.LookPath("apt")
|
||||||
|
if err == nil {
|
||||||
|
cmd = executils.NewCmd(aptExe, "install", "nftables")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check yum
|
||||||
|
if cmd == nil {
|
||||||
|
yumExe, err := exec.LookPath("yum")
|
||||||
|
if err == nil {
|
||||||
|
cmd = executils.NewCmd(yumExe, "-y", "install", "nftables")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.WithTimeout(10 * time.Minute)
|
||||||
|
cmd.WithStderr()
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err.Error() + ": " + cmd.Stderr())
|
||||||
|
}
|
||||||
|
|
||||||
|
remotelogs.Println("NFTABLES", "installed nftables with command '"+cmd.String()+"' successfully")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user