You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2019/11/06 06:27:16 UTC
[incubator-apisix] branch master updated: fix:
core.utils.parse_addr didn't parse IPv6 address correctly (#809)
This is an automated email from the ASF dual-hosted git repository.
membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git
The following commit(s) were added to refs/heads/master by this push:
new b7e2800 fix: core.utils.parse_addr didn't parse IPv6 address correctly (#809)
b7e2800 is described below
commit b7e280033bcdad46ef45656242cec4685161ba30
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Wed Nov 6 14:27:08 2019 +0800
fix: core.utils.parse_addr didn't parse IPv6 address correctly (#809)
---
lua/apisix/balancer.lua | 21 +++---------------
lua/apisix/core/utils.lua | 55 ++++++++++++++++++++++++++++++++++++++++-------
t/core/utils.t | 27 +++++++++++++++++++++++
3 files changed, 77 insertions(+), 26 deletions(-)
diff --git a/lua/apisix/balancer.lua b/lua/apisix/balancer.lua
index 8fa20c7..01cb0f5 100644
--- a/lua/apisix/balancer.lua
+++ b/lua/apisix/balancer.lua
@@ -19,13 +19,10 @@ local roundrobin = require("resty.roundrobin")
local resty_chash = require("resty.chash")
local balancer = require("ngx.balancer")
local core = require("apisix.core")
-local sub_str = string.sub
-local find_str = string.find
local error = error
local str_char = string.char
local str_gsub = string.gsub
local pairs = pairs
-local tonumber = tonumber
local tostring = tostring
local set_more_tries = balancer.set_more_tries
local get_last_failure = balancer.get_last_failure
@@ -50,18 +47,6 @@ local _M = {
}
-local function parse_addr(addr)
- local pos = find_str(addr, ":", 1, true)
- if not pos then
- return addr, 80
- end
-
- local host = sub_str(addr, 1, pos - 1)
- local port = sub_str(addr, pos + 1)
- return host, tonumber(port)
-end
-
-
local function fetch_health_nodes(upstream, checker)
if not checker then
return upstream.nodes
@@ -71,7 +56,7 @@ local function fetch_health_nodes(upstream, checker)
local up_nodes = core.table.new(0, #upstream.nodes)
for addr, weight in pairs(upstream.nodes) do
- local ip, port = parse_addr(addr)
+ local ip, port = core.utils.parse_addr(addr)
local ok = checker:get_target_status(ip, port, host)
if ok then
up_nodes[addr] = weight
@@ -95,7 +80,7 @@ local function create_checker(upstream, healthcheck_parent)
})
for addr, weight in pairs(upstream.nodes) do
- local ip, port = parse_addr(addr)
+ local ip, port = core.utils.parse_addr(addr)
local ok, err = checker:add_target(ip, port, upstream.checks.host)
if not ok then
core.log.error("failed to add new health check target: ", addr,
@@ -267,7 +252,7 @@ local function pick_server(route, ctx)
end
end
- local ip, port, err = parse_addr(server)
+ local ip, port, err = core.utils.parse_addr(server)
ctx.balancer_ip = ip
ctx.balancer_port = port
diff --git a/lua/apisix/core/utils.lua b/lua/apisix/core/utils.lua
index 8f68a14..3a5bd36 100644
--- a/lua/apisix/core/utils.lua
+++ b/lua/apisix/core/utils.lua
@@ -21,7 +21,7 @@ local ipmatcher= require("resty.ipmatcher")
local open = io.open
local math = math
local sub_str = string.sub
-local find_str = string.find
+local str_byte = string.byte
local tonumber = tonumber
@@ -83,15 +83,54 @@ function _M.dns_parse(resolvers, domain)
end
-function _M.parse_addr(addr)
- local pos = find_str(addr, ":", 1, true)
- if not pos then
- return addr, 80
+local function rfind_char(s, ch, idx)
+ local b = str_byte(ch)
+ for i = idx or #s, 1, -1 do
+ if str_byte(s, i, i) == b then
+ return i
+ end
end
+ return nil
+end
+
- local host = sub_str(addr, 1, pos - 1)
- local port = sub_str(addr, pos + 1)
- return host, tonumber(port)
+-- parse_addr parses 'addr' into the host and the port parts. If the 'addr'
+-- doesn't have a port, 80 is used to return. For malformed 'addr', the entire
+-- 'addr' is returned as the host part. For IPv6 literal host, like [::1], the
+-- square brackets will be removed.
+function _M.parse_addr(addr)
+ local default_port = 80
+ if str_byte(addr, 1) == str_byte("[") then
+ -- IPv6 format
+ local right_bracket = str_byte("]")
+ local len = #addr
+ if str_byte(addr, len) == right_bracket then
+ -- addr in [ip:v6] format
+ return sub_str(addr, 2, len-1), default_port
+ else
+ local pos = rfind_char(addr, ":", #addr - 1)
+ if not pos or str_byte(addr, pos - 1) ~= right_bracket then
+ -- malformed addr
+ return addr, default_port
+ end
+
+ -- addr in [ip:v6]:port format
+ local host = sub_str(addr, 2, pos - 2)
+ local port = sub_str(addr, pos + 1)
+ return host, tonumber(port)
+ end
+
+ else
+ -- IPv4 format
+ local pos = rfind_char(addr, ":", #addr - 1)
+ if not pos then
+ return addr, default_port
+ end
+
+ local host = sub_str(addr, 1, pos - 1)
+ local port = sub_str(addr, pos + 1)
+ return host, tonumber(port)
+ end
end
diff --git a/t/core/utils.t b/t/core/utils.t
index d4c3666..92e67bb 100644
--- a/t/core/utils.t
+++ b/t/core/utils.t
@@ -39,3 +39,30 @@ __DATA__
GET /t
--- response_body_like eval
qr/random seed \d+\ntwice: false/
+
+
+
+=== TEST 2: parse_addr
+--- config
+ location /t {
+ content_by_lua_block {
+ local parse_addr = require("apisix.core.utils").parse_addr
+ local cases = {
+ {addr = "127.0.0.1", host = "127.0.0.1", port = 80},
+ {addr = "127.0.0.1:90", host = "127.0.0.1", port = 90},
+ {addr = "www.test.com", host = "www.test.com", port = 80},
+ {addr = "www.test.com:90", host = "www.test.com", port = 90},
+ {addr = "[127.0.0.1:90", host = "[127.0.0.1:90", port = 80},
+ {addr = "[::1]", host = "::1", port = 80},
+ {addr = "[::1]:1234", host = "::1", port = 1234},
+ {addr = "[::1234:1234]:12345", host = "::1234:1234", port = 12345},
+ }
+ for _, case in ipairs(cases) do
+ local host, port = parse_addr(case.addr)
+ assert(host == case.host, string.format("host %s mismatch %s", host, case.host))
+ assert(port == case.port, string.format("port %s mismatch %s", port, case.port))
+ end
+ }
+ }
+--- request
+GET /t