This is an automated email from the ASF dual-hosted git repository.

nic443 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 cfb9a64ce fix(performance): move the ipv6 check to schema validation 
(#12714)
cfb9a64ce is described below

commit cfb9a64ce3dd09e4987c6daddf5af7502d450c6e
Author: Ashish Tiwari <[email protected]>
AuthorDate: Tue Nov 4 14:35:23 2025 +0530

    fix(performance): move the ipv6 check to schema validation (#12714)
---
 apisix/balancer.lua    |  7 ------
 apisix/upstream.lua    | 17 +++++++++++--
 t/admin/upstream.t     | 30 +++++++++++++++++++++++
 t/core/schema_def.t    | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++
 t/node/upstream-ipv6.t |  8 +++---
 5 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/apisix/balancer.lua b/apisix/balancer.lua
index ffb797307..5b6b3b029 100644
--- a/apisix/balancer.lua
+++ b/apisix/balancer.lua
@@ -27,7 +27,6 @@ local set_more_tries   = balancer.set_more_tries
 local get_last_failure = balancer.get_last_failure
 local set_timeouts     = balancer.set_timeouts
 local ngx_now          = ngx.now
-local str_byte         = string.byte
 
 local module_name = "balancer"
 local pickers = {}
@@ -195,12 +194,6 @@ end
 local function pick_server(route, ctx)
     local up_conf = ctx.upstream_conf
 
-    for _, node in ipairs(up_conf.nodes) do
-        if core.utils.parse_ipv6(node.host) and str_byte(node.host, 1) ~= 
str_byte("[") then
-            node.host = '[' .. node.host .. ']'
-        end
-    end
-
     local nodes_count = #up_conf.nodes
     if nodes_count == 1 then
         local node = up_conf.nodes[1]
diff --git a/apisix/upstream.lua b/apisix/upstream.lua
index ad374b7b5..37bf25720 100644
--- a/apisix/upstream.lua
+++ b/apisix/upstream.lua
@@ -25,6 +25,7 @@ local tostring = tostring
 local ipairs = ipairs
 local pairs = pairs
 local pcall = pcall
+local str_byte = string.byte
 local ngx_var = ngx.var
 local is_http = ngx.config.subsystem == "http"
 local upstreams
@@ -325,10 +326,16 @@ function _M.upstreams()
 end
 
 
-function _M.check_schema(conf)
+local function check_schema(conf)
+    for _, node in ipairs(conf.nodes or {}) do
+        if core.utils.parse_ipv6(node.host) and str_byte(node.host, 1) ~= 
str_byte("[") then
+            return false, "IPv6 address must be enclosed with '[' and ']'"
+        end
+    end
     return core.schema.check(core.schema.upstream, conf)
 end
 
+_M.check_schema = check_schema
 
 local function get_chash_key_schema(hash_on)
     if not hash_on then
@@ -357,7 +364,7 @@ end
 
 local function check_upstream_conf(in_dp, conf)
     if not in_dp then
-        local ok, err = core.schema.check(core.schema.upstream, conf)
+        local ok, err = check_schema(conf)
         if not ok then
             return false, "invalid configuration: " .. err
         end
@@ -396,6 +403,12 @@ local function check_upstream_conf(in_dp, conf)
                                     .. "wrong ssl type"
             end
         end
+    else
+        for i, node in ipairs(conf.nodes or {}) do
+            if core.utils.parse_ipv6(node.host) and str_byte(node.host, 1) ~= 
str_byte("[") then
+                conf.nodes[i].host = "[" .. node.host .. "]"
+            end
+        end
     end
 
     if is_http then
diff --git a/t/admin/upstream.t b/t/admin/upstream.t
index cbc44d49a..0aa3618c5 100644
--- a/t/admin/upstream.t
+++ b/t/admin/upstream.t
@@ -722,3 +722,33 @@ GET /t
 GET /t
 --- response_body
 passed
+
+
+
+=== TEST 23: verify wrong Ipv6
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin")
+
+            local data = {
+                nodes = {
+                    {host = "::1", port = 80, weight = 1},
+                },
+                type = "roundrobin"
+            }
+            local code, body = t.test('/apisix/admin/upstreams',
+                ngx.HTTP_POST,
+                core.json.encode(data)
+            )
+
+            ngx.status = code
+            ngx.print(body)
+        }
+    }
+--- request
+GET /t
+--- error_code: 400
+--- response_body
+{"error_msg":"invalid configuration: IPv6 address must be enclosed with '[' 
and ']'"}
diff --git a/t/core/schema_def.t b/t/core/schema_def.t
index 2d816d560..c039d3d54 100644
--- a/t/core/schema_def.t
+++ b/t/core/schema_def.t
@@ -250,3 +250,69 @@ passed
     }
 --- response_body
 passed
