This is an automated email from the ASF dual-hosted git repository.
spacewander 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 0842b69c9 feat(real-ip): support search recursive (#6988)
0842b69c9 is described below
commit 0842b69c9246a2fb8f1f8af7025d18a019059ef6
Author: 疯狂的马骝 <[email protected]>
AuthorDate: Fri May 13 19:16:35 2022 +0800
feat(real-ip): support search recursive (#6988)
Co-authored-by: tangzhenhuang <[email protected]>
Co-authored-by: 罗泽轩 <[email protected]>
---
apisix/plugins/real-ip.lua | 38 ++++++++++++++++++++++++++-----
docs/en/latest/plugins/real-ip.md | 9 ++++----
docs/zh/latest/plugins/real-ip.md | 7 +++---
t/plugin/real-ip.t | 47 +++++++++++++++++++++++++++++++++++++++
4 files changed, 88 insertions(+), 13 deletions(-)
diff --git a/apisix/plugins/real-ip.lua b/apisix/plugins/real-ip.lua
index 7b6600f2a..242af9608 100644
--- a/apisix/plugins/real-ip.lua
+++ b/apisix/plugins/real-ip.lua
@@ -15,12 +15,16 @@
-- limitations under the License.
--
local core = require("apisix.core")
+local ngx_re_split = require("ngx.re").split
local is_apisix_or, client = pcall(require, "resty.apisix.client")
local str_byte = string.byte
local str_sub = string.sub
local ipairs = ipairs
local type = type
+local lrucache = core.lrucache.new({
+ type = "plugin",
+})
local schema = {
type = "object",
@@ -33,6 +37,10 @@ local schema = {
source = {
type = "string",
minLength = 1
+ },
+ recursive = {
+ type = "boolean",
+ default = false
}
},
required = {"source"},
@@ -67,6 +75,18 @@ function _M.check_schema(conf)
end
+local function addr_match(conf, ctx, addr)
+ local matcher, err = core.lrucache.plugin_ctx(lrucache, ctx, nil,
+ core.ip.create_ip_matcher,
conf.trusted_addresses)
+ if not matcher then
+ core.log.error("failed to create ip matcher: ", err)
+ return false
+ end
+
+ return matcher:match(addr)
+end
+
+
local function get_addr(conf, ctx)
if conf.source == "http_x_forwarded_for" then
-- use the last address from X-Forwarded-For header
@@ -84,6 +104,17 @@ local function get_addr(conf, ctx)
return addrs
end
+ if conf.recursive and conf.trusted_addresses then
+ local split_addrs = ngx_re_split(addrs, ",\\s*", "jo")
+ for i = #split_addrs, 2, -1 do
+ if not addr_match(conf, ctx, split_addrs[i]) then
+ return split_addrs[i]
+ end
+ end
+
+ return split_addrs[1]
+ end
+
for i = idx + 1, #addrs do
if str_byte(addrs, i) == str_byte(" ") then
idx = idx + 1
@@ -105,13 +136,8 @@ function _M.rewrite(conf, ctx)
end
if conf.trusted_addresses then
- if not conf.matcher then
- conf.matcher = core.ip.create_ip_matcher(conf.trusted_addresses)
- end
-
local remote_addr = ctx.var.remote_addr
- local trusted = conf.matcher:match(remote_addr)
- if not trusted then
+ if not addr_match(conf, ctx, remote_addr) then
return
end
end
diff --git a/docs/en/latest/plugins/real-ip.md
b/docs/en/latest/plugins/real-ip.md
index 45c4ceb67..f675bbaf1 100644
--- a/docs/en/latest/plugins/real-ip.md
+++ b/docs/en/latest/plugins/real-ip.md
@@ -41,10 +41,11 @@ This Plugin requires APISIX to run on
[APISIX-Base](../how-to-build.md#step-6-bu
## Attributes
-| Name | Type | Required | Valid values
| Description
|
-|-------------------|---------------|----------|-----------------------------------------------------------------|-----------------------------------------------------------------------------------|
-| source | string | True | Any Nginx variable like
`arg_realip` or `http_x_forwarded_for`. | Dynamically sets the client's IP
address and an optional port from APISIX's view. |
-| trusted_addresses | array[string] | False | List of IPs or CIDR ranges.
| Dynamically sets the `set_real_ip_from`
field. |
+| Name | Type | Required | Valid values
| Description
|
+|-------------------|---------------|----------|-----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| source | string | True | Any Nginx variable like
`arg_realip` or `http_x_forwarded_for`. | Dynamically sets the client's IP
address and an optional port from APISIX's view.
|
+| trusted_addresses | array[string] | False | List of IPs or CIDR ranges.
| Dynamically sets the `set_real_ip_from`
field.
|
+| recursive | boolean | False | True to enable, false to
disable, default is false | If recursive search is disabled, the
original client address that matches one of the trusted addresses is replaced
by the last address sent in the configured `source`. If recursive search is
enabled, the original client address that matches one of the trusted addresses
is replaced by the last non-trusted address sent in the configured `source`. |
:::note
diff --git a/docs/zh/latest/plugins/real-ip.md
b/docs/zh/latest/plugins/real-ip.md
index 9e16e5ff5..adcfaf589 100644
--- a/docs/zh/latest/plugins/real-ip.md
+++ b/docs/zh/latest/plugins/real-ip.md
@@ -42,9 +42,10 @@ description: 本文介绍了关于 Apache APISIX `real-ip` 插件的基本信息
## 属性
| 名称 | 类型 | 必选项 | 有效值
| 描述
|
-|-------------------|---------------|-------|-------------------------------------------------------------|----------------------------------------------------------------------|
-| source | string | 是 | 任何 NGINX 变量,如 `arg_realip` 或
`http_x_forwarded_for` 。 | 动态设置客户端的 IP 地址和端口。如果该值不包含端口,则不会更改客户端的端口。|
-| trusted_addresses | array[string] | 否 | IP 或 CIDR 范围列表。
| 动态设置 `set_real_ip_from` 字段。
|
+|-------------------|---------------|--|-------------------------------------------------------------|----------------------------------------------------------------------|
+| source | string | 是 | 任何 NGINX 变量,如 `arg_realip` 或
`http_x_forwarded_for` 。 | 动态设置客户端的 IP 地址和端口。如果该值不包含端口,则不会更改客户端的端口。|
+| trusted_addresses | array[string] | 否 | IP 或 CIDR 范围列表。
| 动态设置 `set_real_ip_from` 字段。
|
+| recursive | boolean | 否 | true 或者 false,默认是 false
|
如果禁用递归搜索,则与受信任地址之一匹配的原始客户端地址将替换为配置的`source`中发送的最后一个地址。如果启用递归搜索,则与受信任地址之一匹配的原始客户端地址将替换为配置的`source`中发送的最后一个非受信任地址。
|
:::note
diff --git a/t/plugin/real-ip.t b/t/plugin/real-ip.t
index 5df38137a..a2541d049 100644
--- a/t/plugin/real-ip.t
+++ b/t/plugin/real-ip.t
@@ -427,3 +427,50 @@ passed
GET /hello
--- more_headers
X-Forwarded-For: 1.1.1.1
+
+
+
+=== TEST 22: X-Forwarded-For and recursive
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/hello",
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": {
+ "127.0.0.1:1980": 1
+ }
+ },
+ "plugins": {
+ "real-ip": {
+ "trusted_addresses": ["192.128.0.0/16",
"127.0.0.0/24"],
+ "source": "http_x_forwarded_for",
+ "recursive": true
+ },
+ "ip-restriction": {
+ "whitelist": ["1.1.1.1"]
+ }
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+}
+--- response_body
+passed
+
+
+
+=== TEST 23: hit
+--- request
+GET /hello
+--- more_headers
+X-Forwarded-For: 1.1.1.1, 192.128.1.1, 127.0.0.1