From 1b905bcd5e70eaf0d124f298d0805148ab257ae1 Mon Sep 17 00:00:00 2001 From: gresham Date: Mon, 26 Oct 2026 12:21:50 +0800 Subject: [PATCH] bugfix: balancer.bind_to_local_addr() crashed the worker on an invalid address. ngx_parse_addr_port() returns NGX_DECLINED when the text is not an address; NGX_ERROR only means an allocation failed. The FFI function only checked for NGX_ERROR, so an invalid address such as "not-an-ip" was reported as success, and an ngx_addr_t whose sockaddr was never set (it comes from ngx_palloc()) was published to bp->local. The upstream connect then called ngx_inet_get_port() and bind() on that pointer, and the worker exited on signal 11. Treat anything but NGX_OK as an invalid address and keep the previous bp->local, as ngx_stream_lua_ffi_balancer_bind_to_local_addr() already does. Co-Authored-By: Claude Opus 5.5 --- src/ngx_http_lua_balancer.c | 6 +++++- t/138-balancer-upstream-bind.t | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index bd56d9da19..ff0b2a5dc6 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -1006,8 +1006,12 @@ ngx_http_lua_ffi_balancer_bind_to_local_addr(ngx_http_request_t *r, return NGX_ERROR; } + /* + * NGX_DECLINED means addr is not an address, and local->sockaddr is + * left unset then, so it must not be published to bp->local either. + */ rc = ngx_parse_addr_port(r->pool, local, (u_char *) addr, addr_len); - if (rc == NGX_ERROR) { + if (rc != NGX_OK) { p = ngx_snprintf(errbuf, *errbuf_size, "invalid addr %s", addr); *errbuf_size = p - errbuf; return NGX_ERROR; diff --git a/t/138-balancer-upstream-bind.t b/t/138-balancer-upstream-bind.t index 9f6d52c278..0b5a213466 100644 --- a/t/138-balancer-upstream-bind.t +++ b/t/138-balancer-upstream-bind.t @@ -173,3 +173,38 @@ GET /t 127.0.0.2 --- no_error_log [error] + + + +=== TEST 6: bind to an invalid address in balancer phase +--- no_http2 +--- http_config + lua_package_path "$TEST_NGINX_SERVER_ROOT/html/?.lua;;"; + + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local balancer = require "ngx.balancer" + assert(balancer.bind_to_local_addr("127.0.0.2")) + local ok, err = balancer.bind_to_local_addr("not-an-ip") + if not ok then + ngx.log(ngx.ERR, "failed to bind: ", err) + end + assert(balancer.set_current_peer("127.0.0.1", ngx.var.server_port)) + } + } +--- config + location = /t { + proxy_pass http://backend/back; + } + + location = /back { + echo $remote_addr; + } + +--- request +GET /t +--- response_body +127.0.0.2 +--- error_log +failed to bind: invalid addr not-an-ip