+
+
+
+=== TEST 5: validate IPv6 address format in upstream nodes
+--- config
+location /t {
+    content_by_lua_block {
+        local schema_def = require("apisix.schema_def")
+        local core = require("apisix.core")
+        local upstream = require("apisix.upstream")
+        local t = require("lib.test_admin")
+        -- Test valid IPv6 addresses (enclosed in brackets)
+        local valid_cases = {
+            {
+                nodes = {
+                    {host = "[::1]", port = 80, weight = 1},
+                },
+                type = "roundrobin"
+            },
+            {
+                nodes = {
+                    {host = "[2001:db8::1]", port = 80, weight = 1},
+                },
+                type = "roundrobin"
+            }
+        }
+
+        for _, ups in ipairs(valid_cases) do
+            local ok, err = upstream.check_schema(ups)
+            if not ok then
+                ngx.log(ngx.ERR, "Expected valid case failed: ", err)
+            end
+            assert(ok, "Valid IPv6 case should pass: " .. (err or ""))
+        end
+
+        -- Test invalid IPv6 addresses (not enclosed in brackets)
+        local invalid_cases = {
+            {
+                nodes = {
+                    {host = "::1", port = 80, weight = 1},
+                },
+                type = "roundrobin"
+            },
+            {
+                nodes = {
+                    {host = "2001:db8::1", port = 80, weight = 1},
+                },
+                type = "roundrobin"
+            }
+        }
+
+        for i, ups in ipairs(invalid_cases) do
+            local ok, err = upstream.check_schema(ups)
+            if ok then
+                ngx.log(ngx.ERR, "Expected invalid case passed: ", i)
+            end
+            assert(not ok, "Invalid IPv6 case should fail")
+            assert(string.find(err, "IPv6 address must be enclosed with '%[' 
and '%]'"),
+                   "Error should mention IPv6 enclosure requirement")
+        end
+
+        ngx.say("passed")
+    }
+}
+--- response_body
+passed
diff --git a/t/node/upstream-ipv6.t b/t/node/upstream-ipv6.t
index 760109a2c..a2509577b 100644
--- a/t/node/upstream-ipv6.t
+++ b/t/node/upstream-ipv6.t
@@ -115,7 +115,7 @@ hello world
                         {
                             "weight": 100,
                             "priority": 0,
-                            "host": "::1",
+                            "host": "[::1]",
                             "port": 1980
                         }
                     ],
@@ -221,7 +221,7 @@ passed
 GET /hello
 --- error_code: 502
 --- error_log
-connect() to [::0.1.25.128]:80 failed
+failed to set server peer [::1:1980:80] err: invalid port while connecting to 
upstream
 
 
 
@@ -237,13 +237,13 @@ connect() to [::0.1.25.128]:80 failed
                         {
                             "weight": 100,
                             "priority": 0,
-                            "host": "::1",
+                            "host": "[::1]",
                             "port": 1980
                         },
                         {
                             "weight": 100,
                             "priority": 0,
-                            "host": "::1",
+                            "host": "[::1]",
                             "port": 1980
                         }
                     ],

Reply via email to