Files
EdgeNode/internal/waf/ip_table.go
刘祥超 04b9a65d4d 实现WAF
2020-10-08 15:06:42 +08:00

155 lines
3.1 KiB
Go

package waf
import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"
"regexp"
"strings"
"time"
)
type IPAction = string
var RegexpDigitNumber = regexp.MustCompile("^\\d+$")
const (
IPActionAccept IPAction = "accept"
IPActionReject IPAction = "reject"
)
// ip table
type IPTable struct {
Id string `yaml:"id" json:"id"`
On bool `yaml:"on" json:"on"`
IP string `yaml:"ip" json:"ip"` // single ip, cidr, ip range, TODO support *
Port string `yaml:"port" json:"port"` // single port, range, *
Action IPAction `yaml:"action" json:"action"` // accept, reject
TimeFrom int64 `yaml:"timeFrom" json:"timeFrom"` // from timestamp
TimeTo int64 `yaml:"timeTo" json:"timeTo"` // zero means forever
Remark string `yaml:"remark" json:"remark"`
// port
minPort int
maxPort int
minPortWildcard bool
maxPortWildcard bool
ports []int
// ip
ipRange *shared.IPRangeConfig
}
func NewIPTable() *IPTable {
return &IPTable{
On: true,
Id: stringutil.Rand(16),
}
}
func (this *IPTable) Init() error {
// parse port
if RegexpDigitNumber.MatchString(this.Port) {
this.minPort = types.Int(this.Port)
this.maxPort = types.Int(this.Port)
} else if regexp.MustCompile(`[:-]`).MatchString(this.Port) {
pieces := regexp.MustCompile(`[:-]`).Split(this.Port, 2)
if pieces[0] == "*" {
this.minPortWildcard = true
} else {
this.minPort = types.Int(pieces[0])
}
if pieces[1] == "*" {
this.maxPortWildcard = true
} else {
this.maxPort = types.Int(pieces[1])
}
} else if strings.Contains(this.Port, ",") {
pieces := strings.Split(this.Port, ",")
for _, piece := range pieces {
piece = strings.TrimSpace(piece)
if len(piece) > 0 {
this.ports = append(this.ports, types.Int(piece))
}
}
} else if this.Port == "*" {
this.minPortWildcard = true
this.maxPortWildcard = true
}
// parse ip
if len(this.IP) > 0 {
ipRange, err := shared.ParseIPRange(this.IP)
if err != nil {
return err
}
this.ipRange = ipRange
}
return nil
}
// check ip
func (this *IPTable) Match(ip string, port int) (isMatched bool) {
if !this.On {
return
}
now := time.Now().Unix()
if this.TimeFrom > 0 && now < this.TimeFrom {
return
}
if this.TimeTo > 0 && now > this.TimeTo {
return
}
if !this.matchPort(port) {
return
}
if !this.matchIP(ip) {
return
}
return true
}
func (this *IPTable) matchPort(port int) bool {
if port == 0 {
return false
}
if this.minPortWildcard {
if this.maxPortWildcard {
return true
}
if this.maxPort >= port {
return true
}
}
if this.maxPortWildcard {
if this.minPortWildcard {
return true
}
if this.minPort <= port {
return true
}
}
if (this.minPort > 0 || this.maxPort > 0) && this.minPort <= port && this.maxPort >= port {
return true
}
if len(this.ports) > 0 {
return lists.ContainsInt(this.ports, port)
}
return false
}
func (this *IPTable) matchIP(ip string) bool {
if this.ipRange == nil {
return false
}
return this.ipRange.Contains(ip)
}