From 3128df9abde9072f731e1b04bf5459937ce8d6ac Mon Sep 17 00:00:00 2001 From: renz7 Date: Tue, 12 Mar 2024 16:25:44 +0800 Subject: [PATCH] feat: add ip-restriction wasm-go plugin (#759) --- .../extensions/ip-restriction/README.md | 31 +++ .../wasm-go/extensions/ip-restriction/VERSION | 1 + .../wasm-go/extensions/ip-restriction/go.mod | 22 ++ .../wasm-go/extensions/ip-restriction/go.sum | 24 ++ .../wasm-go/extensions/ip-restriction/main.go | 157 +++++++++++++ .../extensions/ip-restriction/utils.go | 37 +++ .../extensions/ip-restriction/utils_test.go | 106 +++++++++ .../tests/go-wasm-ip-restriction-allow.yaml | 46 ++++ .../tests/go-wasm-ip-restriction-deny.yaml | 46 ++++ .../tests/go-wasm-ip-restriction.go | 219 ++++++++++++++++++ 10 files changed, 689 insertions(+) create mode 100644 plugins/wasm-go/extensions/ip-restriction/README.md create mode 100644 plugins/wasm-go/extensions/ip-restriction/VERSION create mode 100644 plugins/wasm-go/extensions/ip-restriction/go.mod create mode 100644 plugins/wasm-go/extensions/ip-restriction/go.sum create mode 100644 plugins/wasm-go/extensions/ip-restriction/main.go create mode 100644 plugins/wasm-go/extensions/ip-restriction/utils.go create mode 100644 plugins/wasm-go/extensions/ip-restriction/utils_test.go create mode 100644 test/e2e/conformance/tests/go-wasm-ip-restriction-allow.yaml create mode 100644 test/e2e/conformance/tests/go-wasm-ip-restriction-deny.yaml create mode 100644 test/e2e/conformance/tests/go-wasm-ip-restriction.go diff --git a/plugins/wasm-go/extensions/ip-restriction/README.md b/plugins/wasm-go/extensions/ip-restriction/README.md new file mode 100644 index 000000000..9f6bab8a8 --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/README.md @@ -0,0 +1,31 @@ +# 功能说明 + +`ip-restriction `插件可以通过将 IP 地址列入白名单或黑名单来限制对服务或路由的访问.支持对单个 IP 地址、多个 IP 地址和类似 +10.10.10.0/24 的 CIDR范围的限制. + +# 配置说明 + +| 配置项 | 类型 | 必填 | 默认值 | 说明 | +|----------------|--------|----|-----------------------------|------------------------------------------| +| ip_source_type | string | 否 | origin-source | 可选值:1. 对端socket ip:`origin-source`; 2. 通过header获取:`header` | +| ip_header_name | string | 否 | x-forwarded-for | 当`ip_source_type`为`header`时,指定自定义IP来源头 | +| allow | array | 否 | [] | 白名单列表 | +| deny | array | 否 | [] | 黑名单列表 | +| status | int | 否 | 403 | 拒绝访问时的 HTTP 状态码 | +| message | string | 否 | Your IP address is blocked. | 拒绝访问时的返回信息 | + + +```yaml +ip_source_type: origin-source +allow: + - 10.0.0.1 + - 192.168.0.0/16 +``` + +```yaml +ip_source_type: header +ip_header_name: x-real-iP +deny: + - 10.0.0.1 + - 192.169.0.0/16 +``` diff --git a/plugins/wasm-go/extensions/ip-restriction/VERSION b/plugins/wasm-go/extensions/ip-restriction/VERSION new file mode 100644 index 000000000..afaf360d3 --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/VERSION @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/plugins/wasm-go/extensions/ip-restriction/go.mod b/plugins/wasm-go/extensions/ip-restriction/go.mod new file mode 100644 index 000000000..d2287c759 --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/go.mod @@ -0,0 +1,22 @@ +module github.com/alibaba/higress/plugins/wasm-go/extensions/ip-restriction + +go 1.19 + +replace github.com/alibaba/higress/plugins/wasm-go => ../.. + +require ( + github.com/alibaba/higress/plugins/wasm-go v0.0.0 + github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a + github.com/tidwall/gjson v1.14.3 + github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837 +) + +require ( + github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect + github.com/magefile/mage v1.14.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/resp v0.1.1 // indirect +) diff --git a/plugins/wasm-go/extensions/ip-restriction/go.sum b/plugins/wasm-go/extensions/ip-restriction/go.sum new file mode 100644 index 000000000..192a97c4b --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/go.sum @@ -0,0 +1,24 @@ +github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56 h1:Wi5Tgn8K+jDcBYL+dIMS1+qXYH2r7tpRAyBgqrWfQtw= +github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56/go.mod h1:8BhOLuqtSuT5NZtZMwfvEibi09RO3u79uqfHZzfDTR4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA= +github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew= +github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a h1:luYRvxLTE1xYxrXYj7nmjd1U0HHh8pUPiKfdZ0MhCGE= +github.com/higress-group/proxy-wasm-go-sdk v0.0.0-20240226064518-b3dc4646a35a/go.mod h1:hNFjhrLUIq+kJ9bOcs8QtiplSQ61GZXtd2xHKx4BYRo= +github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= +github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE= +github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0= +github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837 h1:DjHnADS2r2zynZ3WkCFAQ+PNYngMSNceRROi0pO6c3M= +github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837/go.mod h1:9vp0bxqozzQwcjBwenEXfKVq8+mYbwHkQ1NF9Ap0DMw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/plugins/wasm-go/extensions/ip-restriction/main.go b/plugins/wasm-go/extensions/ip-restriction/main.go new file mode 100644 index 000000000..364668b29 --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/main.go @@ -0,0 +1,157 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" + "github.com/higress-group/proxy-wasm-go-sdk/proxywasm" + "github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types" + "github.com/tidwall/gjson" + "github.com/zmap/go-iptree/iptree" + "net" + "strings" +) + +const ( + DefaultRealIpHeader string = "X-Forwarded-For" + DefaultDenyStatus uint32 = 403 + DefaultDenyMessage string = "Your IP address is blocked." +) +const ( + OriginSourceType = "origin-source" + HeaderSourceType = "header" +) + +type RestrictionConfig struct { + IPSourceType string `json:"ip_source_type"` //IP来源类型 + IPHeaderName string `json:"ip_header_name"` //真实IP头 + Allow *iptree.IPTree `json:"allow"` //允许的IP + Deny *iptree.IPTree `json:"deny"` //拒绝的IP + Status uint32 `json:"status"` //被拒绝时返回的状态码 + Message string `json:"message"` //被拒绝时返回的消息 +} + +func main() { + wrapper.SetCtx( + "ip-restriction", + wrapper.ParseConfigBy(parseConfig), + wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders)) +} + +func parseConfig(json gjson.Result, config *RestrictionConfig, log wrapper.Log) error { + sourceType := json.Get("ip_source_type") + if sourceType.Exists() && sourceType.String() != "" { + switch sourceType.String() { + case HeaderSourceType: + config.IPSourceType = HeaderSourceType + case OriginSourceType: + default: + config.IPSourceType = OriginSourceType + } + } else { + config.IPSourceType = OriginSourceType + } + + header := json.Get("ip_header_name") + if header.Exists() && header.String() != "" { + config.IPHeaderName = header.String() + } else { + config.IPHeaderName = DefaultRealIpHeader + } + status := json.Get("status") + if status.Exists() && status.Uint() > 1 { + config.Status = uint32(header.Uint()) + } else { + config.Status = DefaultDenyStatus + } + message := json.Get("message") + if message.Exists() && message.String() != "" { + config.Message = message.String() + } else { + config.Message = DefaultDenyMessage + } + allowNets, err := parseIPNets(json.Get("allow").Array()) + if err != nil { + log.Error(err.Error()) + return err + } + denyNets, err := parseIPNets(json.Get("deny").Array()) + if err != nil { + log.Error(err.Error()) + return err + } + if allowNets != nil && denyNets != nil { + log.Warn("allow and deny cannot be set at the same time") + return fmt.Errorf("allow and deny cannot be set at the same time") + } + if allowNets == nil && denyNets == nil { + log.Warn("allow and deny cannot be empty at the same time") + return fmt.Errorf("allow and deny cannot be empty at the same time") + } + config.Allow = allowNets + config.Deny = denyNets + return nil +} + +func getDownStreamIp(config RestrictionConfig) (net.IP, error) { + var ( + s string + err error + ) + + if config.IPSourceType == HeaderSourceType { + s, err = proxywasm.GetHttpRequestHeader(config.IPHeaderName) + if err == nil { + s = strings.Split(strings.Trim(s, " "), ",")[0] + } + } else { + var bs []byte + bs, err = proxywasm.GetProperty([]string{"source", "address"}) + s = string(bs) + } + if err != nil { + return nil, err + } + ip := parseIP(s) + realIP := net.ParseIP(ip) + if realIP == nil { + return nil, fmt.Errorf("invalid ip[%s]", ip) + } + return realIP, nil +} + +func onHttpRequestHeaders(context wrapper.HttpContext, config RestrictionConfig, log wrapper.Log) types.Action { + realIp, err := getDownStreamIp(config) + if err != nil { + return deniedUnauthorized(config) + } + allow := config.Allow + deny := config.Deny + if allow != nil { + if realIp == nil { + log.Error("realIp is nil, blocked") + return deniedUnauthorized(config) + } + if _, found, _ := allow.Get(realIp); !found { + return deniedUnauthorized(config) + } + } + if deny != nil { + if realIp == nil { + log.Error("realIp is nil, continue") + return types.ActionContinue + } + if _, found, _ := deny.Get(realIp); found { + return deniedUnauthorized(config) + } + } + return types.ActionContinue +} + +func deniedUnauthorized(config RestrictionConfig) types.Action { + body, _ := json.Marshal(map[string]string{ + "message": config.Message, + }) + _ = proxywasm.SendHttpResponse(config.Status, nil, body, -1) + return types.ActionContinue +} diff --git a/plugins/wasm-go/extensions/ip-restriction/utils.go b/plugins/wasm-go/extensions/ip-restriction/utils.go new file mode 100644 index 000000000..869ca063f --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/utils.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "github.com/tidwall/gjson" + "github.com/zmap/go-iptree/iptree" + "strings" +) + +// parseIPNets 解析Ip段配置 +func parseIPNets(array []gjson.Result) (*iptree.IPTree, error) { + if len(array) == 0 { + return nil, nil + } else { + tree := iptree.New() + for _, result := range array { + err := tree.AddByString(result.String(), 0) + if err != nil { + return nil, fmt.Errorf("invalid IP[%s]", result.String()) + } + } + return tree, nil + } +} + +// parseIP 解析IP +func parseIP(source string) string { + if strings.Contains(source, ".") { + // parse ipv4 + return strings.Split(source, ":")[0] + } + //parse ipv6 + if strings.Contains(source, "]") { + return strings.Split(source, "]")[0][1:] + } + return source +} diff --git a/plugins/wasm-go/extensions/ip-restriction/utils_test.go b/plugins/wasm-go/extensions/ip-restriction/utils_test.go new file mode 100644 index 000000000..1c42eea3a --- /dev/null +++ b/plugins/wasm-go/extensions/ip-restriction/utils_test.go @@ -0,0 +1,106 @@ +package main + +import ( + "github.com/tidwall/gjson" + "testing" +) + +func Test_parseIPNets(t *testing.T) { + type args struct { + array []gjson.Result + } + tests := []struct { + name string + args args + wantVal bool + wantErr bool + }{ + { + name: "", + args: args{ + array: gjson.Parse(`["127.0.0.1/30","10.0.0.1"]`).Array(), + }, + wantVal: true, + wantErr: false, + }, + { + name: "", + args: args{ + array: gjson.Parse(``).Array(), + }, + wantVal: false, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseIPNets(tt.args.array) + if (err != nil) != tt.wantErr { + t.Errorf("parseIPNets() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantVal && got == nil { + return + } + if _, found, _ := got.GetByString("10.0.0.1"); found != tt.wantVal { + t.Errorf("parseIPNets() got = %v, want %v", found, tt.wantVal) + return + } + }) + } +} + +func Test_parseIP(t *testing.T) { + type args struct { + source string + } + tests := []struct { + name string + args args + want string + }{ + // TODO: Add test cases. + { + name: "case 1", + args: args{ + "127.0.0.1", + }, + want: "127.0.0.1", + }, + { + name: "case 2", + args: args{ + "127.0.0.1:12", + }, + want: "127.0.0.1", + }, + { + name: "case 3", + args: args{ + "fe80::14d5:8aff:fed9:2114", + }, + want: "fe80::14d5:8aff:fed9:2114", + }, + { + name: "case 4", + args: args{ + "[fe80::14d5:8aff:fed9:2114]:123", + }, + want: "fe80::14d5:8aff:fed9:2114", + }, + { + name: "case 5", + args: args{ + "127.0.0.1:12,[fe80::14d5:8aff:fed9:2114]:123", + }, + want: "127.0.0.1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := parseIP(tt.args.source); got != tt.want { + t.Errorf("parseIP() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/test/e2e/conformance/tests/go-wasm-ip-restriction-allow.yaml b/test/e2e/conformance/tests/go-wasm-ip-restriction-allow.yaml new file mode 100644 index 000000000..47a45832f --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-ip-restriction-allow.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2022 Alibaba Group Holding Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + name: httproute-app-root + namespace: higress-conformance-infra +spec: + ingressClassName: higress + rules: + - host: "foo.com" + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: infra-backend-v1 + port: + number: 8080 +--- +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: ip-restriction-allow + namespace: higress-system +spec: + defaultConfig: + ip_source_type: header + ip_header_name: x-real-ip + allow: + - 192.168.0.1/16 + - 10.0.0.1 + url: file:///opt/plugins/wasm-go/extensions/ip-restriction/plugin.wasm diff --git a/test/e2e/conformance/tests/go-wasm-ip-restriction-deny.yaml b/test/e2e/conformance/tests/go-wasm-ip-restriction-deny.yaml new file mode 100644 index 000000000..5c45a168a --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-ip-restriction-deny.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2022 Alibaba Group Holding Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + name: httproute-app-root + namespace: higress-conformance-infra +spec: + ingressClassName: higress + rules: + - host: "foo.com" + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: infra-backend-v1 + port: + number: 8080 +--- +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: ip-restriction-deny + namespace: higress-system +spec: + defaultConfig: + ip_source_type: header + ip_header_name: x-real-ip + deny: + - 192.168.0.1/16 + - 10.0.0.1 + url: file:///opt/plugins/wasm-go/extensions/ip-restriction/plugin.wasm diff --git a/test/e2e/conformance/tests/go-wasm-ip-restriction.go b/test/e2e/conformance/tests/go-wasm-ip-restriction.go new file mode 100644 index 000000000..cdd8a5263 --- /dev/null +++ b/test/e2e/conformance/tests/go-wasm-ip-restriction.go @@ -0,0 +1,219 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tests + +import ( + "testing" + + "github.com/alibaba/higress/test/e2e/conformance/utils/http" + "github.com/alibaba/higress/test/e2e/conformance/utils/suite" +) + +func init() { + Register(WasmPluginsIPRestrictionAllow) + Register(WasmPluginsIPRestrictionDeny) +} + +var WasmPluginsIPRestrictionAllow = suite.ConformanceTest{ + ShortName: "WasmPluginsIPRestrictionAllow", + Description: "The Ingress in the higress-conformance-infra namespace test the ip-restriction wasmplugins.", + Manifests: []string{"tests/go-wasm-ip-restriction-allow.yaml"}, + Features: []suite.SupportedFeature{suite.WASMGoConformanceFeature}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + testcases := []http.Assertion{ + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "10.0.0.1"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "10.0.0.2"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 403, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "192.168.5.0"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "192.169.5.0"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 403, + }, + ExpectedResponseNoRequest: true, + }, + }, + } + t.Run("WasmPlugins ip-restriction", func(t *testing.T) { + for _, testcase := range testcases { + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, testcase) + } + }) + }, +} + +var WasmPluginsIPRestrictionDeny = suite.ConformanceTest{ + ShortName: "WasmPluginsIPRestrictionDeny", + Description: "The Ingress in the higress-conformance-infra namespace test the ip-restriction wasmplugins.", + Manifests: []string{"tests/go-wasm-ip-restriction-deny.yaml"}, + Features: []suite.SupportedFeature{suite.WASMGoConformanceFeature}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + testcases := []http.Assertion{ + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "10.0.0.1"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 403, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "10.0.0.2"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "192.168.5.0"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 403, + }, + ExpectedResponseNoRequest: true, + }, + }, + { + Meta: http.AssertionMeta{ + TargetBackend: "infra-backend-v1", + TargetNamespace: "higress-conformance-infra", + }, + Request: http.AssertionRequest{ + ActualRequest: http.Request{ + Host: "foo.com", + Path: "/info", + UnfollowRedirect: true, + Headers: map[string]string{"X-REAL-IP": "192.169.5.0"}, + }, + }, + Response: http.AssertionResponse{ + ExpectedResponse: http.Response{ + StatusCode: 200, + }, + ExpectedResponseNoRequest: true, + }, + }, + } + t.Run("WasmPlugins ip-restriction", func(t *testing.T) { + for _, testcase := range testcases { + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, testcase) + } + }) + }, +}