From 987cc72adf605fca557cbfb12a6814daec468e5d Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Fri, 23 Aug 2019 11:35:22 +0800 Subject: [PATCH 1/9] CLI: supported to listen IPv6. --- bin/apisix | 6 +++++- conf/config.yaml | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/apisix b/bin/apisix index ce350982885c..7e5319cefb85 100755 --- a/bin/apisix +++ b/bin/apisix @@ -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; diff --git a/conf/config.yaml b/conf/config.yaml index 2b657a071259..2acec2d1e753 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -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 From c4220dbf9d1048ee85ea2dff2e84c11db6d1b516 Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 07:53:49 +0800 Subject: [PATCH 2/9] feature: supported to match route by remote address. --- lua/apisix/core/schema.lua | 3 +- lua/apisix/http/router/r3_uri.lua | 1 + lua/apisix/http/router/radixtree_uri.lua | 2 + t/APISix.pm | 2 + t/lib/test_admin.lua | 44 ++++++++++ t/node/remote-addr-ipv6.t | 107 +++++++++++++++++++++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 t/node/remote-addr-ipv6.t diff --git a/lua/apisix/core/schema.lua b/lua/apisix/core/schema.lua index de1d15219892..a36f129b6261 100644 --- a/lua/apisix/core/schema.lua +++ b/lua/apisix/core/schema.lua @@ -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) .. [[, diff --git a/lua/apisix/http/router/r3_uri.lua b/lua/apisix/http/router/r3_uri.lua index 556b7c238284..6c266057680c 100644 --- a/lua/apisix/http/router/r3_uri.lua +++ b/lua/apisix/http/router/r3_uri.lua @@ -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 diff --git a/lua/apisix/http/router/radixtree_uri.lua b/lua/apisix/http/router/radixtree_uri.lua index 99e06c1e221e..bb409de799fe 100644 --- a/lua/apisix/http/router/radixtree_uri.lua +++ b/lua/apisix/http/router/radixtree_uri.lua @@ -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 diff --git a/t/APISix.pm b/t/APISix.pm index 960fdb43513b..88227f803a85 100644 --- a/t/APISix.pm +++ b/t/APISix.pm @@ -105,11 +105,13 @@ _EOC_ $block->set_value("http_config", $http_config); my $TEST_NGINX_HTML_DIR = $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); + my $TEST_NGINX_SERVER_PORT = $ENV{TEST_NGINX_SERVER_PORT} // 1984; my $wait_etcd_sync = $block->wait_etcd_sync // 0.1; my $config = $block->config // ''; $config .= <<_EOC_; + listen \[::1\]:$TEST_NGINX_SERVER_PORT; listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate cert/apisix.crt; diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua index 1b98e0b91eec..22882bd96d05 100644 --- a/t/lib/test_admin.lua +++ b/t/lib/test_admin.lua @@ -40,6 +40,46 @@ local methods = { } +function _M.test_ipv6(uri) + local sock = ngx.socket.tcp() + local port = ngx.var.server_port + local ok, err = sock:connect("[::1]", port) + 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 +107,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 diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t new file mode 100644 index 000000000000..ef4e2201e0fe --- /dev/null +++ b/t/node/remote-addr-ipv6.t @@ -0,0 +1,107 @@ +use t::APISix 'no_plan'; + +no_root_location(); + +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 +--- 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 +--- request +GET /not_found +--- error_code: 404 +--- response_body_like eval +qr{.*404 Not Found.*} +--- no_error_log +[error] + + + +=== TEST 4: IPv6 /hello +--- 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 +--- request +GET /hello +--- error_code: 404 +--- response_body_like eval +qr{.*404 Not Found.*} +--- no_error_log +[error] From e8f7afd8b5ccea3c601f2afc595cc4c8292484d5 Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 07:56:29 +0800 Subject: [PATCH 3/9] feature: supported to match `remote addr` for router `r3_host_uri`. --- lua/apisix/http/router/r3_host_uri.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/apisix/http/router/r3_host_uri.lua b/lua/apisix/http/router/r3_host_uri.lua index 76e4868df89b..4a3f726f5bd0 100644 --- a/lua/apisix/http/router/r3_host_uri.lua +++ b/lua/apisix/http/router/r3_host_uri.lua @@ -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) From 85c2f7722d7c7bc0f83a807a6841c72cd08c0b97 Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 08:03:24 +0800 Subject: [PATCH 4/9] test: changed the IPv6 listen port to 12345. --- t/APISix.pm | 2 +- t/lib/test_admin.lua | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/t/APISix.pm b/t/APISix.pm index 88227f803a85..a0d701440778 100644 --- a/t/APISix.pm +++ b/t/APISix.pm @@ -105,7 +105,7 @@ _EOC_ $block->set_value("http_config", $http_config); my $TEST_NGINX_HTML_DIR = $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - my $TEST_NGINX_SERVER_PORT = $ENV{TEST_NGINX_SERVER_PORT} // 1984; + my $TEST_NGINX_SERVER_PORT = 12345; my $wait_etcd_sync = $block->wait_etcd_sync // 0.1; diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua index 22882bd96d05..17922b89d71d 100644 --- a/t/lib/test_admin.lua +++ b/t/lib/test_admin.lua @@ -42,8 +42,7 @@ local methods = { function _M.test_ipv6(uri) local sock = ngx.socket.tcp() - local port = ngx.var.server_port - local ok, err = sock:connect("[::1]", port) + local ok, err = sock:connect("[::1]", 12345) if not ok then ngx.say("failed to connect: ", err) return From 446f8a7433a17e81fc41c3cf22df0c88367b4ccd Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 08:21:43 +0800 Subject: [PATCH 5/9] test: skipped if under linux. --- t/node/remote-addr-ipv6.t | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t index ef4e2201e0fe..056ee88d4fd4 100644 --- a/t/node/remote-addr-ipv6.t +++ b/t/node/remote-addr-ipv6.t @@ -1,7 +1,14 @@ -use t::APISix 'no_plan'; +use t::APISix; no_root_location(); +my $unmae = `uname`; +if ($unmae eq "linux") { + plan(skip_all => "skip remote address(IPv6) under linux"); +} else { + plan 'no_plan'; +} + run_tests(); __DATA__ From 2dd6e105dc330c4ab3741659a81bae2a80ad74bc Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 08:26:59 +0800 Subject: [PATCH 6/9] test: added new option `listen_ipv6`. --- t/APISix.pm | 7 +++++-- t/node/remote-addr-ipv6.t | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/t/APISix.pm b/t/APISix.pm index a0d701440778..f68c63de5028 100644 --- a/t/APISix.pm +++ b/t/APISix.pm @@ -105,13 +105,16 @@ _EOC_ $block->set_value("http_config", $http_config); my $TEST_NGINX_HTML_DIR = $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); - my $TEST_NGINX_SERVER_PORT = 12345; + 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_; - listen \[::1\]:$TEST_NGINX_SERVER_PORT; + $ipv6_listen_conf listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate cert/apisix.crt; diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t index 056ee88d4fd4..cf89fa77bc2d 100644 --- a/t/node/remote-addr-ipv6.t +++ b/t/node/remote-addr-ipv6.t @@ -49,6 +49,7 @@ passed === TEST 2: IPv6 /not_found +--- listen_ipv6 --- config location /t { content_by_lua_block { @@ -67,6 +68,7 @@ qr{.*404 Not Found.*} === TEST 3: IPv4 /not_found +--- listen_ipv6 --- request GET /not_found --- error_code: 404 @@ -78,6 +80,7 @@ qr{.*404 Not Found.*} === TEST 4: IPv6 /hello +--- listen_ipv6 --- config location /t { content_by_lua_block { @@ -105,6 +108,7 @@ close: 1 nil === TEST 5: IPv4 /hello +--- listen_ipv6 --- request GET /hello --- error_code: 404 From af86d929d04c1798c7a8e20ab6cc3367ced08d09 Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 08:42:58 +0800 Subject: [PATCH 7/9] test: typo. --- t/node/remote-addr-ipv6.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t index cf89fa77bc2d..8a3686c763e5 100644 --- a/t/node/remote-addr-ipv6.t +++ b/t/node/remote-addr-ipv6.t @@ -2,8 +2,9 @@ use t::APISix; no_root_location(); -my $unmae = `uname`; -if ($unmae eq "linux") { +my $uname = eval { `uname` }; +chomp $uname; +if ($uname eq "linux") { plan(skip_all => "skip remote address(IPv6) under linux"); } else { plan 'no_plan'; From eb149d93078a008cc1a42690d965318ab0a175fa Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 08:53:51 +0800 Subject: [PATCH 8/9] test: use `TRAVIS_OS_NAME`. --- t/node/remote-addr-ipv6.t | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t index 8a3686c763e5..1d370c88f91a 100644 --- a/t/node/remote-addr-ipv6.t +++ b/t/node/remote-addr-ipv6.t @@ -2,12 +2,11 @@ use t::APISix; no_root_location(); -my $uname = eval { `uname` }; -chomp $uname; -if ($uname eq "linux") { - plan(skip_all => "skip remote address(IPv6) under linux"); -} else { +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(); From 68721973b894b86c6713a7032053b42943bf1d9d Mon Sep 17 00:00:00 2001 From: Yuansheng Date: Sat, 24 Aug 2019 09:00:36 +0800 Subject: [PATCH 9/9] test: should not match. --- t/node/remote-addr.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/node/remote-addr.t b/t/node/remote-addr.t index a480d6eeb034..47aa211fdd6e 100644 --- a/t/node/remote-addr.t +++ b/t/node/remote-addr.t @@ -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]