From f2a1329aa5c480dedc456b1980187f5bbdbc343e Mon Sep 17 00:00:00 2001 From: alonbg Date: Wed, 14 Sep 2016 15:51:32 +0300 Subject: [PATCH] fix udp bind and update tests --- src/ngx_stream_lua_socket_udp.c | 37 ++++++----- src/ngx_stream_lua_socket_udp.h | 1 + t/087-udp-socket.t | 6 +- t/141-tcp-socket-bind.t | 64 +++++++++++++++--- t/142-udp-socket-bind.t | 112 ++++++++++++++++++++++++++++---- 5 files changed, 183 insertions(+), 37 deletions(-) diff --git a/src/ngx_stream_lua_socket_udp.c b/src/ngx_stream_lua_socket_udp.c index 66469bdc..afb9c351 100644 --- a/src/ngx_stream_lua_socket_udp.c +++ b/src/ngx_stream_lua_socket_udp.c @@ -55,7 +55,7 @@ static void ngx_stream_lua_socket_udp_read_handler(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u); static void ngx_stream_lua_socket_udp_handle_success(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_stream_lua_udp_connect(lua_State *L, +static ngx_int_t ngx_stream_lua_udp_connect( ngx_stream_lua_udp_connection_t *uc); static int ngx_stream_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_stream_lua_socket_udp_resume(ngx_stream_session_t *s, @@ -224,6 +224,7 @@ ngx_stream_lua_socket_udp_setpeername(lua_State *L) ngx_stream_lua_udp_connection_t *uc; int timeout; ngx_stream_lua_co_ctx_t *coctx; + ngx_addr_t *local; ngx_stream_lua_socket_udp_upstream_t *u; @@ -333,6 +334,14 @@ ngx_stream_lua_socket_udp_setpeername(lua_State *L) dd("lua peer connection log: %p", &uc->log); + lua_rawgeti(L, 1, SOCKET_BIND_INDEX); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (local) { + uc->local = local; + } + lua_rawgeti(L, 1, SOCKET_TIMEOUT_INDEX); timeout = (ngx_int_t) lua_tointeger(L, -1); lua_pop(L, 1); @@ -705,7 +714,7 @@ ngx_stream_lua_socket_resolve_retval_handler(ngx_stream_session_t *s, return 2; } - rc = ngx_stream_lua_udp_connect(L, uc); + rc = ngx_stream_lua_udp_connect(uc); if (rc != NGX_OK) { u->socket_errno = ngx_socket_errno; @@ -1371,7 +1380,7 @@ ngx_stream_lua_socket_udp_handle_success(ngx_stream_session_t *s, static ngx_int_t -ngx_stream_lua_udp_connect(lua_State *L, ngx_stream_lua_udp_connection_t *uc) +ngx_stream_lua_udp_connect(ngx_stream_lua_udp_connection_t *uc) { int rc; ngx_int_t event; @@ -1447,19 +1456,17 @@ ngx_stream_lua_udp_connect(lua_State *L, ngx_stream_lua_udp_connection_t *uc) } #endif - lua_rawgeti(L, 1, SOCKET_BIND_INDEX); - local = lua_touserdata(L, -1); - lua_pop(L, 1); + local = uc->local; + if (local) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "udp socket bind"); - if (local && (uc->sockaddr->sa_family == AF_INET - || uc->sockaddr->sa_family == AF_INET6)) { - if (bind(uc->connection->fd, - local->sockaddr, local->socklen) != 0) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, - "bind(%V) failed", &local->name); - return NGX_ERROR; - } - } + if (bind(c->fd, local->sockaddr, local->socklen) != 0) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + "bind(%V) failed", &local->name); + + return NGX_ERROR; + } + } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); diff --git a/src/ngx_stream_lua_socket_udp.h b/src/ngx_stream_lua_socket_udp.h index 7055c4f6..bce0f322 100644 --- a/src/ngx_stream_lua_socket_udp.h +++ b/src/ngx_stream_lua_socket_udp.h @@ -26,6 +26,7 @@ typedef void (*ngx_stream_lua_socket_udp_upstream_handler_pt) typedef struct { ngx_connection_t *connection; + ngx_addr_t *local; struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t server; diff --git a/t/087-udp-socket.t b/t/087-udp-socket.t index 1b0b6a91..88e319e3 100644 --- a/t/087-udp-socket.t +++ b/t/087-udp-socket.t @@ -287,7 +287,6 @@ qr/content_by_lua_block\(nginx\.conf:\d+\):7: bad session/ === TEST 6: connect again immediately --- stream_server_config - content_by_lua_block { local sock = ngx.socket.udp() local port = $TEST_NGINX_MEMCACHED_PORT @@ -301,7 +300,7 @@ qr/content_by_lua_block\(nginx\.conf:\d+\):7: bad session/ ngx.say("connected: ", ok) ok, err = sock:setpeername("127.0.0.1", port) - if not ok then + if not ok then ngx.say("failed to connect: ", err) return end @@ -520,6 +519,8 @@ lua udp socket receive buffer size: 8192 === TEST 11: access the google DNS server (using domain names) --- stream_server_config lua_resolver $TEST_NGINX_RESOLVER ipv6=off; + #lua_resolver agentzh.org ipv6=off; + #lua_resolver 8.8.8.8 ipv6=off; content_by_lua_block { -- avoid flushing google in "check leak" testing mode: local counter = package.loaded.counter @@ -540,6 +541,7 @@ lua udp socket receive buffer size: 8192 udp:settimeout(2000) -- 2 sec local ok, err = udp:setpeername("google-public-dns-a.google.com", 53) + --local ok, err = udp:setpeername("127.0.1.1", 53) if not ok then ngx.say("failed to connect: ", err) return diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t index 56b714be..ce4abedb 100644 --- a/t/141-tcp-socket-bind.t +++ b/t/141-tcp-socket-bind.t @@ -6,13 +6,17 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 2); -my $local_ip = `ifconfig | grep -oE '([0-9]{1,3}\\.?){4}' | grep '\\.' | grep -v '127.0.0.1' | head -n 1`; +my $local_ip = `ifconfig | grep -oE 'addr:([0-9]{1,3}+\\.){3}[0-9]{1,3}' | sed -e 's/addr://' | grep -v '127.0.0.1' | head -n 1`; chomp $local_ip; +my $local_domain_server = `dig something | grep -oE ' ([0-9]{1,3}+\\.){3}[0-9]{1,3}'`; +chomp $local_domain_server; +$ENV{TEST_NGINX_LOCAL_DOMAIN_SERVER} ||= $local_domain_server; $ENV{TEST_NGINX_SERVER_IP} ||= $local_ip; $ENV{TEST_NGINX_NOT_EXIST_IP} ||= '8.8.8.8'; $ENV{TEST_NGINX_INVALID_IP} ||= '127.0.0.1:8899'; + no_long_string(); #no_diff(); #log_level 'warn'; @@ -25,7 +29,7 @@ __DATA__ === TEST 1: upstream sockets bind 127.0.0.1 --- stream_config server { - listen 2986; + listen 127.0.1.2:2986; content_by_lua_block { ngx.say(ngx.var.remote_addr) } @@ -42,7 +46,7 @@ server { return end - local ok, err = sock:connect("127.0.0.1", port) + local ok, err = sock:connect("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) return @@ -65,7 +69,7 @@ server { === TEST 2: upstream sockets bind non loopback ip --- stream_config server { - listen 2986; + listen 127.0.1.2:2986; content_by_lua_block { ngx.say(ngx.var.remote_addr) } @@ -82,7 +86,7 @@ server { return end - local ok, err = sock:connect("127.0.0.1", port) + local ok, err = sock:connect("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) return @@ -105,7 +109,7 @@ ip matched === TEST 3: upstream sockets bind not exist ip --- stream_config server { - listen 2986; + listen 127.0.1.2:2986; content_by_lua_block { ngx.say(ngx.var.remote_addr) } @@ -121,7 +125,7 @@ server { ngx.log(ngx.INFO, err) end - local ok, err = sock:connect("127.0.0.1", port) + local ok, err = sock:connect("127.0.1.2", port) if not ok then ngx.say(err) end @@ -139,7 +143,7 @@ cannot assign requested address === TEST 4: upstream sockets bind invalid ip --- stream_config server { - listen 2986; + listen 127.0.1.2:2986; content_by_lua_block { ngx.say(ngx.var.remote_addr) } @@ -155,7 +159,7 @@ server { ngx.say(err) end - local ok, err = sock:connect("127.0.0.1", port) + local ok, err = sock:connect("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) end @@ -173,3 +177,45 @@ bad address 127.0.0.1 --- no_error_log [error] + + +=== TEST 5: upstream sockets bind 127.0.0.1 and resolve peername +--- SKIP +--- stream_config +lua_resolver $TEST_NGINX_LOCAL_DOMAIN_SERVER ipv6=off; +server { + listen localhost:2986; + content_by_lua_block { + ngx.say(ngx.var.remote_addr) + } +} +--- stream_server_config + content_by_lua_block { + local ip = "127.0.0.1" + local port = 2986 + local sock = ngx.socket.tcp() + + local ok, err = sock:bind(ip) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:connect("localhost", port) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local line, err, part = sock:receive() + if line then + ngx.say(line) + else + ngx.log(ngx.ERR, err) + end + } + +--- stream_response +127.0.0.1 +--- no_error_log +[error] diff --git a/t/142-udp-socket-bind.t b/t/142-udp-socket-bind.t index 46f8f165..a005e57a 100644 --- a/t/142-udp-socket-bind.t +++ b/t/142-udp-socket-bind.t @@ -6,9 +6,12 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 4); -my $local_ip = `ifconfig | grep -oE '([0-9]{1,3}\\.?){4}' | grep '\\.' | grep -v '127.0.0.1' | head -n 1`; +my $local_ip = `ifconfig | grep -oE 'addr:([0-9]{1,3}+\\.){3}[0-9]{1,3}' | sed -e 's/addr://' | grep -v '127.0.0.1' | head -n 1`; chomp $local_ip; +my $local_domain_server = `dig something | grep -oE ' ([0-9]{1,3}+\\.){3}[0-9]{1,3}'`; +chomp $local_domain_server; +$ENV{TEST_NGINX_LOCAL_DOMAIN_SERVER} ||= $local_domain_server; $ENV{TEST_NGINX_SERVER_IP} ||= $local_ip; $ENV{TEST_NGINX_NOT_EXIST_IP} ||= '8.8.8.8'; $ENV{TEST_NGINX_INVALID_IP} ||= '127.0.0.1:8899'; @@ -25,7 +28,7 @@ __DATA__ === TEST 1: upstream sockets bind 127.0.0.1 --- stream_config server { - listen 127.0.0.1:2986 udp; + listen 127.0.1.2:2986 udp; content_by_lua_block { ngx.log(ngx.INFO, "udp bind address: " .. ngx.var.remote_addr) } @@ -42,7 +45,7 @@ server { return end - local ok, err = sock:setpeername("127.0.0.1", port) + local ok, err = sock:setpeername("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) return @@ -58,13 +61,13 @@ server { [error] --- error_log eval ["lua udp socket bind ip: 127.0.0.1", -"udp bind address: 127.0.0.1 while handling client connection, udp client: 127.0.0.1, server: 127.0.0.1:2986"] +"udp bind address: 127.0.0.1 while handling client connection, udp client: 127.0.0.1, server: 127.0.1.2:2986"] === TEST 2: upstream sockets bind non loopback ip --- stream_config server { - listen 127.0.0.1:2986 udp; + listen 127.0.1.2:2986 udp; content_by_lua_block { ngx.log(ngx.INFO, "udp bind address: " .. ngx.var.remote_addr) } @@ -81,7 +84,7 @@ server { return end - local ok, err = sock:setpeername("127.0.0.1", port) + local ok, err = sock:setpeername("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) return @@ -97,13 +100,13 @@ server { [error] --- error_log eval ["lua udp socket bind ip: $ENV{TEST_NGINX_SERVER_IP}", -"udp bind address: $ENV{TEST_NGINX_SERVER_IP} while handling client connection, udp client: $ENV{TEST_NGINX_SERVER_IP}, server: 127.0.0.1:2986"] +"udp bind address: $ENV{TEST_NGINX_SERVER_IP} while handling client connection, udp client: $ENV{TEST_NGINX_SERVER_IP}, server: 127.0.1.2:2986"] === TEST 3: upstream sockets bind not exist ip --- stream_config server { - listen 127.0.0.1:2986 udp; + listen 127.0.1.2:2986 udp; content_by_lua_block { ngx.log(ngx.INFO, "udp bind address: " .. ngx.var.remote_addr) } @@ -120,7 +123,7 @@ server { return end - local ok, err = sock:setpeername("127.0.0.1", port) + local ok, err = sock:setpeername("127.0.1.2", port) if not ok then ngx.log(ngx.INFO, err) return @@ -142,7 +145,7 @@ server { === TEST 4: upstream sockets bind invalid ip --- stream_config server { - listen 127.0.0.1:2986 udp; + listen 127.0.1.2:2986 udp; content_by_lua_block { ngx.log(ngx.INFO, "udp bind address from remote: " .. ngx.var.remote_addr) return @@ -159,7 +162,7 @@ server { ngx.log(ngx.INFO, err) end - local ok, err = sock:setpeername("127.0.0.1", port) + local ok, err = sock:setpeername("127.0.1.2", port) if not ok then ngx.log(ngx.ERR, err) return @@ -176,3 +179,90 @@ server { --- error_log eval ["bad address while handling client connection, client: 127.0.0.1", "udp bind address from remote: 127.0.0.1"] + + +=== TEST 5: upstream sockets bind 127.0.0.1 and resolve peername +--- SKIP +--- stream_config +lua_resolver $TEST_NGINX_LOCAL_DOMAIN_SERVER ipv6=off; +server { + listen localhost:2986 udp; + content_by_lua_block { + ngx.log(ngx.INFO, "udp bind address: " .. ngx.var.remote_addr) + } +} +--- stream_server_config + content_by_lua_block { + local ip = "127.0.0.1" + local port = 2986 + local sock = ngx.socket.udp() + + local ok, err = sock:bind(ip) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:setpeername("localhost", port) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:send("trigger") + if not ok then + ngx.log(ngx.ERR, err) + end + +} + +--- no_error_log +[error] +--- error_log eval +["lua udp socket bind ip: 127.0.0.1", +"udp bind address: 127.0.0.1 while handling client connection, udp client: 127.0.0.1, server: 127.0.0.1:2986"] + + +=== TEST 6: upstream sockets double bind 127.0.0.1 and resolve peername +--- SKIP +--- stream_config +#lua_resolver $TEST_NGINX_LOCAL_DOMAIN_SERVER ipv6=off; +server { + listen localhost:2986 udp; + content_by_lua_block { + ngx.log(ngx.INFO, "udp bind address: " .. ngx.var.remote_addr) + } +} +--- stream_server_config + content_by_lua_block { + local ip = "127.0.0.1" + local port = 2986 + local sock = ngx.socket.udp() + + local ok, err = sock:bind(ip) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:setpeername("localhost", port) + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:bind("$TEST_NGINX_SERVER_IP") + if not ok then + ngx.log(ngx.ERR, err) + return + end + + local ok, err = sock:setpeername("localhost", port) + if not ok then + ngx.log(ngx.ERR, err) + return + end +} + +--- no_error_log +[error]