Skip to content

Commit b328ac1

Browse files
oyayazhuizhuhaomeng
authored andcommitted
fix: support tcp binding ip:port or ip of ipv4 or ipv6
1 parent d1d5b73 commit b328ac1

File tree

3 files changed

+95
-6
lines changed

3 files changed

+95
-6
lines changed

README.markdown

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7855,13 +7855,14 @@ See also [ngx.socket.udp](#ngxsocketudp).
78557855

78567856
tcpsock:bind
78577857
------------
7858-
**syntax:** *ok, err = tcpsock:bind(address)*
7858+
**syntax:** *ok, err = tcpsock:bind(address, port?)*
78597859

78607860
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua**
78617861

78627862
Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address.
78637863

7864-
Only IP addresses can be specified as the `address` argument.
7864+
IP addresses can be specified as the `address` argument.
7865+
The optional `port` argument is usually used in the transparent proxy.
78657866

78667867
Here is an example for connecting to a TCP server from the specified local IP address:
78677868

src/ngx_http_lua_socket_tcp.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,9 @@ ngx_http_lua_socket_tcp_bind(lua_State *L)
862862

863863
n = lua_gettop(L);
864864

865-
if (n != 2) {
866-
return luaL_error(L, "expecting 2 arguments, but got %d",
865+
/* Correct the parameter check and allow 2 or 3 parameters */
866+
if (n != 2 && n != 3) {
867+
return luaL_error(L, "expecting 2 or 3 arguments, but got %d",
867868
lua_gettop(L));
868869
}
869870

@@ -881,6 +882,26 @@ ngx_http_lua_socket_tcp_bind(lua_State *L)
881882

882883
luaL_checktype(L, 1, LUA_TTABLE);
883884

885+
port = 0;
886+
/* handle case: host:port */
887+
/* Hit the following parameter combination:
888+
* sock:bind("127.0.0.1", port) */
889+
if (n == 3) {
890+
if (!lua_isnumber(L, 3)) {
891+
lua_pushnil(L);
892+
lua_pushfstring(L, "expecting port to be a"
893+
"number but got type: %s", luaL_typename(L, 3));
894+
return 2;
895+
}
896+
897+
port = (int) lua_tointeger(L, 3);
898+
if (port < 0 || port > 65535) {
899+
lua_pushnil(L);
900+
lua_pushfstring(L, "bad port number: %d", port);
901+
return 2;
902+
}
903+
}
904+
884905
text = (u_char *) luaL_checklstring(L, 2, &len);
885906

886907
local = ngx_http_lua_parse_addr(L, text, len);
@@ -890,9 +911,11 @@ ngx_http_lua_socket_tcp_bind(lua_State *L)
890911
return 2;
891912
}
892913

914+
if (port > 0) {
915+
ngx_inet_set_port(local->sockaddr, (in_port_t) port);
916+
}
893917
/* TODO: we may reuse the userdata here */
894918
lua_rawseti(L, 1, SOCKET_BIND_INDEX);
895-
896919
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
897920
"lua tcp socket bind ip: %V", &local->name);
898921

@@ -1145,6 +1168,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
11451168

11461169
lua_rawgeti(L, 1, SOCKET_BIND_INDEX);
11471170
local = lua_touserdata(L, -1);
1171+
1172+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1173+
"lua tcp socket sock:connect ip: %V", &local->name);
1174+
11481175
lua_pop(L, 1);
11491176

11501177
if (local) {
@@ -3435,7 +3462,7 @@ ngx_http_lua_socket_tcp_handler(ngx_event_t *ev)
34353462
static ngx_int_t
34363463
ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc, void *data)
34373464
{
3438-
/* empty */
3465+
pc->type = SOCK_STREAM;
34393466
return NGX_OK;
34403467
}
34413468

t/168-tcp-socket-bind.t

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,64 @@ GET /t
365365
connected: 1
366366
--- no_error_log
367367
[error]
368+
369+
370+
371+
=== TEST 7: upstream sockets bind with ip port
372+
--- config
373+
server_tokens off;
374+
location /t {
375+
set $port $TEST_NGINX_SERVER_PORT;
376+
content_by_lua_block {
377+
local ip = "127.0.0.1"
378+
local port = ngx.var.port
379+
380+
local sock = ngx.socket.tcp()
381+
382+
local ok, err = sock:bind(ip, 12345)
383+
if not ok then
384+
ngx.say("failed to bind", err)
385+
return
386+
end
387+
388+
local ok, err = sock:connect("127.0.0.1", port)
389+
if not ok then
390+
ngx.say("failed to connect: ", err)
391+
return
392+
end
393+
394+
local ok, err = sock:setoption("reuseaddr", 1)
395+
if not ok then
396+
ngx.say("setoption reuseaddr failed: ", err)
397+
end
398+
399+
ngx.say("connected: ", ok)
400+
401+
local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n")
402+
if not bytes then
403+
ngx.say("failed to send request: ", err)
404+
return
405+
end
406+
407+
local reader = sock:receiveuntil("\r\n0\r\n\r\n")
408+
local data, err = reader()
409+
410+
if not data then
411+
ngx.say("failed to receive response body: ", err)
412+
return
413+
end
414+
sock:close()
415+
ngx.say(data)
416+
417+
}
418+
}
419+
420+
location /foo {
421+
echo bind: $remote_addr:$remote_port;
422+
}
423+
--- request
424+
GET /t
425+
--- response_body eval
426+
qr/bind:\s127\.0\.0\.1:12345|failed\s+to\s+connect:\s+address\s+already\s+in\s+use/
427+
--- error_log eval
428+
"lua tcp socket bind ip: 127.0.0.1"

0 commit comments

Comments
 (0)