mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-05 01:20:26 +08:00
IP范围支持多行
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/waf/checkpoints"
|
"github.com/TeaOSLab/EdgeNode/internal/waf/checkpoints"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
|
"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/waf/utils"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf/values"
|
||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
@@ -47,6 +48,10 @@ type Rule struct {
|
|||||||
isIP bool
|
isIP bool
|
||||||
ipValue net.IP
|
ipValue net.IP
|
||||||
|
|
||||||
|
ipRangeListValue *values.IPRangeList
|
||||||
|
numberListValue *values.NumberList
|
||||||
|
stringListValue *values.StringList
|
||||||
|
|
||||||
floatValue float64
|
floatValue float64
|
||||||
reg *re.Regexp
|
reg *re.Regexp
|
||||||
}
|
}
|
||||||
@@ -104,32 +109,7 @@ func (this *Rule) Init() error {
|
|||||||
return errors.New("value should be a valid ip")
|
return errors.New("value should be a valid ip")
|
||||||
}
|
}
|
||||||
case RuleOperatorIPRange, RuleOperatorNotIPRange:
|
case RuleOperatorIPRange, RuleOperatorNotIPRange:
|
||||||
if strings.Contains(this.Value, ",") {
|
this.ipRangeListValue = values.ParseIPRangeList(this.Value)
|
||||||
ipList := strings.SplitN(this.Value, ",", 2)
|
|
||||||
ipString1 := strings.TrimSpace(ipList[0])
|
|
||||||
ipString2 := strings.TrimSpace(ipList[1])
|
|
||||||
|
|
||||||
if len(ipString1) > 0 {
|
|
||||||
ip1 := net.ParseIP(ipString1)
|
|
||||||
if ip1 == nil {
|
|
||||||
return errors.New("start ip is invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ipString2) > 0 {
|
|
||||||
ip2 := net.ParseIP(ipString2)
|
|
||||||
if ip2 == nil {
|
|
||||||
return errors.New("end ip is invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if strings.Contains(this.Value, "/") {
|
|
||||||
_, _, err := net.ParseCIDR(this.Value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.New("invalid ip range")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if singleParamRegexp.MatchString(this.Param) {
|
if singleParamRegexp.MatchString(this.Param) {
|
||||||
@@ -643,50 +623,11 @@ func (this *Rule) unescape(v string) string {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Rule) containsIP(value interface{}) bool {
|
func (this *Rule) containsIP(value any) bool {
|
||||||
ip := net.ParseIP(types.String(value))
|
if this.ipRangeListValue == nil {
|
||||||
if ip == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查IP范围格式
|
|
||||||
if strings.Contains(this.Value, ",") {
|
|
||||||
ipList := strings.SplitN(this.Value, ",", 2)
|
|
||||||
ipString1 := strings.TrimSpace(ipList[0])
|
|
||||||
ipString2 := strings.TrimSpace(ipList[1])
|
|
||||||
|
|
||||||
if len(ipString1) > 0 {
|
|
||||||
ip1 := net.ParseIP(ipString1)
|
|
||||||
if ip1 == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Compare(ip, ip1) < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ipString2) > 0 {
|
|
||||||
ip2 := net.ParseIP(ipString2)
|
|
||||||
if ip2 == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Compare(ip, ip2) > 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else if strings.Contains(this.Value, "/") {
|
|
||||||
_, ipNet, err := net.ParseCIDR(this.Value)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ipNet.Contains(ip)
|
|
||||||
} else {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
return this.ipRangeListValue.Contains(types.String(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Rule) ipToInt64(ip net.IP) int64 {
|
func (this *Rule) ipToInt64(ip net.IP) int64 {
|
||||||
|
|||||||
7
internal/waf/values/ip_list.go
Normal file
7
internal/waf/values/ip_list.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values
|
||||||
|
|
||||||
|
func ParseIPList(v string) *StringList {
|
||||||
|
return ParseStringList(v)
|
||||||
|
}
|
||||||
26
internal/waf/values/ip_list_test.go
Normal file
26
internal/waf/values/ip_list_test.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf/values"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseIPList(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseIPList("")
|
||||||
|
a.IsFalse(list.Contains("192.168.1.100"))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseIPList(`
|
||||||
|
192.168.1.1
|
||||||
|
192.168.1.101`)
|
||||||
|
a.IsFalse(list.Contains("192.168.1.100"))
|
||||||
|
a.IsTrue(list.Contains("192.168.1.101"))
|
||||||
|
}
|
||||||
|
}
|
||||||
132
internal/waf/values/ip_range.go
Normal file
132
internal/waf/values/ip_range.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPRangeType = string
|
||||||
|
|
||||||
|
const (
|
||||||
|
IPRangeTypeCIDR IPRangeType = "cidr" // CIDR
|
||||||
|
IPRangeTypeSingeIP IPRangeType = "singleIP" // 单个IP
|
||||||
|
IPRangeTypeRange IPRangeType = "range" // IP范围,IP1-IP2
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPRange struct {
|
||||||
|
Type IPRangeType
|
||||||
|
CIDR *net.IPNet
|
||||||
|
IPFrom net.IP
|
||||||
|
IPTo net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IPRange) Contains(netIP net.IP) bool {
|
||||||
|
if netIP == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch this.Type {
|
||||||
|
case IPRangeTypeCIDR:
|
||||||
|
if this.CIDR != nil {
|
||||||
|
return this.CIDR.Contains(netIP)
|
||||||
|
}
|
||||||
|
case IPRangeTypeSingeIP:
|
||||||
|
if this.IPFrom != nil {
|
||||||
|
return bytes.Equal(this.IPFrom, netIP)
|
||||||
|
}
|
||||||
|
case IPRangeTypeRange:
|
||||||
|
return bytes.Compare(this.IPFrom, netIP) <= 0 && bytes.Compare(this.IPTo, netIP) >= 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPRangeList struct {
|
||||||
|
Ranges []*IPRange
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIPRangeList() *IPRangeList {
|
||||||
|
return &IPRangeList{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseIPRangeList(value string) *IPRangeList {
|
||||||
|
var list = NewIPRangeList()
|
||||||
|
|
||||||
|
if len(value) == 0 {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = strings.Split(value, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(line, ",") { // IPFrom,IPTo
|
||||||
|
var pieces = strings.SplitN(line, ",", 2)
|
||||||
|
if len(pieces) == 2 {
|
||||||
|
var ipFrom = net.ParseIP(strings.TrimSpace(pieces[0]))
|
||||||
|
var ipTo = net.ParseIP(strings.TrimSpace(pieces[1]))
|
||||||
|
if ipFrom != nil && ipTo != nil {
|
||||||
|
if bytes.Compare(ipFrom, ipTo) > 0 {
|
||||||
|
ipFrom, ipTo = ipTo, ipFrom
|
||||||
|
}
|
||||||
|
list.Ranges = append(list.Ranges, &IPRange{
|
||||||
|
Type: IPRangeTypeRange,
|
||||||
|
IPFrom: ipFrom,
|
||||||
|
IPTo: ipTo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if strings.Contains(line, "-") { // IPFrom-IPTo
|
||||||
|
var pieces = strings.SplitN(line, "-", 2)
|
||||||
|
if len(pieces) == 2 {
|
||||||
|
var ipFrom = net.ParseIP(strings.TrimSpace(pieces[0]))
|
||||||
|
var ipTo = net.ParseIP(strings.TrimSpace(pieces[1]))
|
||||||
|
if ipFrom != nil && ipTo != nil {
|
||||||
|
if bytes.Compare(ipFrom, ipTo) > 0 {
|
||||||
|
ipFrom, ipTo = ipTo, ipFrom
|
||||||
|
}
|
||||||
|
list.Ranges = append(list.Ranges, &IPRange{
|
||||||
|
Type: IPRangeTypeRange,
|
||||||
|
IPFrom: ipFrom,
|
||||||
|
IPTo: ipTo,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if strings.Contains(line, "/") { // CIDR
|
||||||
|
_, cidr, _ := net.ParseCIDR(line)
|
||||||
|
if cidr != nil {
|
||||||
|
list.Ranges = append(list.Ranges, &IPRange{
|
||||||
|
Type: IPRangeTypeCIDR,
|
||||||
|
CIDR: cidr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else { // single ip
|
||||||
|
var netIP = net.ParseIP(line)
|
||||||
|
if netIP != nil {
|
||||||
|
list.Ranges = append(list.Ranges, &IPRange{
|
||||||
|
Type: IPRangeTypeSingeIP,
|
||||||
|
IPFrom: netIP,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IPRangeList) Contains(ip string) bool {
|
||||||
|
var netIP = net.ParseIP(ip)
|
||||||
|
if netIP == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range this.Ranges {
|
||||||
|
if r.Contains(netIP) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
54
internal/waf/values/ip_range_test.go
Normal file
54
internal/waf/values/ip_range_test.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf/values"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIPRange_ParseIPRangeList(t *testing.T) {
|
||||||
|
{
|
||||||
|
var r = values.ParseIPRangeList("")
|
||||||
|
logs.PrintAsJSON(r, t)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var r = values.ParseIPRangeList("192.168.2.1")
|
||||||
|
logs.PrintAsJSON(r, t)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var r = values.ParseIPRangeList(`192.168.2.1
|
||||||
|
192.168.1.100/24
|
||||||
|
192.168.1.1-192.168.2.100
|
||||||
|
192.168.1.2,192.168.2.200
|
||||||
|
192.168.2.200 - 192.168.2.100
|
||||||
|
# 以下是错误的
|
||||||
|
192.168
|
||||||
|
192.168.100.1-1`)
|
||||||
|
logs.PrintAsJSON(r, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPRange_Contains(t *testing.T) {
|
||||||
|
{
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
var r = values.ParseIPRangeList(`192.168.2.1
|
||||||
|
192.168.1.100/24
|
||||||
|
192.168.1.1-192.168.2.100
|
||||||
|
192.168.2.2,192.168.2.200
|
||||||
|
192.168.3.200 - 192.168.3.100
|
||||||
|
192.168.4.100
|
||||||
|
192.168.5.1/26`)
|
||||||
|
a.IsTrue(r.Contains("192.168.1.102"))
|
||||||
|
a.IsTrue(r.Contains("192.168.2.101"))
|
||||||
|
a.IsTrue(r.Contains("192.168.1.1"))
|
||||||
|
a.IsTrue(r.Contains("192.168.2.100"))
|
||||||
|
a.IsFalse(r.Contains("192.168.2.201"))
|
||||||
|
a.IsTrue(r.Contains("192.168.3.101"))
|
||||||
|
a.IsTrue(r.Contains("192.168.4.100"))
|
||||||
|
a.IsTrue(r.Contains("192.168.5.63"))
|
||||||
|
a.IsFalse(r.Contains("192.168.5.128"))
|
||||||
|
}
|
||||||
|
}
|
||||||
48
internal/waf/values/number_list.go
Normal file
48
internal/waf/values/number_list.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NumberList struct {
|
||||||
|
ValueMap map[float64]zero.Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNumberList() *NumberList {
|
||||||
|
return &NumberList{
|
||||||
|
ValueMap: map[float64]zero.Zero{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseNumberList(v string) *NumberList {
|
||||||
|
var list = NewNumberList()
|
||||||
|
if len(v) == 0 {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = strings.Split(v, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = strings.Split(line, ",")
|
||||||
|
for _, value := range values {
|
||||||
|
value = strings.TrimSpace(value)
|
||||||
|
if len(value) > 0 {
|
||||||
|
list.ValueMap[types.Float64(value)] = zero.Zero{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *NumberList) Contains(f float64) bool {
|
||||||
|
_, ok := this.ValueMap[f]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
29
internal/waf/values/number_list_test.go
Normal file
29
internal/waf/values/number_list_test.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf/values"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseNumberList(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseNumberList("")
|
||||||
|
a.IsFalse(list.Contains(123))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseNumberList(`123
|
||||||
|
456
|
||||||
|
|
||||||
|
789.1234`)
|
||||||
|
a.IsTrue(list.Contains(123))
|
||||||
|
a.IsFalse(list.Contains(0))
|
||||||
|
a.IsFalse(list.Contains(789.123))
|
||||||
|
a.IsTrue(list.Contains(789.1234))
|
||||||
|
}
|
||||||
|
}
|
||||||
47
internal/waf/values/string_list.go
Normal file
47
internal/waf/values/string_list.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringList struct {
|
||||||
|
ValueMap map[string]zero.Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringList() *StringList {
|
||||||
|
return &StringList{
|
||||||
|
ValueMap: map[string]zero.Zero{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseStringList(v string) *StringList {
|
||||||
|
var list = NewStringList()
|
||||||
|
if len(v) == 0 {
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines = strings.Split(v, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = strings.Split(line, ",")
|
||||||
|
for _, value := range values {
|
||||||
|
value = strings.TrimSpace(value)
|
||||||
|
if len(value) > 0 {
|
||||||
|
list.ValueMap[value] = zero.Zero{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *StringList) Contains(f string) bool {
|
||||||
|
_, ok := this.ValueMap[f]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
30
internal/waf/values/string_list_test.go
Normal file
30
internal/waf/values/string_list_test.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package values_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf/values"
|
||||||
|
"github.com/iwind/TeaGo/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseStringList(t *testing.T) {
|
||||||
|
var a = assert.NewAssertion(t)
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseStringList("")
|
||||||
|
a.IsFalse(list.Contains("hello"))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = values.ParseStringList(`hello
|
||||||
|
|
||||||
|
world
|
||||||
|
hi
|
||||||
|
|
||||||
|
people`)
|
||||||
|
a.IsTrue(list.Contains("hello"))
|
||||||
|
a.IsFalse(list.Contains("hello1"))
|
||||||
|
a.IsTrue(list.Contains("hi"))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user