This is an automated email from the ASF dual-hosted git repository.
tokers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new cd3a80c feat: parse_addr supports IPv6 without brackets (#4784)
cd3a80c is described below
commit cd3a80c29567e3a5711283908544690e46eeab2f
Author: 罗泽轩 <[email protected]>
AuthorDate: Wed Aug 11 19:18:02 2021 +0800
feat: parse_addr supports IPv6 without brackets (#4784)
Signed-off-by: spacewander <[email protected]>
---
apisix/core/utils.lua | 54 ++++++++++++++++++++++++++++++++++++++++-----------
t/core/utils.t | 3 +++
2 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/apisix/core/utils.lua b/apisix/core/utils.lua
index 7fb1493..5f22852 100644
--- a/apisix/core/utils.lua
+++ b/apisix/core/utils.lua
@@ -136,13 +136,31 @@ local function rfind_char(s, ch, idx)
end
+local function _parse_ipv4_or_host(addr)
+ local pos = rfind_char(addr, ":", #addr - 1)
+ if not pos then
+ return addr, nil
+ end
+
+ local host = sub_str(addr, 1, pos - 1)
+ local port = sub_str(addr, pos + 1)
+ return host, tonumber(port)
+end
+
+
+local function _parse_ipv6_without_port(addr)
+ return addr
+end
+
+
-- parse_addr parses 'addr' into the host and the port parts. If the 'addr'
--- doesn't have a port, nil 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 kept.
+-- doesn't have a port, nil is used to return.
+-- For IPv6 literal host with brackets, like [::1], the square brackets will
be kept.
+-- For malformed 'addr', the returned value can be anything. This method
doesn't validate
+-- if the input is valid.
function _M.parse_addr(addr)
if str_byte(addr, 1) == str_byte("[") then
- -- IPv6 format
+ -- IPv6 format, with brackets, maybe with port
local right_bracket = str_byte("]")
local len = #addr
if str_byte(addr, len) == right_bracket then
@@ -162,15 +180,29 @@ function _M.parse_addr(addr)
end
else
- -- IPv4 format
- local pos = rfind_char(addr, ":", #addr - 1)
- if not pos then
- return addr, nil
+ -- When we reach here, the input can be:
+ -- 1. IPv4
+ -- 2. IPv4, with port
+ -- 3. IPv6, like "2001:db8::68" or "::ffff:192.0.2.1"
+ -- 4. Malformed input
+ -- 5. Host, like "test.com" or "localhost"
+ -- 6. Host with port
+ local colon = str_byte(":")
+ local colon_counter = 0
+ local dot = str_byte(".")
+ for i = 1, #addr do
+ local ch = str_byte(addr, i, i)
+ if ch == dot then
+ return _parse_ipv4_or_host(addr)
+ elseif ch == colon then
+ colon_counter = colon_counter + 1
+ if colon_counter == 2 then
+ return _parse_ipv6_without_port(addr)
+ end
+ end
end
- local host = sub_str(addr, 1, pos - 1)
- local port = sub_str(addr, pos + 1)
- return host, tonumber(port)
+ return _parse_ipv4_or_host(addr)
end
end
diff --git a/t/core/utils.t b/t/core/utils.t
index 481a704..9b40610 100644
--- a/t/core/utils.t
+++ b/t/core/utils.t
@@ -52,10 +52,13 @@ qr/random seed \d+(\.\d+)?(e\+\d+)?\ntwice: false/
{addr = "127.0.0.1:90", host = "127.0.0.1", port = 90},
{addr = "www.test.com", host = "www.test.com"},
{addr = "www.test.com:90", host = "www.test.com", port = 90},
+ {addr = "localhost", host = "localhost"},
+ {addr = "localhost:90", host = "localhost", port = 90},
{addr = "[127.0.0.1:90", host = "[127.0.0.1:90"},
{addr = "[::1]", host = "[::1]"},
{addr = "[::1]:1234", host = "[::1]", port = 1234},
{addr = "[::1234:1234]:12345", host = "[::1234:1234]", port =
12345},
+ {addr = "::1", host = "::1"},
}
for _, case in ipairs(cases) do
local host, port = parse_addr(case.addr)