feature: support to match IPv6 request. (#341)

* CLI: supported to listen IPv6.

* feature: supported to match route by remote address.
This commit is contained in:
YuanSheng Wang 2019-08-24 09:10:11 +08:00 committed by GitHub
parent c4cb7cd250
commit 1002765831
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 184 additions and 4 deletions

View File

@ -146,7 +146,7 @@ http {
listen {* port_admin *};
location /apisix/admin/ {
{% for _, allow_ip in ipairs(allow_admin) do %}
{% for _, allow_ip in ipairs(allow_admin or {}) do %}
allow {*allow_ip*};
{% end %}
deny all;
@ -161,6 +161,10 @@ http {
server {
listen {* node_listen *};
listen {* node_ssl_listen *} ssl;
{% if enable_ipv6 then %}
listen [::]:{* node_listen *};
listen [::]:{* node_ssl_listen *} ssl;
{% end %}
ssl_certificate cert/apisix.crt;
ssl_certificate_key cert/apisix.key;
ssl_session_cache shared:SSL:1m;

View File

@ -4,8 +4,10 @@ apisix:
enable_heartbeat: true
enable_admin: true
enable_debug: false
enable_ipv6: true
allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
- 127.0.0.0/24
- "::/64"
# port_admin: 9180 # use a separate port
real_ip_header: "X-Real-IP" # http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
real_ip_from: # http://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from

View File

@ -277,7 +277,8 @@ local route = [[{
"anyOf": [
{"pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$"},
{"pattern": "^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}]]
.. [[/[0-9]{1,2}$"}
.. [[/[0-9]{1,2}$"},
{"pattern": "^([a-f0-9]{0,4}:){0,8}(:[a-f0-9]{0,4}){0,8}$"}
]
},
"service_id": ]] .. json.encode(id_schema) .. [[,

View File

@ -47,6 +47,7 @@ local function push_valid_route(route)
core.table.insert(only_uri_routes, {
path = route.value.uri,
method = route.value.methods,
remote_addr = route.value.remote_addr,
handler = function (params, api_ctx)
api_ctx.matched_params = params
api_ctx.matched_route = route
@ -64,6 +65,7 @@ local function push_valid_route(route)
core.table.insert(host_uri_routes, {
path = "/" .. host .. route.value.uri,
method = route.value.methods,
remote_addr = route.value.remote_addr,
handler = function (params, api_ctx)
api_ctx.matched_params = params
api_ctx.matched_route = route
@ -104,6 +106,7 @@ function _M.match(api_ctx)
core.table.clear(match_opts)
match_opts.method = api_ctx.var.method
match_opts.remote_addr = api_ctx.var.remote_addr
local host_uri = "/" .. str_reverse(api_ctx.var.host) .. api_ctx.var.uri
local ok = host_uri_router:dispatch2(nil, host_uri, match_opts, api_ctx)

View File

@ -67,6 +67,7 @@ function _M.match(api_ctx)
core.table.clear(match_opts)
match_opts.method = api_ctx.var.method
match_opts.host = api_ctx.var.host
match_opts.remote_addr = api_ctx.var.remote_addr
local ok = uri_router:dispatch2(nil, api_ctx.var.uri, match_opts, api_ctx)
if not ok then

View File

@ -38,6 +38,7 @@ local function create_radixtree_router(routes)
path = route.value.uri,
method = route.value.methods,
host = route.value.host,
remote_addr = route.value.remote_addr,
handler = function (api_ctx)
api_ctx.matched_params = nil
api_ctx.matched_route = route
@ -66,6 +67,7 @@ function _M.match(api_ctx)
core.table.clear(match_opts)
match_opts.method = api_ctx.var.method
match_opts.host = api_ctx.var.host
match_opts.remote_addr = api_ctx.var.remote_addr
local ok = uri_router:dispatch(api_ctx.var.uri, match_opts, api_ctx)
if not ok then

5
t/APISix.pm vendored
View File

@ -105,11 +105,16 @@ _EOC_
$block->set_value("http_config", $http_config);
my $TEST_NGINX_HTML_DIR = $ENV{TEST_NGINX_HTML_DIR} ||= html_dir();
my $ipv6_listen_conf = '';
if (defined $block->listen_ipv6) {
$ipv6_listen_conf = "listen \[::1\]:12345;"
}
my $wait_etcd_sync = $block->wait_etcd_sync // 0.1;
my $config = $block->config // '';
$config .= <<_EOC_;
$ipv6_listen_conf
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
ssl_certificate cert/apisix.crt;

View File

@ -40,6 +40,45 @@ local methods = {
}
function _M.test_ipv6(uri)
local sock = ngx.socket.tcp()
local ok, err = sock:connect("[::1]", 12345)
if not ok then
ngx.say("failed to connect: ", err)
return
end
ngx.say("connected: ", ok)
local req = "GET " .. uri .. " HTTP/1.0\r\nHost: localhost\r\n"
.. "Connection: close\r\n\r\n"
-- req = "OK"
-- ngx.log(ngx.WARN, "req: ", req)
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send request: ", err)
return
end
ngx.say("request sent: ", bytes)
while true do
local line, err, part = sock:receive()
if line then
ngx.say("received: ", line)
else
ngx.say("failed to receive a line: ", err, " [", part, "]")
break
end
end
ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end
function _M.test(uri, method, body, pattern)
if type(body) == "table" then
body = json.encode(body)
@ -67,6 +106,10 @@ function _M.test(uri, method, body, pattern)
},
}
)
if not res then
ngx.log(ngx.ERR, "failed http: ", err)
return nil, err
end
if res.status >= 300 then
return res.status, res.body

118
t/node/remote-addr-ipv6.t Normal file
View File

@ -0,0 +1,118 @@
use t::APISix;
no_root_location();
my $travis_os_name = $ENV{TRAVIS_OS_NAME};
if ($travis_os_name eq "osx") {
plan 'no_plan';
} else {
plan(skip_all => "skip remote address(IPv6) under linux");
}
run_tests();
__DATA__
=== TEST 1: set route: remote addr = ::1
--- 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,
[[{
"remote_addr": "::1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 2: IPv6 /not_found
--- listen_ipv6
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test_ipv6
t('/not_found')
}
}
--- request
GET /t
--- response_body_like eval
qr{.*404 Not Found.*}
--- no_error_log
[error]
=== TEST 3: IPv4 /not_found
--- listen_ipv6
--- request
GET /not_found
--- error_code: 404
--- response_body_like eval
qr{.*404 Not Found.*}
--- no_error_log
[error]
=== TEST 4: IPv6 /hello
--- listen_ipv6
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.2)
local t = require("lib.test_admin").test_ipv6
t('/hello')
}
}
--- request
GET /t
--- response_body
connected: 1
request sent: 59
received: HTTP/1.1 200 OK
received: Content-Type: text/plain
received: Connection: close
received: Server: openresty
received:
received: hello world
failed to receive a line: closed []
close: 1 nil
--- no_error_log
[error]
=== TEST 5: IPv4 /hello
--- listen_ipv6
--- request
GET /hello
--- error_code: 404
--- response_body_like eval
qr{.*404 Not Found.*}
--- no_error_log
[error]

View File

@ -100,8 +100,9 @@ passed
=== TEST 5: not hit route: 127.0.0.2 =~ 127.0.0.1
--- request
GET /hello
--- response_body
hello world
--- error_code: 404
--- response_body_like eval
qr/404 Not Found/
--- no_error_log
[error]