diff --git a/ncat/Makefile.in b/ncat/Makefile.in index 6190937a0..86d1380ce 100644 --- a/ncat/Makefile.in +++ b/ncat/Makefile.in @@ -83,15 +83,19 @@ DATAFILES = certs/ca-bundle.crt endif ifneq ($(HAVE_LUA),) -LUA_SRCS = ncat_lua_exec.c ncat_lua.c ncat_lua_filters.c -LUA_OBJS = ncat_lua_exec.o ncat_lua.o ncat_lua_filters.o +LUA_SRCS = ncat_lua.c ncat_lua_exec.c ncat_lua_filters.c ncat_lua_connect.c +LUA_OBJS = ncat_lua.o ncat_lua_exec.o ncat_lua_filters.o ncat_lua_connect.o LUA_LIBS = @LIBLUA_LIBS@ -lm LUA_CFLAGS += -DHAVE_LUA=1 -I../liblua +# This is the result of lua_setup() pulling in recv/send routines, which +# in turn pull a few other files. +MORE_TEST_OBJS = http.o http_digest.o base64.o ncat_ssl.o ncat_connect.o else LUA_SRCS = LUA_OBJS = LUA_LIBS = LUA_CFLAGS = +MORE_TEST_OBJS = endif SRCS += $(LUA_SRCS) @@ -135,16 +139,16 @@ config.h: $(SHELL) ./config.status; \ fi -test/addrset: test/addrset.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS) +test/addrset: test/addrset.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(MORE_TEST_OBJS) $(LUA_OBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS) $(LIBS) -test/test-uri: test/test-uri.o base64.o http.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS) +test/test-uri: test/test-uri.o base64.o http.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(MORE_TEST_OBJS) $(LUA_OBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS) $(LIBS) -test/test-cmdline-split: test/test-cmdline-split.o ncat_posix.o ncat_core.o sys_wrap.o util.o $(LUA_OBJS) +test/test-cmdline-split: test/test-cmdline-split.o ncat_posix.o ncat_core.o sys_wrap.o util.o $(MORE_TEST_OBJS) $(LUA_OBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS) $(LIBS) -test/test-wildcard: test/test-wildcard.o ncat_core.o ncat_ssl.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS) +test/test-wildcard: test/test-wildcard.o ncat_core.o ncat_ssl.o sys_wrap.o util.o ncat_posix.o $(MORE_TEST_OBJS) $(LUA_OBJS) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS) $(LIBS) .PHONY: uninstall all clean distclean diff --git a/ncat/ncat_connect.c b/ncat/ncat_connect.c index 0289882c8..ec0e3648a 100644 --- a/ncat/ncat_connect.c +++ b/ncat/ncat_connect.c @@ -151,6 +151,11 @@ #define SHUT_WR SD_SEND #endif +#ifdef HAVE_LUA +#include "ncat_lua_filters.h" +#include "ncat_lua_connect.h" +#endif + struct conn_state { nsock_iod sock_nsi; nsock_iod stdin_nsi; @@ -169,7 +174,6 @@ static void connect_handler(nsock_pool nsp, nsock_event evt, void *data); static void post_connect(nsock_pool nsp, nsock_iod iod); static void read_stdin_handler(nsock_pool nsp, nsock_event evt, void *data); static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data); -static void write_socket_handler(nsock_pool nsp, nsock_event evt, void *data); static void idle_timer_handler(nsock_pool nsp, nsock_event evt, void *data); static void refresh_idle_timer(nsock_pool nsp); @@ -549,6 +553,10 @@ int ncat_connect(void) cs.sock_nsi = nsi_new(mypool, NULL); if (cs.sock_nsi == NULL) bye("Failed to create nsock_iod."); +#ifdef HAVE_LUA + if (o.script) + lua_nsock_save(mypool, cs.sock_nsi); +#endif if (nsi_set_hostname(cs.sock_nsi, o.target) == -1) bye("Failed to set hostname on iod."); @@ -706,6 +714,10 @@ int ncat_connect(void) /* Create IOD for nsp->stdin */ if ((cs.stdin_nsi = nsi_new2(mypool, 0, NULL)) == NULL) bye("Failed to create stdin nsiod."); +#ifdef HAVE_LUA + if (o.script) + lua_nsock_save(mypool, cs.sock_nsi); +#endif post_connect(mypool, cs.sock_nsi); } @@ -792,8 +804,14 @@ static void post_connect(nsock_pool nsp, nsock_iod iod) /* Start the initial reads. */ - if (!o.sendonly) - nsock_read(nsp, cs.sock_nsi, read_socket_handler, -1, NULL); + if (!o.sendonly) { +#ifdef HAVE_LUA + if (o.script) + lua_nsock_read(0); + else +#endif + nsock_read(nsp, cs.sock_nsi, read_socket_handler, -1, NULL); + } if (!o.recvonly) nsock_readbytes(nsp, cs.stdin_nsi, read_stdin_handler, -1, NULL, 0); @@ -845,7 +863,13 @@ static void read_stdin_handler(nsock_pool nsp, nsock_event evt, void *data) buf = tmp; } - nsock_write(nsp, cs.sock_nsi, write_socket_handler, -1, NULL, buf, nbytes); +#ifdef HAVE_LUA + if (o.script) + lua_nsock_write(nsp, cs.sock_nsi, buf, nbytes); + else +#endif + nsock_write(nsp, cs.sock_nsi, write_socket_handler, -1, NULL, buf, nbytes); + ncat_log_send(buf, nbytes); if (tmp) @@ -854,12 +878,11 @@ static void read_stdin_handler(nsock_pool nsp, nsock_event evt, void *data) refresh_idle_timer(nsp); } -static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data) +/* Handle nsock errors. */ +int check_nsock_error(nsock_pool nsp, nsock_event evt) { enum nse_status status = nse_status(evt); enum nse_type type = nse_type(evt); - char *buf; - int nbytes; ncat_assert(type == NSE_TYPE_READ); @@ -868,7 +891,7 @@ static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data) /* In --recv-only mode or non-TCP mode, exit after EOF on the socket. */ if (o.proto != IPPROTO_TCP || (o.proto == IPPROTO_TCP && o.recvonly)) nsock_loop_quit(nsp); - return; + return 1; } else if (status == NSE_STATUS_ERROR) { loguser("%s.\n", socket_strerror(nse_errorcode(evt))); exit(1); @@ -876,29 +899,46 @@ static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data) loguser("%s.\n", socket_strerror(ETIMEDOUT)); exit(1); } else if (status == NSE_STATUS_CANCELLED || status == NSE_STATUS_KILL) { - return; + return 1; } else { ncat_assert(status == NSE_STATUS_SUCCESS); } + return 0; +} - buf = nse_readbuf(evt, &nbytes); - +/* Handle some post-read activities. */ +void ncat_nsock_postread(nsock_pool nsp, nsock_event evt, const char *buf, int nbytes) +{ if (o.linedelay) ncat_delay_timer(o.linedelay); - if (o.telnet) - dotelnet(nsi_getsd(nse_iod(evt)), (unsigned char *) buf, nbytes); + if (nbytes > 0) { + if (o.telnet) + dotelnet(nsi_getsd(nse_iod(evt)), (unsigned char *) buf, nbytes); - /* Write socket data to stdout */ - Write(STDOUT_FILENO, buf, nbytes); - ncat_log_recv(buf, nbytes); - - nsock_readbytes(nsp, cs.sock_nsi, read_socket_handler, -1, NULL, 0); + /* Write socket data to stdout */ + Write(STDOUT_FILENO, buf, nbytes); + ncat_log_recv(buf, nbytes); + } refresh_idle_timer(nsp); } -static void write_socket_handler(nsock_pool nsp, nsock_event evt, void *data) +static void read_socket_handler(nsock_pool nsp, nsock_event evt, void *data) +{ + char *buf; + int nbytes; + + if (check_nsock_error(nsp, evt)) + return; + + buf = nse_readbuf(evt, &nbytes); + ncat_nsock_postread(nsp, evt, buf, nbytes); + + nsock_readbytes(nsp, cs.sock_nsi, read_socket_handler, -1, NULL, 0); +} + +void write_socket_handler(nsock_pool nsp, nsock_event evt, void *data) { enum nse_status status = nse_status(evt); enum nse_type type = nse_type(evt); diff --git a/ncat/ncat_connect.h b/ncat/ncat_connect.h index 67755a225..9fba68275 100644 --- a/ncat/ncat_connect.h +++ b/ncat/ncat_connect.h @@ -123,5 +123,13 @@ #include "nsock.h" +#ifdef HAVE_LUA +#include "ncat_lua.h" +#include "ncat_lua_connect.h" +#endif + /* handle nsock-powered connections */ extern int ncat_connect(void); +int check_nsock_error(nsock_pool nsp, nsock_event evt); +void ncat_nsock_postread(nsock_pool nsp, nsock_event evt, const char *buf, int nbytes); +void write_socket_handler(nsock_pool nsp, nsock_event evt, void *data); diff --git a/ncat/ncat_lua_filters.c b/ncat/ncat_lua_filters.c index f201894d9..93215086e 100644 --- a/ncat/ncat_lua_filters.c +++ b/ncat/ncat_lua_filters.c @@ -139,11 +139,17 @@ static void lua_create_supersocket() lua_newtable(filters_L); lua_pushstring(filters_L, "recv"); - lua_pushcfunction(filters_L, lua_do_nothing); + if (o.listen) + lua_pushcfunction(filters_L, lua_do_nothing); /* TODO */ + else + lua_pushcfunction(filters_L, lua_nsock_recv_raw); lua_settable(filters_L, -3); lua_pushstring(filters_L, "send"); - lua_pushcfunction(filters_L, lua_do_nothing); + if (o.listen) + lua_pushcfunction(filters_L, lua_do_nothing); + else + lua_pushcfunction(filters_L, lua_nsock_write_raw); lua_settable(filters_L, -3); lua_set_registry("socket"); @@ -229,3 +235,109 @@ void lua_run_filter(char *cmdexec) lua_report(filters_L, cmdexec, 1); lua_set_registry("socket"); } + +/* Try to find the connection in the global table named "connections" with fd + as the key. If it's not there, create it, find its topmost "super", set its + "fd" to the given struct ncat_lua_state and save it in connection_supers. + Leave the socket on the stack. If *fdn is NULL, we assume that fd=0 and + we're in connect mode. Also, if *created is not NULL, it is set to 1 if + the socket put on the stack was just created. */ +struct ncat_lua_state* get_connection(struct fdinfo *fdn, int *created) +{ + struct ncat_lua_state *ret; + int connections_key; + if (fdn == NULL) + connections_key = 0; + else + connections_key = fdn->fd; + /* Try to access connections[fd]. Leave connections[] on the stack. */ + lua_fetch_registry("connections"); + lua_pushinteger(filters_L, connections_key); + lua_gettable(filters_L, -2); + + if (lua_isnil(filters_L, -1)) { + + lua_pop(filters_L, 1); /* nil means we hadn't added the connection yet, pop it. */ + + /* Basically: connections[fd] = new_socket(socket) */ + lua_pushinteger(filters_L, connections_key); + lua_pushvalue(filters_L, make_socket_function_idx); + lua_pushvalue(filters_L, make_socket_function_idx); + lua_fetch_registry("socket"); + if (lua_pcall(filters_L, 2, 1, error_handler_idx) != LUA_OK) + lua_report(filters_L, "Error creating the socket", 1); + lua_pushvalue(filters_L, -1); /* Make a copy of the connection we created. */ + lua_insert(filters_L, -4); /* Move it below connection, 5 and original table. */ + lua_settable(filters_L, -3); + lua_pop(filters_L, 1); /* Get rid of connections[]. */ + + /* Make another copy of the table - we'll work on the current one + looking for the topmost super. */ + lua_pushvalue(filters_L, -1); + for(;;) { + lua_pushvalue(filters_L, -1); /* Copy the current table */ + lua_pushstring(filters_L, "super"); + lua_gettable(filters_L, -2); + lua_insert(filters_L, -2); /* Move the copy to the top, pop it */ + lua_pop(filters_L, 1); + if (lua_isnil(filters_L, -1)) { + lua_pop(filters_L, 1); /* Pop the nil */ + break; /* There's no super, we're at the top */ + } + lua_insert(filters_L, -2); /* Get rid of the old table */ + lua_pop(filters_L, 1); + } + + ret = (struct ncat_lua_state *) Calloc(1, sizeof(*ret)); + if (fdn != NULL) + ret->fdn = *fdn; + + /* Set the "lua_state" to a pointer to ret. */ + lua_pushlightuserdata(filters_L, ret); + lua_setfield(filters_L, -2, "lua_state"); + + lua_fetch_registry("connection_roots"); + lua_pushinteger(filters_L, connections_key); + lua_pushvalue(filters_L, -3); + lua_remove(filters_L, -4); + lua_settable(filters_L, -3); + lua_pop(filters_L, 1); + + if (created != NULL) + *created = 1; + } else { + lua_insert(filters_L, -2); /* Get rid of connections[]. */ + lua_pop(filters_L, 1); + + /* Get the struct ncat_lua_state from connection_roots[fd].lua_state. */ + lua_fetch_registry("connection_roots"); + lua_pushinteger(filters_L, connections_key); + lua_gettable(filters_L, -2); + lua_getfield(filters_L, -1, "lua_state"); + ret = (struct ncat_lua_state *) lua_touserdata(filters_L, -1); + lua_pop(filters_L, 3); /* Pop the userdata, the table and connection_roots. */ + + if (created != NULL) + *created = 0; + } + + return ret; +} + + +/* Read "lua_state" field from socket table available under stack index given + as the second argument. If after the call *ret is set to a non-negative + value, it must be returned. */ +struct ncat_lua_state* lua_fetch_userdata(lua_State *L, int idx, int *ret) +{ + struct ncat_lua_state *nls; + *ret = -1; + lua_getfield(L, idx, "lua_state"); + nls = (struct ncat_lua_state *) lua_touserdata(L, -1); + if (nls == NULL) { + lua_pushnil(L); + lua_pushstring(L, "Socket already closed"); + *ret = 2; + } + return nls; +} diff --git a/ncat/ncat_lua_filters.h b/ncat/ncat_lua_filters.h index 4af89811c..8c1ef76cb 100644 --- a/ncat/ncat_lua_filters.h +++ b/ncat/ncat_lua_filters.h @@ -126,6 +126,19 @@ struct ncat_lua_state { struct fdinfo fdn; + + /* Only used in connect mode: */ + int in_send; + + /* Needed for receiving */ + nsock_event evt; + /* 1 if the next read should be performed by nsock_readbytes, 0 if + nsock_read. */ + int readbytes; + + /* Needed for sending */ + nsock_pool nsp; + nsock_iod nsiod; }; void lua_fetch_registry(const char *key);