Skip to content

feature: added new API bind tcpsock:bind. #2072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,4 @@ script:
- dig +short myip.opendns.com @resolver1.opendns.com || exit 0
- dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0
- dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0
- prove -I. -Itest-nginx/lib -r t
- prove -I. -Itest-nginx/lib -r t/
38 changes: 38 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3682,6 +3682,7 @@ Nginx API for Lua
* [udpsock:settimeout](#udpsocksettimeout)
* [ngx.socket.stream](#ngxsocketstream)
* [ngx.socket.tcp](#ngxsockettcp)
* [tcpsock:bind](#tcpsockbind)
* [tcpsock:connect](#tcpsockconnect)
* [tcpsock:setclientcert](#tcpsocksetclientcert)
* [tcpsock:sslhandshake](#tcpsocksslhandshake)
Expand Down Expand Up @@ -7654,6 +7655,7 @@ ngx.socket.tcp

Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object:

* [bind](#tcpsockbind)
* [connect](#tcpsockconnect)
* [setclientcert](#tcpsocksetclientcert)
* [sslhandshake](#tcpsocksslhandshake)
Expand Down Expand Up @@ -7693,6 +7695,42 @@ See also [ngx.socket.udp](#ngxsocketudp).

[Back to TOC](#nginx-api-for-lua)

tcpsock:bind
------------
**syntax:** *ok, err = tcpsock:bind(address)*

**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*.


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.

Only IP addresses can be specified as the `address` argument.

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

```nginx

location /test {
content_by_lua_block {
local sock = ngx.socket.tcp()
-- assume "192.168.1.10" is the local ip address
local ok, err = sock:bind("192.168.1.10")
if not ok then
ngx.say("failed to bind")
return
end
local ok, err = sock:connect("192.168.1.67", 80)
if not ok then
ngx.say("failed to connect server: ", err)
return
end
ngx.say("successfully connected!")
sock:close()
}
}
```

[Back to TOC](#nginx-api-for-lua)

tcpsock:connect
---------------

Expand Down
33 changes: 33 additions & 0 deletions doc/HttpLuaModule.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -6498,6 +6498,7 @@ This API function was first added to the <code>v0.10.1</code> release.

Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object:

* [[#tcpsock:bind|bind]]
* [[#tcpsock:connect|connect]]
* [[#tcpsock:setclientcert|setclientcert]]
* [[#tcpsock:sslhandshake|sslhandshake]]
Expand Down Expand Up @@ -6535,6 +6536,38 @@ This feature was first introduced in the <code>v0.5.0rc1</code> release.

See also [[#ngx.socket.udp|ngx.socket.udp]].

== tcpsock:bind ==
'''syntax:''' ''ok, err = tcpsock:bind(address)''

'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*''

Just like the standard [[HttpProxyModule#proxy_bind|proxy_bind]] directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address.

Only IP addresses can be specified as the <code>address</code> argument.

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

<geshi lang="nginx">
location /test {
content_by_lua_block {
local sock = ngx.socket.tcp()
-- assume "192.168.1.10" is the local ip address
local ok, err = sock:bind("192.168.1.10")
if not ok then
ngx.say("failed to bind")
return
end
local ok, err = sock:connect("192.168.1.67", 80)
if not ok then
ngx.say("failed to connect server: ", err)
return
end
ngx.say("successfully connected!")
sock:close()
}
}
</geshi>

== tcpsock:connect ==

'''syntax:''' ''ok, err = tcpsock:connect(host, port, options_table?)''
Expand Down
71 changes: 70 additions & 1 deletion src/ngx_http_lua_socket_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@


static int ngx_http_lua_socket_tcp(lua_State *L);
static int ngx_http_lua_socket_tcp_bind(lua_State *L);
static int ngx_http_lua_socket_tcp_connect(lua_State *L);
#if (NGX_HTTP_SSL)
static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c);
Expand Down Expand Up @@ -162,6 +163,7 @@ enum {
SOCKET_READ_TIMEOUT_INDEX = 5,
SOCKET_CLIENT_CERT_INDEX = 6 ,
SOCKET_CLIENT_PKEY_INDEX = 7 ,
SOCKET_BIND_INDEX = 8 /* only in upstream cosocket */
};


Expand Down Expand Up @@ -314,7 +316,10 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L)
/* {{{tcp object metatable */
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
tcp_socket_metatable_key));
lua_createtable(L, 0 /* narr */, 15 /* nrec */);
lua_createtable(L, 0 /* narr */, 16 /* nrec */);

lua_pushcfunction(L, ngx_http_lua_socket_tcp_bind);
lua_setfield(L, -2, "bind");

lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect);
lua_setfield(L, -2, "connect");
Expand Down Expand Up @@ -827,6 +832,61 @@ ngx_http_lua_socket_tcp_connect_helper(lua_State *L,
}


static int
ngx_http_lua_socket_tcp_bind(lua_State *L)
{
ngx_http_request_t *r;
ngx_http_lua_ctx_t *ctx;
int n;
u_char *text;
size_t len;
ngx_addr_t *local;

n = lua_gettop(L);

if (n != 2) {
return luaL_error(L, "expecting 2 arguments, but got %d",
lua_gettop(L));
}

r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request found");
}

ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return luaL_error(L, "no ctx found");
}

ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
| NGX_HTTP_LUA_CONTEXT_ACCESS
| NGX_HTTP_LUA_CONTEXT_CONTENT
| NGX_HTTP_LUA_CONTEXT_TIMER
| NGX_HTTP_LUA_CONTEXT_SSL_CERT);

luaL_checktype(L, 1, LUA_TTABLE);

text = (u_char *) luaL_checklstring(L, 2, &len);

local = ngx_http_lua_parse_addr(L, text, len);
if (local == NULL) {
lua_pushnil(L);
lua_pushfstring(L, "bad address");
return 2;
}

/* TODO: we may reuse the userdata here */
lua_rawseti(L, 1, SOCKET_BIND_INDEX);

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua tcp socket bind ip: %V", &local->name);

lua_pushboolean(L, 1);
return 1;
}


static int
ngx_http_lua_socket_tcp_connect(lua_State *L)
{
Expand All @@ -838,6 +898,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
size_t len;
ngx_http_lua_loc_conf_t *llcf;
ngx_peer_connection_t *pc;
ngx_addr_t *local;
int connect_timeout, send_timeout, read_timeout;
unsigned custom_pool;
int key_index;
Expand Down Expand Up @@ -1068,6 +1129,14 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)

dd("lua peer connection log: %p", pc->log);

lua_rawgeti(L, 1, SOCKET_BIND_INDEX);
local = lua_touserdata(L, -1);
lua_pop(L, 1);

if (local) {
u->peer.local = local;
}

lua_rawgeti(L, 1, SOCKET_CONNECT_TIMEOUT_INDEX);
lua_rawgeti(L, 1, SOCKET_SEND_TIMEOUT_INDEX);
lua_rawgeti(L, 1, SOCKET_READ_TIMEOUT_INDEX);
Expand Down
73 changes: 73 additions & 0 deletions src/ngx_http_lua_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4396,4 +4396,77 @@ ngx_http_lua_copy_escaped_header(ngx_http_request_t *r,
return NGX_OK;
}


ngx_addr_t *
ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len)
{
ngx_addr_t *addr;
size_t socklen;
in_addr_t inaddr;
ngx_uint_t family;
struct sockaddr_in *sin;
#if (NGX_HAVE_INET6)
struct in6_addr inaddr6;
struct sockaddr_in6 *sin6;

/*
* prevent MSVC8 warning:
* potentially uninitialized local variable 'inaddr6' used
*/
ngx_memzero(&inaddr6, sizeof(struct in6_addr));
#endif

inaddr = ngx_inet_addr(text, len);

if (inaddr != INADDR_NONE) {
family = AF_INET;
socklen = sizeof(struct sockaddr_in);

#if (NGX_HAVE_INET6)

} else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
family = AF_INET6;
socklen = sizeof(struct sockaddr_in6);
#endif

} else {
return NULL;
}

addr = lua_newuserdata(L, sizeof(ngx_addr_t) + socklen + len);
if (addr == NULL) {
luaL_error(L, "no memory");
return NULL;
}

addr->sockaddr = (struct sockaddr *) ((u_char *) addr + sizeof(ngx_addr_t));

ngx_memzero(addr->sockaddr, socklen);

addr->sockaddr->sa_family = (u_char) family;
addr->socklen = socklen;

switch (family) {

#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) addr->sockaddr;
ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
break;
#endif

default: /* AF_INET */
sin = (struct sockaddr_in *) addr->sockaddr;
sin->sin_addr.s_addr = inaddr;
break;
}

addr->name.data = (u_char *) addr->sockaddr + socklen;
addr->name.len = len;
ngx_memcpy(addr->name.data, text, len);

return addr;
}


/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
2 changes: 2 additions & 0 deletions src/ngx_http_lua_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ void ngx_http_lua_cleanup_free(ngx_http_request_t *r,
void ngx_http_lua_set_sa_restart(ngx_log_t *log);
#endif

ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len);

size_t ngx_http_lua_escape_log(u_char *dst, u_char *src, size_t size);


Expand Down
2 changes: 1 addition & 1 deletion t/062-count.t
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ worker: 4
--- request
GET /test
--- response_body
n = 15
n = 16
--- no_error_log
[error]

Expand Down
Loading