Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(real-ip): implement the first version #4813

Merged
merged 3 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions apisix/plugins/real-ip.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
--
-- 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 core = require("apisix.core")
local is_apisix_or, client = pcall(require, "resty.apisix.client")
local str_byte = string.byte
local str_sub = string.sub


local schema = {
type = "object",
properties = {
source = {
type = "string",
minLength = 1
}
},
required = {"source"},
}


local plugin_name = "real-ip"


local _M = {
version = 0.1,
priority = 23000,
name = plugin_name,
schema = schema,
}


function _M.check_schema(conf)
return core.schema.check(schema, conf)
end


local function get_addr(conf, ctx)
return ctx.var[conf.source]
end


function _M.rewrite(conf, ctx)
if not is_apisix_or then
core.log.error("need to build APISIX-OpenResty to support setting real ip")
return 501
end

local addr = get_addr(conf, ctx)
if not addr then
core.log.warn("missing real address")
return
end

local ip, port = core.utils.parse_addr(addr)
if not ip or (not core.utils.parse_ipv4(ip) and not core.utils.parse_ipv6(ip)) then
core.log.warn("bad address: ", addr)
return
end

if str_byte(ip, 1, 1) == str_byte("[") then
-- For IPv6, the `set_real_ip` accepts '::1' but not '[::1]'
ip = str_sub(ip, 2, #ip - 1)
end

if port ~= nil and (port < 1 or port > 65535) then
core.log.warn("bad port: ", port)
return
end

core.log.info("set real ip: ", ip, ", port: ", port)

local ok, err = client.set_real_ip(ip, port)
if not ok then
core.log.error("failed to set real ip: ", err)
return
end

-- flush cached vars in APISIX
ctx.var.remote_addr = nil
ctx.var.remote_port = nil
ctx.var.realip_remote_addr = nil
ctx.var.realip_remote_port = nil
end


return _M
1 change: 1 addition & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ graphql:
#cmd: ["ls", "-l"]

plugins: # plugin list (sorted by priority)
- real-ip # priority: 23000
- client-control # priority: 22000
- ext-plugin-pre-req # priority: 12000
- zipkin # priority: 11011
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"plugins/redirect",
"plugins/echo",
"plugins/gzip",
"plugins/real-ip",
"plugins/server-info",
"plugins/ext-plugin-pre-req",
"plugins/ext-plugin-post-req"
Expand Down
2 changes: 1 addition & 1 deletion docs/en/latest/plugins/client-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ title: client-control
The `client-control` plugin dynamically controls the behavior of Nginx to
handle the client request.

This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#step-6-build-openresty-for-apache-apisix).
**This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#step-6-build-openresty-for-apache-apisix).**

## Attributes

Expand Down
2 changes: 1 addition & 1 deletion docs/en/latest/plugins/gzip.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ title: gzip

The `gzip` plugin dynamically set the gzip behavior of Nginx.

This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#step-6-build-openresty-for-apache-apisix).
**This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#step-6-build-openresty-for-apache-apisix).**

## Attributes

Expand Down
106 changes: 106 additions & 0 deletions docs/en/latest/plugins/real-ip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: real-ip
---

<!--
#
# 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.
#
-->

## Summary

- [**Name**](#name)
- [**Attributes**](#attributes)
- [**How To Enable**](#how-to-enable)
- [**Test Plugin**](#test-plugin)
- [**Disable Plugin**](#disable-plugin)

## Name

The `real-ip` plugin dynamically changes the client's IP and port seen by APISIX.

It works like Nginx's `ngx_http_realip_module`, but is more flexible.

**This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#step-6-build-openresty-for-apache-apisix).**

## Attributes

| Name | Type | Requirement | Default | Valid | Description |
| --------- | ------------- | ----------- | ---------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| source | string | required | | Any Nginx variable like `arg_realip` or `http_x_forwarded_for`| dynamically set the client's IP and port in APISIX's view, according to the value of variable. If the value doesn't contain a port, the client's port won't be changed. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may also hint to the users that if the address format is not correct, the real-ip plugin will just let it go and don't change the client address.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in the new commit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in the new commit


If the remote address comes from `source` is missing or invalid, this plugin will just let it go and don't change the client address.

## How To Enable

Here's an example, enable this plugin on the specified route:

```shell
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"real-ip": {
"source": "arg_realip"
},
"response-rewrite": {
"headers": {
"remote_addr": "$remote_addr",
"remote_port": "$remote_port"
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

## Test Plugin

Use curl to access:

```shell
curl 'http://127.0.0.1:9080/index.html?realip=1.2.3.4:9080' -I
...
remote-addr: 1.2.3.4
remote-port: 9080
```

## Disable Plugin

When you want to disable this plugin, it is very simple,
you can delete the corresponding JSON configuration in the plugin configuration,
no need to restart the service, it will take effect immediately:

```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```

This plugin has been disabled now. It works for other plugins.
2 changes: 1 addition & 1 deletion t/admin/plugins.t
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
qr/\["real-ip","client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
--- no_error_log
[error]

Expand Down
2 changes: 1 addition & 1 deletion t/core/config.t
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ __DATA__
GET /t
--- response_body
etcd host: http://127.0.0.1:2379
first plugin: "client-control"
first plugin: "real-ip"



Expand Down
1 change: 1 addition & 0 deletions t/debug/debug-mode.t
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ GET /t
--- response_body
done
--- error_log
loaded plugin and sort by priority: 23000 name: real-ip
loaded plugin and sort by priority: 22000 name: client-control
loaded plugin and sort by priority: 12000 name: ext-plugin-pre-req
loaded plugin and sort by priority: 11011 name: zipkin
Expand Down
Loading