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"}

Reply via email to