nftables封禁IP使用异步操作

This commit is contained in:
GoEdgeLab
2022-08-04 11:01:16 +08:00
parent 2014cd2fdf
commit 9c00b07d9e
9 changed files with 68 additions and 14 deletions

View File

@@ -161,7 +161,7 @@ func main() {
app.On("ip.drop", func() { app.On("ip.drop", func() {
var args = os.Args[2:] var args = os.Args[2:]
if len(args) == 0 { if len(args) == 0 {
fmt.Println("Usage: edge-node ip.drop IP [--timeout=SECONDS]") fmt.Println("Usage: edge-node ip.drop IP [--timeout=SECONDS] [--async]")
return return
} }
var ip = args[0] var ip = args[0]
@@ -175,6 +175,11 @@ func main() {
if ok { if ok {
timeoutSeconds = types.Int(timeout[0]) timeoutSeconds = types.Int(timeout[0])
} }
var async = false
_, ok = options["async"]
if ok {
async = true
}
fmt.Println("drop ip '" + ip + "' for '" + types.String(timeoutSeconds) + "' seconds") fmt.Println("drop ip '" + ip + "' for '" + types.String(timeoutSeconds) + "' seconds")
var sock = gosock.NewTmpSock(teaconst.ProcessName) var sock = gosock.NewTmpSock(teaconst.ProcessName)
@@ -183,6 +188,7 @@ func main() {
Params: map[string]interface{}{ Params: map[string]interface{}{
"ip": ip, "ip": ip,
"timeoutSeconds": timeoutSeconds, "timeoutSeconds": timeoutSeconds,
"async": async,
}, },
}) })
if err != nil { if err != nil {

View File

@@ -3,6 +3,7 @@
package firewalls package firewalls
import ( import (
"errors"
"github.com/TeaOSLab/EdgeNode/internal/goman" "github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs" "github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
@@ -143,7 +144,7 @@ func (this *Firewalld) RejectSourceIP(ip string, timeoutSeconds int) error {
return nil return nil
} }
func (this *Firewalld) DropSourceIP(ip string, timeoutSeconds int) error { func (this *Firewalld) DropSourceIP(ip string, timeoutSeconds int, async bool) error {
if !this.isReady { if !this.isReady {
return nil return nil
} }
@@ -156,8 +157,16 @@ func (this *Firewalld) DropSourceIP(ip string, timeoutSeconds int) error {
args = append(args, "--timeout="+types.String(timeoutSeconds)+"s") args = append(args, "--timeout="+types.String(timeoutSeconds)+"s")
} }
var cmd = exec.Command(this.exe, args...) var cmd = exec.Command(this.exe, args...)
if async {
this.pushCmd(cmd) this.pushCmd(cmd)
return nil return nil
}
err := cmd.Run()
if err != nil {
return errors.New("run command failed '" + cmd.String() + "': " + err.Error())
}
return nil
} }
func (this *Firewalld) RemoveSourceIP(ip string) error { func (this *Firewalld) RemoveSourceIP(ip string) error {

View File

@@ -23,7 +23,10 @@ type FirewallInterface interface {
RejectSourceIP(ip string, timeoutSeconds int) error RejectSourceIP(ip string, timeoutSeconds int) error
// DropSourceIP 丢弃某个源IP数据 // DropSourceIP 丢弃某个源IP数据
DropSourceIP(ip string, timeoutSeconds int) error // ip 要封禁的IP
// timeoutSeconds 过期时间
// async 是否异步
DropSourceIP(ip string, timeoutSeconds int, async bool) error
// RemoveSourceIP 删除某个源IP // RemoveSourceIP 删除某个源IP
RemoveSourceIP(ip string) error RemoveSourceIP(ip string) error

View File

@@ -47,7 +47,7 @@ func (this *MockFirewall) RejectSourceIP(ip string, timeoutSeconds int) error {
} }
// DropSourceIP 丢弃某个源IP数据 // DropSourceIP 丢弃某个源IP数据
func (this *MockFirewall) DropSourceIP(ip string, timeoutSeconds int) error { func (this *MockFirewall) DropSourceIP(ip string, timeoutSeconds int, async bool) error {
_ = ip _ = ip
_ = timeoutSeconds _ = timeoutSeconds
return nil return nil

View File

@@ -10,6 +10,7 @@ import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const" teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/events" "github.com/TeaOSLab/EdgeNode/internal/events"
"github.com/TeaOSLab/EdgeNode/internal/firewalls/nftables" "github.com/TeaOSLab/EdgeNode/internal/firewalls/nftables"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs" "github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"net" "net"
@@ -28,7 +29,7 @@ func init() {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
var ticker = time.NewTicker(3 * time.Minute) var ticker = time.NewTicker(3 * time.Minute)
go func() { goman.New(func() {
for range ticker.C { for range ticker.C {
// if already ready, we break // if already ready, we break
if nftablesIsReady { if nftablesIsReady {
@@ -53,7 +54,7 @@ func init() {
break break
} }
} }
}() })
} }
} }
@@ -79,9 +80,16 @@ func (this *nftablesTableDefinition) protocol() string {
return "ip" return "ip"
} }
type blockIPItem struct {
action string
ip string
timeoutSeconds int
}
func NewNFTablesFirewall() (*NFTablesFirewall, error) { func NewNFTablesFirewall() (*NFTablesFirewall, error) {
var firewall = &NFTablesFirewall{ var firewall = &NFTablesFirewall{
conn: nftables.NewConn(), conn: nftables.NewConn(),
dropIPQueue: make(chan *blockIPItem, 4096),
} }
err := firewall.init() err := firewall.init()
if err != nil { if err != nil {
@@ -103,6 +111,8 @@ type NFTablesFirewall struct {
denyIPv6Set *nftables.Set denyIPv6Set *nftables.Set
firewalld *Firewalld firewalld *Firewalld
dropIPQueue chan *blockIPItem
} }
func (this *NFTablesFirewall) init() error { func (this *NFTablesFirewall) init() error {
@@ -248,6 +258,18 @@ func (this *NFTablesFirewall) init() error {
nftablesIsReady = true nftablesIsReady = true
nftablesInstance = this nftablesInstance = this
goman.New(func() {
for ipItem := range this.dropIPQueue {
switch ipItem.action {
case "drop":
err = this.DropSourceIP(ipItem.ip, ipItem.timeoutSeconds, false)
if err != nil {
remotelogs.Warn("NFTABLES", "drop ip '"+ipItem.ip+"' failed: "+err.Error())
}
}
}
})
// load firewalld // load firewalld
var firewalld = NewFirewalld() var firewalld = NewFirewalld()
if firewalld.IsReady() { if firewalld.IsReady() {
@@ -312,16 +334,29 @@ func (this *NFTablesFirewall) AllowSourceIP(ip string) error {
// RejectSourceIP 拒绝某个源IP连接 // RejectSourceIP 拒绝某个源IP连接
// we did not create set for drop ip, so we reuse DropSourceIP() method here // we did not create set for drop ip, so we reuse DropSourceIP() method here
func (this *NFTablesFirewall) RejectSourceIP(ip string, timeoutSeconds int) error { func (this *NFTablesFirewall) RejectSourceIP(ip string, timeoutSeconds int) error {
return this.DropSourceIP(ip, timeoutSeconds) return this.DropSourceIP(ip, timeoutSeconds, true)
} }
// DropSourceIP 丢弃某个源IP数据 // DropSourceIP 丢弃某个源IP数据
func (this *NFTablesFirewall) DropSourceIP(ip string, timeoutSeconds int) error { func (this *NFTablesFirewall) DropSourceIP(ip string, timeoutSeconds int, async bool) error {
var data = net.ParseIP(ip) var data = net.ParseIP(ip)
if data == nil { if data == nil {
return errors.New("invalid ip '" + ip + "'") return errors.New("invalid ip '" + ip + "'")
} }
if async {
select {
case this.dropIPQueue <- &blockIPItem{
action: "drop",
ip: ip,
timeoutSeconds: timeoutSeconds,
}:
default:
return errors.New("drop ip queue is full")
}
return nil
}
if strings.Contains(ip, ":") { // ipv6 if strings.Contains(ip, ":") { // ipv6
if this.denyIPv6Set == nil { if this.denyIPv6Set == nil {
return errors.New("ipv6 ip set is nil") return errors.New("ipv6 ip set is nil")

View File

@@ -51,7 +51,7 @@ func (this *NFTablesFirewall) RejectSourceIP(ip string, timeoutSeconds int) erro
} }
// DropSourceIP 丢弃某个源IP数据 // DropSourceIP 丢弃某个源IP数据
func (this *NFTablesFirewall) DropSourceIP(ip string, timeoutSeconds int) error { func (this *NFTablesFirewall) DropSourceIP(ip string, timeoutSeconds int, async bool) error {
return nil return nil
} }

View File

@@ -57,7 +57,7 @@ func (this *ClientListener) Accept() (net.Conn, error) {
if beingDenied { if beingDenied {
var fw = firewalls.Firewall() var fw = firewalls.Firewall()
if fw != nil && !fw.IsMock() { if fw != nil && !fw.IsMock() {
_ = fw.DropSourceIP(ip, 60) _ = fw.DropSourceIP(ip, 120, true)
} }
} }

View File

@@ -784,7 +784,8 @@ func (this *Node) listenSock() error {
var m = maps.NewMap(cmd.Params) var m = maps.NewMap(cmd.Params)
var ip = m.GetString("ip") var ip = m.GetString("ip")
var timeSeconds = m.GetInt("timeoutSeconds") var timeSeconds = m.GetInt("timeoutSeconds")
err := firewalls.Firewall().DropSourceIP(ip, timeSeconds) var async = m.GetBool("async")
err := firewalls.Firewall().DropSourceIP(ip, timeSeconds, async)
if err != nil { if err != nil {
_ = cmd.Reply(&gosock.Command{ _ = cmd.Reply(&gosock.Command{
Params: map[string]interface{}{ Params: map[string]interface{}{

View File

@@ -112,7 +112,7 @@ func (this *IPList) RecordIP(ipType string,
if seconds > 3600 { if seconds > 3600 {
seconds = 3600 seconds = 3600
} }
_ = firewalls.Firewall().DropSourceIP(ip, int(seconds)) _ = firewalls.Firewall().DropSourceIP(ip, int(seconds), true)
} }
} }
} }