Files
EdgeNode/internal/waf/ip_list.go

220 lines
5.0 KiB
Go
Raw Normal View History

2021-07-18 15:51:49 +08:00
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package waf
import (
2021-10-18 20:08:43 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeNode/internal/conns"
"github.com/TeaOSLab/EdgeNode/internal/firewalls"
2021-07-18 15:51:49 +08:00
"github.com/TeaOSLab/EdgeNode/internal/utils/expires"
2021-10-18 20:08:43 +08:00
"github.com/iwind/TeaGo/types"
2021-07-18 15:51:49 +08:00
"sync"
"sync/atomic"
"time"
2021-07-18 15:51:49 +08:00
)
var SharedIPWhiteList = NewIPList(IPListTypeAllow)
var SharedIPBlackList = NewIPList(IPListTypeDeny)
type IPListType = string
const (
IPListTypeAllow IPListType = "allow"
IPListTypeDeny IPListType = "deny"
)
2021-07-18 15:51:49 +08:00
const IPTypeAll = "*"
// IPList IP列表管理
type IPList struct {
expireList *expires.List
2022-04-09 18:28:22 +08:00
ipMap map[string]uint64 // ip => id
idMap map[uint64]string // id => ip
listType IPListType
2021-07-18 15:51:49 +08:00
2022-04-09 18:28:22 +08:00
id uint64
2021-07-18 15:51:49 +08:00
locker sync.RWMutex
}
// NewIPList 获取新对象
func NewIPList(listType IPListType) *IPList {
2021-07-18 15:51:49 +08:00
var list = &IPList{
2022-04-09 18:28:22 +08:00
ipMap: map[string]uint64{},
idMap: map[uint64]string{},
listType: listType,
2021-07-18 15:51:49 +08:00
}
e := expires.NewList()
list.expireList = e
2022-04-09 18:28:22 +08:00
e.OnGC(func(itemId uint64) {
list.remove(itemId) // TODO 使用异步防止阻塞GC
})
2021-07-18 15:51:49 +08:00
return list
}
// Add 添加IP
2021-10-18 20:08:43 +08:00
func (this *IPList) Add(ipType string, scope firewallconfigs.FirewallScope, serverId int64, ip string, expiresAt int64) {
switch scope {
case firewallconfigs.FirewallScopeGlobal:
ip = "*@" + ip + "@" + ipType
case firewallconfigs.FirewallScopeService:
ip = types.String(serverId) + "@" + ip + "@" + ipType
default:
2021-10-21 09:31:31 +08:00
ip = "*@" + ip + "@" + ipType
2021-10-18 20:08:43 +08:00
}
2021-07-18 15:51:49 +08:00
var id = this.nextId()
this.expireList.Add(id, expiresAt)
this.locker.Lock()
2022-09-03 09:54:25 +08:00
// 删除以前
oldId, ok := this.ipMap[ip]
if ok {
delete(this.idMap, oldId)
this.expireList.Remove(oldId)
}
2021-07-18 15:51:49 +08:00
this.ipMap[ip] = id
this.idMap[id] = ip
this.locker.Unlock()
}
// RecordIP 记录IP
func (this *IPList) RecordIP(ipType string,
scope firewallconfigs.FirewallScope,
serverId int64,
ip string,
expiresAt int64,
policyId int64,
useLocalFirewall bool,
groupId int64,
2022-01-10 19:54:10 +08:00
setId int64,
reason string) {
this.Add(ipType, scope, serverId, ip, expiresAt)
if this.listType == IPListTypeDeny {
// 加入队列等待上传
select {
case recordIPTaskChan <- &recordIPTask{
ip: ip,
listId: firewallconfigs.GlobalListId,
expiresAt: expiresAt,
level: firewallconfigs.DefaultEventLevel,
serverId: serverId,
sourceServerId: serverId,
sourceHTTPFirewallPolicyId: policyId,
sourceHTTPFirewallRuleGroupId: groupId,
sourceHTTPFirewallRuleSetId: setId,
2022-01-10 19:54:10 +08:00
reason: reason,
}:
default:
}
// 使用本地防火墙
if useLocalFirewall {
var seconds = expiresAt - time.Now().Unix()
if seconds > 0 {
// 最大3600防止误封时间过长
if seconds > 3600 {
seconds = 3600
}
2022-08-04 11:01:16 +08:00
_ = firewalls.Firewall().DropSourceIP(ip, int(seconds), true)
}
}
2022-09-03 09:54:25 +08:00
// 关闭此IP相关连接
conns.SharedMap.CloseIPConns(ip)
}
}
2021-07-18 15:51:49 +08:00
// Contains 判断是否有某个IP
2021-10-18 20:08:43 +08:00
func (this *IPList) Contains(ipType string, scope firewallconfigs.FirewallScope, serverId int64, ip string) bool {
switch scope {
case firewallconfigs.FirewallScopeGlobal:
ip = "*@" + ip + "@" + ipType
case firewallconfigs.FirewallScopeService:
ip = types.String(serverId) + "@" + ip + "@" + ipType
default:
2021-10-21 09:31:31 +08:00
ip = "*@" + ip + "@" + ipType
2021-10-18 20:08:43 +08:00
}
2021-07-18 15:51:49 +08:00
this.locker.RLock()
_, ok := this.ipMap[ip]
this.locker.RUnlock()
2021-07-18 15:51:49 +08:00
return ok
}
2022-09-03 09:54:25 +08:00
// ContainsExpires 判断是否有某个IP并返回过期时间
func (this *IPList) ContainsExpires(ipType string, scope firewallconfigs.FirewallScope, serverId int64, ip string) (expiresAt int64, ok bool) {
switch scope {
case firewallconfigs.FirewallScopeGlobal:
ip = "*@" + ip + "@" + ipType
case firewallconfigs.FirewallScopeService:
ip = types.String(serverId) + "@" + ip + "@" + ipType
default:
ip = "*@" + ip + "@" + ipType
}
this.locker.RLock()
id, ok := this.ipMap[ip]
if ok {
expiresAt = this.expireList.ExpiresAt(id)
}
this.locker.RUnlock()
return expiresAt, ok
}
// RemoveIP 删除IP
func (this *IPList) RemoveIP(ip string, serverId int64, shouldExecute bool) {
this.locker.Lock()
2022-09-03 09:54:25 +08:00
{
var key = "*@" + ip + "@" + IPTypeAll
id, ok := this.ipMap[key]
if ok {
delete(this.ipMap, key)
delete(this.idMap, id)
this.expireList.Remove(id)
}
}
if serverId > 0 {
2022-09-03 09:54:25 +08:00
var key = types.String(serverId) + "@" + ip + "@" + IPTypeAll
id, ok := this.ipMap[key]
if ok {
delete(this.ipMap, key)
delete(this.idMap, id)
this.expireList.Remove(id)
}
}
2022-09-03 09:54:25 +08:00
this.locker.Unlock()
// 从本地防火墙中删除
if shouldExecute {
_ = firewalls.Firewall().RemoveSourceIP(ip)
}
}
2022-04-09 18:28:22 +08:00
func (this *IPList) remove(id uint64) {
2021-07-18 15:51:49 +08:00
this.locker.Lock()
ip, ok := this.idMap[id]
if ok {
ipId, ok := this.ipMap[ip]
if ok && ipId == id {
delete(this.ipMap, ip)
}
delete(this.idMap, id)
}
this.locker.Unlock()
}
2022-04-09 18:28:22 +08:00
func (this *IPList) nextId() uint64 {
return atomic.AddUint64(&this.id, 1)
2021-07-18 15:51:49 +08:00
}