Skip to content
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
38 changes: 38 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -2926,6 +2926,7 @@ Nginx API for Lua
* [udpsock:settimeout](#udpsocksettimeout)
* [ngx.socket.stream](#ngxsocketstream)
* [ngx.socket.tcp](#ngxsockettcp)
* [tcpsock:bind](#tcpsockbind)
* [tcpsock:connect](#tcpsockconnect)
* [tcpsock:sslhandshake](#tcpsocksslhandshake)
* [tcpsock:send](#tcpsocksend)
Expand Down Expand Up @@ -6383,6 +6384,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)
* [sslhandshake](#tcpsocksslhandshake)
* [send](#tcpsocksend)
Expand Down Expand Up @@ -6419,6 +6421,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**

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
---------------
**syntax:** *ok, err = tcpsock:connect(host, port, options_table?)*
Expand Down
33 changes: 33 additions & 0 deletions doc/HttpLuaModule.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -5347,6 +5347,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:sslhandshake|sslhandshake]]
* [[#tcpsock:send|send]]
Expand Down Expand Up @@ -5381,6 +5382,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
75 changes: 72 additions & 3 deletions src/ngx_http_lua_socket_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,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 int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L);
Expand Down Expand Up @@ -138,7 +139,8 @@ static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c);
enum {
SOCKET_CTX_INDEX = 1,
SOCKET_TIMEOUT_INDEX = 2,
SOCKET_KEY_INDEX = 3
SOCKET_KEY_INDEX = 3,
SOCKET_BIND_INDEX = 4 /* only in upstream cosocket */
};


Expand Down Expand Up @@ -266,7 +268,10 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L)

/* {{{tcp object metatable */
lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key);
lua_createtable(L, 0 /* narr */, 11 /* nrec */);
lua_createtable(L, 0 /* narr */, 12 /* 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 @@ -388,7 +393,7 @@ ngx_http_lua_socket_tcp(lua_State *L)
| NGX_HTTP_LUA_CONTEXT_TIMER
| NGX_HTTP_LUA_CONTEXT_SSL_CERT);

lua_createtable(L, 3 /* narr */, 1 /* nrec */);
lua_createtable(L, 4 /* narr */, 1 /* nrec */);
lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
Expand All @@ -399,6 +404,61 @@ ngx_http_lua_socket_tcp(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 @@ -416,6 +476,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L)
ngx_int_t rc;
ngx_http_lua_loc_conf_t *llcf;
ngx_peer_connection_t *pc;
ngx_addr_t *local;
int timeout;
unsigned custom_pool;
int key_index;
Expand Down Expand Up @@ -574,6 +635,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_TIMEOUT_INDEX);
timeout = (ngx_int_t) lua_tointeger(L, -1);
lua_pop(L, 1);
Expand Down
71 changes: 71 additions & 0 deletions src/ngx_http_lua_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4097,4 +4097,75 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup)
}


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 @@ -245,6 +245,8 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r,
void ngx_http_lua_cleanup_free(ngx_http_request_t *r,
ngx_http_cleanup_pt *cleanup);

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


#define ngx_http_lua_check_if_abortable(L, ctx) \
if ((ctx)->no_abort) { \
Expand Down
Loading