This is an automated email from the ASF dual-hosted git repository.
shuyangw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 44ead1f feat(stream): add ip-restriction (#4602)
44ead1f is described below
commit 44ead1f46ec5b89666a1f700ff16eb00b00174e8
Author: 罗泽轩 <[email protected]>
AuthorDate: Wed Jul 21 07:09:44 2021 +0800
feat(stream): add ip-restriction (#4602)
Signed-off-by: spacewander <[email protected]>
---
Makefile | 3 +
apisix/plugins/ip-restriction.lua | 142 +-----------------
.../init.lua} | 4 +-
apisix/stream/plugins/ip-restriction.lua | 23 +++
conf/config-default.yaml | 1 +
t/stream-plugin/ip-restriction.t | 161 +++++++++++++++++++++
6 files changed, 193 insertions(+), 141 deletions(-)
diff --git a/Makefile b/Makefile
index f82cf33..4afde2f 100644
--- a/Makefile
+++ b/Makefile
@@ -215,6 +215,9 @@ install: default
$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/grpc-transcode
$(INSTALL) apisix/plugins/grpc-transcode/*.lua
$(INST_LUADIR)/apisix/plugins/grpc-transcode/
+ $(INSTALL) -d $(INST_LUADIR)/apisix/plugins/ip-restriction
+ $(INSTALL) apisix/plugins/ip-restriction/*.lua
$(INST_LUADIR)/apisix/plugins/ip-restriction/
+
$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/limit-conn
$(INSTALL) apisix/plugins/limit-conn/*.lua
$(INST_LUADIR)/apisix/plugins/limit-conn/
diff --git a/apisix/plugins/ip-restriction.lua
b/apisix/plugins/ip-restriction.lua
index 8791429..01b175b 100644
--- a/apisix/plugins/ip-restriction.lua
+++ b/apisix/plugins/ip-restriction.lua
@@ -14,146 +14,10 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-local ipairs = ipairs
-local core = require("apisix.core")
-local ipmatcher = require("resty.ipmatcher")
-local str_sub = string.sub
-local str_find = core.string.find
-local tonumber = tonumber
-local lrucache = core.lrucache.new({
- ttl = 300, count = 512
-})
+local ip_restriction = require("apisix.plugins.ip-restriction.init")
-local schema = {
- type = "object",
- properties = {
- message = {
- type = "string",
- minLength = 1,
- maxLength = 1024,
- default = "Your IP address is not allowed"
- },
- whitelist = {
- type = "array",
- items = {anyOf = core.schema.ip_def},
- minItems = 1
- },
- blacklist = {
- type = "array",
- items = {anyOf = core.schema.ip_def},
- minItems = 1
- },
- },
- oneOf = {
- {required = {"whitelist"}},
- {required = {"blacklist"}},
- },
- additionalProperties = false,
-}
+ip_restriction.access = ip_restriction.restrict
-local plugin_name = "ip-restriction"
-
-
-local _M = {
- version = 0.1,
- priority = 3000, -- TODO: add a type field, may be a good idea
- name = plugin_name,
- schema = schema,
-}
-
-
-local function valid_ip(ip)
- local mask = 0
- local sep_pos = str_find(ip, "/")
- if sep_pos then
- mask = str_sub(ip, sep_pos + 1)
- mask = tonumber(mask)
- if mask < 0 or mask > 128 then
- return false
- end
- ip = str_sub(ip, 1, sep_pos - 1)
- end
-
- if ipmatcher.parse_ipv4(ip) then
- if mask < 0 or mask > 32 then
- return false
- end
- return true
- end
-
- if mask < 0 or mask > 128 then
- return false
- end
- return ipmatcher.parse_ipv6(ip)
-end
-
-
-function _M.check_schema(conf)
- local ok, err = core.schema.check(schema, conf)
-
- if not ok then
- return false, err
- end
-
- -- we still need this as it is too complex to filter out all invalid IPv6
via regex
- if conf.whitelist and #conf.whitelist > 0 then
- for _, cidr in ipairs(conf.whitelist) do
- if not valid_ip(cidr) then
- return false, "invalid ip address: " .. cidr
- end
- end
- end
-
- if conf.blacklist and #conf.blacklist > 0 then
- for _, cidr in ipairs(conf.blacklist) do
- if not valid_ip(cidr) then
- return false, "invalid ip address: " .. cidr
- end
- end
- end
-
- return true
-end
-
-
-local function create_ip_matcher(ip_list)
- local ip, err = ipmatcher.new(ip_list)
- if not ip then
- core.log.error("failed to create ip matcher: ", err,
- " ip list: ", core.json.delay_encode(ip_list))
- return nil
- end
-
- return ip
-end
-
-
-function _M.access(conf, ctx)
- local block = false
- local remote_addr = ctx.var.remote_addr
-
- if conf.blacklist and #conf.blacklist > 0 then
- local matcher = lrucache(conf.blacklist, nil,
- create_ip_matcher, conf.blacklist)
- if matcher then
- block = matcher:match(remote_addr)
- end
- end
-
- if conf.whitelist and #conf.whitelist > 0 then
- local matcher = lrucache(conf.whitelist, nil,
- create_ip_matcher, conf.whitelist)
- if matcher then
- block = not matcher:match(remote_addr)
- end
- end
-
- if block then
- return 403, { message = conf.message }
- end
-end
-
-
-return _M
+return ip_restriction
diff --git a/apisix/plugins/ip-restriction.lua
b/apisix/plugins/ip-restriction/init.lua
similarity index 97%
copy from apisix/plugins/ip-restriction.lua
copy to apisix/plugins/ip-restriction/init.lua
index 8791429..373ea2c 100644
--- a/apisix/plugins/ip-restriction.lua
+++ b/apisix/plugins/ip-restriction/init.lua
@@ -58,7 +58,7 @@ local plugin_name = "ip-restriction"
local _M = {
version = 0.1,
- priority = 3000, -- TODO: add a type field, may be a good idea
+ priority = 3000,
name = plugin_name,
schema = schema,
}
@@ -130,7 +130,7 @@ local function create_ip_matcher(ip_list)
end
-function _M.access(conf, ctx)
+function _M.restrict(conf, ctx)
local block = false
local remote_addr = ctx.var.remote_addr
diff --git a/apisix/stream/plugins/ip-restriction.lua
b/apisix/stream/plugins/ip-restriction.lua
new file mode 100644
index 0000000..ffbfb2a
--- /dev/null
+++ b/apisix/stream/plugins/ip-restriction.lua
@@ -0,0 +1,23 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You 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.
+--
+local ip_restriction = require("apisix.plugins.ip-restriction.init")
+
+
+ip_restriction.preread = ip_restriction.restrict
+
+
+return ip_restriction
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index e221a4a..8db9af0 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -322,6 +322,7 @@ plugins: # plugin list (sorted by
priority)
- ext-plugin-post-req # priority: -3000
stream_plugins: # sorted by priority
+ - ip-restriction # priority: 3000
- limit-conn # priority: 1003
- mqtt-proxy # priority: 1000
# <- recommend to use priority (0, 100) for your custom plugins
diff --git a/t/stream-plugin/ip-restriction.t b/t/stream-plugin/ip-restriction.t
new file mode 100644
index 0000000..9f8ea5a
--- /dev/null
+++ b/t/stream-plugin/ip-restriction.t
@@ -0,0 +1,161 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_shuffle();
+no_root_location();
+
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ if (!$block->error_log && !$block->no_error_log) {
+ $block->set_value("no_error_log", "[error]\n[alert]");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: blacklist
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/upstreams/1',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": {
+ "127.0.0.1:1995": 1
+ },
+ "type": "roundrobin"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(body)
+ return
+ end
+
+ local code, body = t('/apisix/admin/stream_routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "ip-restriction": {
+ "blacklist": [
+ "127.0.0.0/24"
+ ]
+ }
+ },
+ "upstream_id": "1"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: hit
+--- stream_enable
+--- stream_request eval
+mmm
+--- error_log
+Connection reset by peer
+
+
+
+=== TEST 3: whitelist
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/stream_routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "ip-restriction": {
+ "whitelist": [
+ "127.0.0.0/24"
+ ]
+ }
+ },
+ "upstream_id": "1"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: hit
+--- stream_enable
+--- stream_request eval
+mmm
+--- stream_response
+hello world
+
+
+
+=== TEST 5: validate schema
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/stream_routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "ip-restriction": {
+ }
+ },
+ "upstream_id": "1"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- request
+GET /t
+--- error_code: 400
+--- response_body
+{"error_msg":"failed to check the configuration of stream plugin
[ip-restriction]: value should match only one schema, but matches none"}