Files
EdgeNode/internal/waf/rule_test.go
2023-12-05 17:18:53 +08:00

771 lines
14 KiB
Go

package waf
import (
"github.com/TeaOSLab/EdgeNode/internal/waf/checkpoints"
"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
"github.com/iwind/TeaGo/assert"
"github.com/iwind/TeaGo/maps"
"net/http"
"net/url"
"testing"
)
func TestRule_Init_Single(t *testing.T) {
rule := NewRule()
rule.Param = "${arg.name}"
rule.Operator = RuleOperatorEqString
rule.Value = "lu"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
t.Log(rule.singleParam, rule.singleCheckpoint)
rawReq, err := http.NewRequest(http.MethodGet, "http://teaos.cn/hello?name=lu&age=20", nil)
if err != nil {
t.Fatal(err)
}
req := requests.NewTestRequest(rawReq)
t.Log(rule.MatchRequest(req))
}
func TestRule_Init_Composite(t *testing.T) {
rule := NewRule()
rule.Param = "${arg.name} ${arg.age}"
rule.Operator = RuleOperatorContains
rule.Value = "lu"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
t.Log(rule.singleParam, rule.singleCheckpoint)
rawReq, err := http.NewRequest(http.MethodGet, "http://teaos.cn/hello?name=lu&age=20", nil)
if err != nil {
t.Fatal(err)
}
req := requests.NewTestRequest(rawReq)
t.Log(rule.MatchRequest(req))
}
func TestRule_Test(t *testing.T) {
a := assert.NewAssertion(t)
{
rule := NewRule()
rule.Operator = RuleOperatorGt
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("124"))
a.IsFalse(rule.Test("123"))
a.IsFalse(rule.Test("122"))
a.IsFalse(rule.Test("abcdef"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorGte
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("124"))
a.IsTrue(rule.Test("123"))
a.IsFalse(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorLt
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("124"))
a.IsFalse(rule.Test("123"))
a.IsTrue(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorLte
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("124"))
a.IsTrue(rule.Test("123"))
a.IsTrue(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorEq
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("124"))
a.IsTrue(rule.Test("123"))
a.IsFalse(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNeq
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("124"))
a.IsFalse(rule.Test("123"))
a.IsTrue(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorEqString
rule.Value = "123"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("124"))
a.IsTrue(rule.Test("123"))
a.IsFalse(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorEqString
rule.Value = "abc"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("ABC"))
a.IsTrue(rule.Test("abc"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorEqString
rule.IsCaseInsensitive = true
rule.Value = "abc"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("ABC"))
a.IsTrue(rule.Test("abc"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNeqString
rule.Value = "abc"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("124"))
a.IsFalse(rule.Test("abc"))
a.IsTrue(rule.Test("122"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNeqString
rule.IsCaseInsensitive = true
rule.Value = "abc"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("ABC"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("123"))
a.IsFalse(rule.Test("abc123"))
}
{
var rule = NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test([]byte("123")))
a.IsFalse(rule.Test([]byte("abc123")))
}
{
var rule = NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test([][]byte{[]byte("123"), []byte("456")}))
a.IsFalse(rule.Test([][]byte{[]byte("abc123")}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "abc"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("ABC"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test([]string{"123", "456", "abc"}))
a.IsFalse(rule.Test([]string{"abc123"}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNotMatch
rule.Value = "\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("123"))
a.IsTrue(rule.Test("abc"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNotMatch
rule.Value = "abc"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("ABC"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNotMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test([]string{"123", "456", "abc"}))
a.IsTrue(rule.Test([]string{"abc123"}))
}
{
var rule = NewRule()
rule.Operator = RuleOperatorNotMatch
rule.Value = "^\\d+"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test([][]byte{[]byte("123"), []byte("456")}))
a.IsFalse(rule.Test([][]byte{[]byte("123"), []byte("abc")}))
a.IsTrue(rule.Test([][]byte{[]byte("abc123")}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = "^(?i)[a-z]+$"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("ABC"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorContains
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("Hello, World"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorContains
rule.Value = "hello"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("Hello, World"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorContains
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test([]string{"Hello", "World"}))
a.IsTrue(rule.Test(maps.Map{
"a": "World", "b": "Hello",
}))
a.IsFalse(rule.Test(maps.Map{
"a": "World", "b": "Hello2",
}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNotContains
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test("World"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorNotContains
rule.Value = "hello"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test("World"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorPrefix
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("Hello, World"))
a.IsFalse(rule.Test("World, Hello"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorPrefix
rule.Value = "hello"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsTrue(rule.Test("Hello, World"))
a.IsFalse(rule.Test("World, Hello"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorSuffix
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test("World, Hello"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorSuffix
rule.Value = "hello"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test("World, Hello"))
}
{
rule := NewRule()
rule.Operator = RuleOperatorHasKey
rule.Value = "Hello"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test(maps.Map{
"Hello": "World",
}))
a.IsFalse(rule.Test(maps.Map{
"Hello1": "World",
}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorHasKey
rule.Value = "hello"
rule.IsCaseInsensitive = true
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsTrue(rule.Test(maps.Map{
"Hello": "World",
}))
a.IsFalse(rule.Test(maps.Map{
"Hello1": "World",
}))
}
{
rule := NewRule()
rule.Operator = RuleOperatorHasKey
rule.Value = "3"
err := rule.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(rule.Test("Hello, World"))
a.IsFalse(rule.Test(maps.Map{
"Hello": "World",
}))
a.IsTrue(rule.Test([]int{1, 2, 3, 4}))
}
}
func TestRule_MatchStar(t *testing.T) {
{
rule := NewRule()
rule.Operator = RuleOperatorMatch
rule.Value = `/\*(!|\x00)`
err := rule.Init()
if err != nil {
t.Fatal(err)
}
t.Log(rule.Test("/*!"))
t.Log(rule.Test(url.QueryEscape("/*!")))
t.Log(url.QueryEscape("/*!"))
}
}
func TestRule_SetCheckpointFinder(t *testing.T) {
{
rule := NewRule()
rule.Param = "${arg.abc}"
rule.Operator = RuleOperatorMatch
err := rule.Init()
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", rule.singleCheckpoint)
}
{
rule := NewRule()
rule.Param = "${arg.abc}"
rule.Operator = RuleOperatorMatch
rule.checkpointFinder = func(prefix string) checkpoints.CheckpointInterface {
return new(checkpoints.SampleRequestCheckpoint)
}
err := rule.Init()
if err != nil {
t.Fatal(err)
}
t.Logf("%#v", rule.singleCheckpoint)
}
}
func TestRule_Version(t *testing.T) {
a := assert.NewAssertion(t)
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `1.0,1.1`,
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("1.0"))
}
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `1.0,`,
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("1.0"))
}
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `,1.1`,
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("1.0"))
}
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `1.0,1.1`,
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("0.9"))
}
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `1.0`,
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("0.9"))
}
{
rule := Rule{
Operator: RuleOperatorVersionRange,
Value: `1.0`,
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("1.1"))
}
}
func TestRule_IP(t *testing.T) {
a := assert.NewAssertion(t)
{
rule := Rule{
Operator: RuleOperatorEqIP,
Value: "hello",
}
a.IsNotNil(rule.Init())
a.IsFalse(rule.Test("hello"))
}
{
rule := Rule{
Operator: RuleOperatorEqIP,
Value: "hello",
}
a.IsNotNil(rule.Init())
a.IsFalse(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorEqIP,
Value: "192.168.1.100",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorGtIP,
Value: "192.168.1.90",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorGteIP,
Value: "192.168.1.90",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorLtIP,
Value: "192.168.1.90",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.80"))
}
{
rule := Rule{
Operator: RuleOperatorLteIP,
Value: "192.168.1.90",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.0.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "192.168.0.90,",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.0.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "192.168.0.90,192.168.1.100",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.0.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: ",192.168.1.100",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.0.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "192.168.0.90,192.168.1.99",
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "192.168.0.90/24",
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "192.168.0.90/18",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPRange,
Value: "a/18",
}
a.IsNotNil(rule.Init())
a.IsFalse(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPMod10,
Value: "6",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPMod100,
Value: "76",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorIPMod,
Value: "10,6",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.1.100"))
}
{
rule := Rule{
Operator: RuleOperatorNotIPRange,
Value: "192.168.0.90,192.168.1.100",
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("192.168.0.100"))
}
{
rule := Rule{
Operator: RuleOperatorNotIPRange,
Value: "192.168.0.90,192.168.1.100",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.168.2.100"))
}
{
rule := Rule{
Operator: RuleOperatorNotIPRange,
Value: "192.168.0.90/8",
}
a.IsNil(rule.Init())
a.IsFalse(rule.Test("192.168.2.100"))
}
{
rule := Rule{
Operator: RuleOperatorNotIPRange,
Value: "192.168.0.90/16",
}
a.IsNil(rule.Init())
a.IsTrue(rule.Test("192.169.2.100"))
}
}