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 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_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) 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..f68c63de5028 100644 --- a/t/APISix.pm +++ b/t/APISix.pm @@ -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; diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua index 1b98e0b91eec..17922b89d71d 100644 --- a/t/lib/test_admin.lua +++ b/t/lib/test_admin.lua @@ -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 diff --git a/t/node/remote-addr-ipv6.t b/t/node/remote-addr-ipv6.t new file mode 100644 index 000000000000..1d370c88f91a --- /dev/null +++ b/t/node/remote-addr-ipv6.t @@ -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] 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]