diff --git a/Makefile.in b/Makefile.in
index 7037bbad0..c60a427b7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -82,9 +82,9 @@ UNINSTALLZENMAP=@UNINSTALLZENMAP@
UNINSTALLNPING=@UNINSTALLNPING@
ifneq (@LIBLUA_LIBS@,)
-NSE_SRC=nse_main.cc nse_nsock.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc nse_bit.cc
-NSE_HDRS=nse_main.h nse_nsock.h nse_fs.h nse_nmaplib.h nse_debug.h nse_pcrelib.h nse_binlib.h nse_bit.h
-NSE_OBJS=nse_main.o nse_nsock.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_bit.o
+NSE_SRC=nse_main.cc nse_utility.cc nse_nsock.cc nse_dnet.cc nse_fs.cc nse_nmaplib.cc nse_debug.cc nse_pcrelib.cc nse_binlib.cc nse_bit.cc
+NSE_HDRS=nse_main.h nse_utility.h nse_nsock.h nse_dnet.h nse_fs.h nse_nmaplib.h nse_debug.h nse_pcrelib.h nse_binlib.h nse_bit.h
+NSE_OBJS=nse_main.o nse_utility.o nse_nsock.o nse_dnet.o nse_fs.o nse_nmaplib.o nse_debug.o nse_pcrelib.o nse_binlib.o nse_bit.o
ifneq (@OPENSSL_LIBS@,)
NSE_SRC+=nse_openssl.cc nse_ssl_cert.cc
NSE_HDRS+=nse_openssl.h nse_ssl_cert.h
diff --git a/mswin32/nmap.vcproj b/mswin32/nmap.vcproj
index cff117de3..b162ba511 100644
--- a/mswin32/nmap.vcproj
+++ b/mswin32/nmap.vcproj
@@ -278,6 +278,10 @@
RelativePath="..\nse_main.cc"
>
+
+
@@ -286,6 +290,10 @@
RelativePath="..\nse_nsock.cc"
>
+
+
@@ -479,6 +487,10 @@
RelativePath="..\nse_main.h"
>
+
+
@@ -487,6 +499,10 @@
RelativePath="..\nse_nsock.h"
>
+
+
diff --git a/nse_dnet.cc b/nse_dnet.cc
new file mode 100644
index 000000000..b39a12bc0
--- /dev/null
+++ b/nse_dnet.cc
@@ -0,0 +1,313 @@
+#include "nsock.h"
+#include "nmap_error.h"
+#include "NmapOps.h"
+#include "utils.h"
+#include "tcpip.h"
+#include "protocols.h"
+#include "libnetutil/netutil.h"
+
+#include "nse_main.h"
+#include "nse_utility.h"
+
+extern "C" {
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+}
+
+#include
+
+extern NmapOps o;
+
+/* Map of dnet userdata to ethernet device userdata */
+#define ETH_CACHE_DNET_ETH 0
+/* Map of ethernet device string identifier to ethernet device userdata */
+#define ETH_CACHE_DEVICE_ETH 1
+
+/* metatable entries in the registry */
+#define DNET_METATABLE "DNET_METATABLE"
+#define DNET_ETH_METATABLE "DNET_ETH_METATABLE"
+
+typedef struct nse_dnet_udata
+{
+ eth_t *eth;
+ int sock; /* raw ip socket */
+ int interface; /* integer reference in registry for interface string */
+} nse_dnet_udata;
+
+LUALIB_API int l_dnet_new (lua_State *L)
+{
+ nse_dnet_udata *udata;
+
+ udata = (nse_dnet_udata *) lua_newuserdata(L, sizeof(nse_dnet_udata));
+ luaL_getmetatable(L, DNET_METATABLE);
+ lua_setmetatable(L, -2);
+ udata->eth = NULL;
+ udata->sock = -1;
+ udata->interface = LUA_NOREF;
+
+ return 1;
+}
+
+LUALIB_API int l_dnet_get_interface_link (lua_State *L)
+{
+ struct interface_info *ii = getInterfaceByName(luaL_checkstring(L, 1));
+
+ if (ii == NULL)
+ return luaL_argerror(L, 1, "bad interface");
+
+ switch (ii->device_type)
+ {
+ case devt_ethernet:
+ lua_pushliteral(L, "ethernet");
+ return 1;
+ case devt_loopback:
+ lua_pushliteral(L, "loopback");
+ return 1;
+ case devt_p2p:
+ lua_pushliteral(L, "p2p");
+ return 1;
+ case devt_other:
+ default:
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+static int close_eth (lua_State *L)
+{
+ eth_t **eth = (eth_t **) luaL_checkudata(L, 1, DNET_ETH_METATABLE);
+ assert(*eth != NULL);
+ eth_close(*eth);
+ *eth = NULL;
+ return success(L);
+}
+
+static eth_t *open_eth_cached (lua_State *L, int dnet_index, const char *device)
+{
+ eth_t **eth;
+
+ lua_rawgeti(L, LUA_ENVIRONINDEX, ETH_CACHE_DNET_ETH);
+ lua_rawgeti(L, LUA_ENVIRONINDEX, ETH_CACHE_DEVICE_ETH);
+ lua_getfield(L, -1, device);
+ if (!lua_isuserdata(L, -1))
+ {
+ eth = (eth_t **) lua_newuserdata(L, sizeof(eth_t *));
+ *eth = eth_open(device);
+ if (*eth == NULL)
+ luaL_error(L, "unable to open dnet on ethernet interface %s", device);
+ luaL_getmetatable(L, DNET_ETH_METATABLE);
+ lua_setmetatable(L, -2);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -4, device);
+ lua_replace(L, -2); /* replace nil */
+ }
+ eth = (eth_t **) lua_touserdata(L, -1);
+
+ lua_pushvalue(L, dnet_index);
+ lua_pushvalue(L, -2); /* eth_t userdata */
+ lua_rawset(L, -5); /* add to ETH_CACHE_DNET_ETH */
+ lua_pop(L, 3); /* ETH_CACHE_DNET_ETH, ETH_CACHE_DEVICE_ETH, eth_t userdata */
+
+ return *eth;
+}
+
+static int ethernet_open (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+ const char *interface_name = luaL_checkstring(L, 2);
+ struct interface_info *ii = getInterfaceByName(interface_name);
+
+ if (ii == NULL || ii->device_type != devt_ethernet)
+ return luaL_argerror(L, 2, "device is not valid ethernet interface");
+
+ udata->eth = open_eth_cached(L, 1, interface_name);
+ lua_pushvalue(L, 2);
+ udata->interface = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ return success(L);
+}
+
+static int ethernet_close (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+
+ udata->eth = NULL;
+
+ lua_rawgeti(L, LUA_ENVIRONINDEX, ETH_CACHE_DNET_ETH);
+ lua_pushvalue(L, 1);
+ lua_pushnil(L);
+ lua_rawset(L, -3);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, udata->interface);
+ udata->interface = LUA_NOREF;
+
+ return success(L);
+}
+
+static int ethernet_send (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+ if (udata->eth == NULL)
+ return luaL_error(L, "dnet ethernet interface is not open");
+ eth_send(udata->eth, luaL_checkstring(L, 2), lua_objlen(L, 2));
+ return success(L);
+}
+
+static int ip_open (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+ udata->sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (udata->sock == -1)
+ return luaL_error(L, "failed to open raw socket: %s (errno %d)",
+ socket_strerror(socket_errno()), socket_errno());
+ broadcast_socket(udata->sock);
+#ifndef WIN32
+ sethdrinclude(udata->sock);
+#endif
+ return success(L);
+}
+
+static int ip_close (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+ if (udata->sock == -1)
+ return safe_error(L, "raw socket already closed");
+ close(udata->sock);
+ udata->sock = -1;
+ return success(L);
+}
+
+static int ip_send (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+ const char *packet = luaL_checkstring(L, 2);
+
+ int ret;
+
+ if (udata->sock == -1)
+ return luaL_error(L, "raw socket not open to send");
+
+ if (lua_objlen(L, 2) < sizeof(struct ip))
+ return luaL_error(L, "ip packet too short");
+
+ if (o.sendpref & PACKET_SEND_ETH)
+ {
+ struct route_nfo route;
+ struct sockaddr_storage srcss, dstss, *nexthop;
+ struct sockaddr_in *srcsin = (struct sockaddr_in *) &srcss;
+ struct sockaddr_in *dstsin = (struct sockaddr_in *) &dstss;
+ struct ip *ip = (struct ip *) packet;
+ u8 dstmac[6];
+ eth_nfo eth;
+
+ /* build sockaddr for target from user packet and determine route */
+ memset(&dstss, 0, sizeof(dstss));
+ dstsin->sin_family = AF_INET;
+ dstsin->sin_addr.s_addr = ip->ip_dst.s_addr;
+
+ if (!nmap_route_dst(&dstss, &route))
+ goto usesock;
+
+ if (route.ii.device_type != devt_ethernet)
+ goto usesock;
+
+ /* above we fallback to using the raw socket if we can't find an (ethernet)
+ * route to the host. From here on out it's ethernet all the way.
+ */
+
+ /* build sockaddr for source from user packet to determine next hop mac */
+ memset(&srcss, 0, sizeof(srcss));
+ srcsin->sin_family = AF_INET;
+ srcsin->sin_addr.s_addr = ip->ip_src.s_addr;
+
+ if (route.direct_connect)
+ nexthop = &dstss;
+ else
+ nexthop = &route.nexthop;
+
+ if (!getNextHopMAC(route.ii.devfullname, route.ii.mac, &srcss, nexthop, dstmac))
+ return luaL_error(L, "failed to determine next hop MAC address");
+
+ /* Use cached ethernet device, and use udata's eth and interface to keep
+ * track of if we're reusing the same device from the previous packet, and
+ * close the cached device if not.
+ */
+ memset(ð, 0, sizeof(eth));
+ memcpy(eth.srcmac, route.ii.mac, sizeof(eth.srcmac));
+ memcpy(eth.dstmac, dstmac, sizeof(eth.dstmac));
+
+ /* close any current ethernet associated with this userdata */
+ lua_pushcfunction(L, ethernet_close);
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 0);
+
+ udata->eth = eth.ethsd = open_eth_cached(L, 1, route.ii.devname);
+ lua_pushstring(L, route.ii.devname);
+ udata->interface = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ ret = send_ip_packet(udata->sock, ð, (u8 *) packet, lua_objlen(L, 2));
+ } else {
+usesock:
+#ifdef WIN32
+ if (strlen(dev) > 0)
+ win32_warn_raw_sockets(dev);
+#endif
+ ret = send_ip_packet(udata->sock, NULL, (u8 *) packet, lua_objlen(L, 2));
+ }
+ if (ret == -1)
+ return luaL_error(L, "error while sending: %s (errno %d)",
+ socket_strerror(socket_errno()), socket_errno());
+
+ return success(L);
+}
+
+static int gc (lua_State *L)
+{
+ nse_dnet_udata *udata = (nse_dnet_udata *) luaL_checkudata(L, 1, DNET_METATABLE);
+
+ lua_pushcfunction(L, ip_close);
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 0);
+ lua_pushcfunction(L, ethernet_close);
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 0);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, udata->interface);
+ return 0;
+}
+
+LUALIB_API int luaopen_dnet (lua_State *L)
+{
+ static const luaL_reg l_dnet[] = {
+ {"ethernet_open", ethernet_open},
+ {"ethernet_close", ethernet_close},
+ {"ethernet_send", ethernet_send},
+ {"ip_open", ip_open},
+ {"ip_close", ip_close},
+ {"ip_send", ip_send},
+ {NULL, NULL}
+ };
+
+ lua_createtable(L, 2, 0);
+ lua_replace(L, LUA_ENVIRONINDEX);
+ weak_table(L, 0, 0, "k"); /* dnet udata weak, eth device strong */
+ lua_rawseti(L, LUA_ENVIRONINDEX, ETH_CACHE_DNET_ETH);
+ weak_table(L, 0, 0, "v"); /* eth_device weak */
+ lua_rawseti(L, LUA_ENVIRONINDEX, ETH_CACHE_DEVICE_ETH);
+
+ luaL_newmetatable(L, DNET_METATABLE);
+ lua_createtable(L, 0, 5);
+ luaL_register(L, NULL, l_dnet);
+ lua_setfield(L, -2, "__index");
+ lua_newtable(L);
+ lua_setfield(L, -2, "__metatable");
+ lua_pushcfunction(L, gc);
+ lua_setfield(L, -2, "__gc");
+
+ luaL_newmetatable(L, DNET_ETH_METATABLE);
+ lua_pushcfunction(L, close_eth);
+ lua_setfield(L, -2, "__gc");
+
+ return 0;
+}
diff --git a/nse_dnet.h b/nse_dnet.h
new file mode 100644
index 000000000..296f8db5e
--- /dev/null
+++ b/nse_dnet.h
@@ -0,0 +1,8 @@
+#ifndef NMAP_LUA_DNET_H
+#define NMAP_LUA_DNET_H
+
+LUALIB_API int l_dnet_new (lua_State *);
+LUALIB_API int l_dnet_get_interface_link (lua_State *);
+LUALIB_API int luaopen_dnet (lua_State *L);
+
+#endif
diff --git a/nse_main.cc b/nse_main.cc
index 8f3c3398b..e280e654e 100644
--- a/nse_main.cc
+++ b/nse_main.cc
@@ -1,15 +1,3 @@
-
-#include "nse_main.h"
-
-#include "nse_fs.h"
-#include "nse_nsock.h"
-#include "nse_nmaplib.h"
-#include "nse_bit.h"
-#include "nse_binlib.h"
-#include "nse_pcrelib.h"
-#include "nse_openssl.h"
-#include "nse_debug.h"
-
#include "nmap.h"
#include "nmap_error.h"
#include "portlist.h"
@@ -19,6 +7,17 @@
#include "Target.h"
#include "nmap_tty.h"
+#include "nse_main.h"
+#include "nse_utility.h"
+#include "nse_fs.h"
+#include "nse_nsock.h"
+#include "nse_nmaplib.h"
+#include "nse_bit.h"
+#include "nse_binlib.h"
+#include "nse_pcrelib.h"
+#include "nse_openssl.h"
+#include "nse_debug.h"
+
#define NSE_MAIN "NSE_MAIN" /* the main function */
#define NSE_TRACEBACK "NSE_TRACEBACK"
@@ -130,7 +129,8 @@ static int host_set_output (lua_State *L)
static int port_set_output (lua_State *L)
{
- Port port, *p;
+ Port *p;
+ Port port;
ScriptResult sr;
Target *target = get_target(L, 1);
p = get_port(L, target, &port, 2);
@@ -406,6 +406,9 @@ static int run_main (lua_State *L)
return 0;
}
+/* Lua 5.2 compatibility macro */
+#define lua_yieldk(L,n,ctx,k) lua_yield(L,n)
+
/* int nse_yield (lua_State *L) [-?, +?, e]
*
* This function will yield the running thread back to NSE, even across script
@@ -413,12 +416,12 @@ static int run_main (lua_State *L)
* correct and only way to call is as a tail call:
* return nse_yield(L);
*/
-int nse_yield (lua_State *L)
+int nse_yield (lua_State *L, int ctx, lua_CFunction k)
{
lua_getfield(L, LUA_REGISTRYINDEX, NSE_YIELD);
lua_pushthread(L);
lua_call(L, 1, 1); /* returns NSE_YIELD_VALUE */
- return lua_yield(L, 1); /* yield with NSE_YIELD_VALUE */
+ return lua_yieldk(L, 1, ctx, k); /* yield with NSE_YIELD_VALUE */
}
/* void nse_restore (lua_State *L, int number) [-, -, e]
@@ -527,7 +530,14 @@ void open_nse (void)
fatal("%s: failed to open a Lua state!", SCRIPT_ENGINE);
lua_atpanic(L_NSE, panic);
- if (lua_cpcall(L_NSE, init_main, (void *) &o.chosenScripts) != 0)
+#if 0
+ /* Lua 5.2 */
+ lua_pushcfunction(L_NSE, init_main);
+ lua_pushlightuserdata(L_NSE, &o.chosenScripts);
+ if (lua_pcall(L_NSE, 1, 0, 0))
+#else
+ if (lua_cpcall(L_NSE, init_main, &o.chosenScripts))
+#endif
fatal("%s: failed to initialize the script engine:\n%s\n", SCRIPT_ENGINE,
lua_tostring(L_NSE, -1));
}
@@ -540,7 +550,14 @@ void script_scan (std::vector &targets, stype scantype)
assert(L_NSE != NULL);
lua_settop(L_NSE, 0); /* clear the stack */
- if (lua_cpcall(L_NSE, run_main, (void *) &targets) != 0)
+#if 0
+ /* Lua 5.2 */
+ lua_pushcfunction(L_NSE, run_main);
+ lua_pushlightuserdata(L_NSE, &targets);
+ if (lua_pcall(L_NSE, 1, 0, 0))
+#else
+ if (lua_cpcall(L_NSE, run_main, &targets))
+#endif
error("%s: Script Engine Scan Aborted.\nAn error was thrown by the "
"engine: %s", SCRIPT_ENGINE, lua_tostring(L_NSE, -1));
}
diff --git a/nse_main.h b/nse_main.h
index f74c13b0a..04541f694 100644
--- a/nse_main.h
+++ b/nse_main.h
@@ -9,8 +9,8 @@
extern "C" {
#include "lua.h"
- #include "lualib.h"
#include "lauxlib.h"
+ #include "lualib.h"
}
#include "nmap.h"
@@ -38,7 +38,7 @@ class Target;
/* API */
-int nse_yield (lua_State *);
+int nse_yield (lua_State *, int, lua_CFunction);
void nse_restore (lua_State *, int);
void nse_destructor (lua_State *, char);
void nse_base (lua_State *);
diff --git a/nse_nmaplib.cc b/nse_nmaplib.cc
index bbfa96d55..34cb7c867 100644
--- a/nse_nmaplib.cc
+++ b/nse_nmaplib.cc
@@ -2,6 +2,7 @@
extern "C" {
#include "lua.h"
#include "lauxlib.h"
+ #include "lualib.h"
}
#include
@@ -19,37 +20,15 @@ extern "C" {
#include "protocols.h"
#include "nse_nmaplib.h"
+#include "nse_utility.h"
#include "nse_nsock.h"
+#include "nse_dnet.h"
extern NmapOps o;
static const char *NSE_PROTOCOL_OP[] = {"tcp", "udp", "sctp", NULL};
static const int NSE_PROTOCOL[] = {IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP};
-static void setsfield (lua_State *L, int idx, const char *field, const char *what)
-{
- lua_pushvalue(L, idx);
- lua_pushstring(L, what); /* what can be NULL */
- lua_setfield(L, -2, field);
- lua_pop(L, 1);
-}
-
-static void setnfield (lua_State *L, int idx, const char *field, lua_Number n)
-{
- lua_pushvalue(L, idx);
- lua_pushnumber(L, n);
- lua_setfield(L, -2, field);
- lua_pop(L, 1);
-}
-
-static void setbfield (lua_State *L, int idx, const char *field, int b)
-{
- lua_pushvalue(L, idx);
- lua_pushboolean(L, b);
- lua_setfield(L, -2, field);
- lua_pop(L, 1);
-}
-
void set_version (lua_State *L, const struct serviceDeductions *sd)
{
setsfield(L, -1, "name", sd->name);
@@ -245,7 +224,7 @@ static int aux_mutex (lua_State *L)
}
lua_pushthread(L);
lua_rawseti(L, lua_upvalueindex(1), lua_objlen(L, lua_upvalueindex(1))+1);
- return nse_yield(L);
+ return nse_yield(L, 0, NULL);
case DONE:
lua_pushthread(L);
if (!lua_equal(L, -1, lua_upvalueindex(2)))
@@ -341,7 +320,7 @@ static int aux_condvar (lua_State *L)
case WAIT:
lua_pushthread(L);
lua_rawseti(L, lua_upvalueindex(1), lua_objlen(L, lua_upvalueindex(1))+1);
- return nse_yield(L);
+ return nse_yield(L, 0, NULL);
case SIGNAL:
n = lua_objlen(L, lua_upvalueindex(1));
break;
@@ -398,56 +377,6 @@ static int l_condvar (lua_State *L)
return 1; // condition variable closure
}
-Target *get_target (lua_State *L, int index)
-{
- int top = lua_gettop(L);
- Target *target;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "targetname");
- lua_getfield(L, index, "ip");
- if (!(lua_isstring(L, -2) || lua_isstring(L, -1)))
- luaL_error(L, "host table does not have a 'ip' or 'targetname' field");
- if (lua_isstring(L, -2)) /* targetname */
- {
- nse_gettarget(L, -2); /* use targetname */
- if (lua_islightuserdata(L, -1))
- goto done;
- else
- lua_pop(L, 1);
- }
- if (lua_isstring(L, -1)) /* ip */
- nse_gettarget(L, -1); /* use ip */
- if (!lua_islightuserdata(L, -1))
- luaL_argerror(L, 1, "host is not being processed right now");
-done:
- target = (Target *) lua_touserdata(L, -1);
- lua_settop(L, top); /* reset stack */
- return target;
-}
-
-Port *get_port (lua_State *L, Target *target, Port *port, int index)
-{
- Port *p = NULL;
- int portno, protocol;
- luaL_checktype(L, index, LUA_TTABLE);
- lua_getfield(L, index, "number");
- if (!lua_isnumber(L, -1))
- luaL_error(L, "port 'number' field must be a number");
- lua_getfield(L, index, "protocol");
- if (!lua_isstring(L, -1))
- luaL_error(L, "port 'protocol' field must be a string");
- portno = (int) lua_tointeger(L, -2);
- protocol = strcmp(lua_tostring(L, -1), "tcp") == 0 ? IPPROTO_TCP :
- strcmp(lua_tostring(L, -1), "udp") == 0 ? IPPROTO_UDP :
- strcmp(lua_tostring(L, -1), "sctp") == 0 ? IPPROTO_SCTP :
- luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\"");
- while ((p = target->ports.nextPort(p, port, protocol, PORT_UNKNOWN)) != NULL)
- if (p->portno == portno)
- break;
- lua_pop(L, 2);
- return p;
-}
-
/* Generates an array of port data for the given host and leaves it on
* the top of the stack
*/
@@ -457,7 +386,8 @@ static int l_get_ports (lua_State *L)
"open|filtered", "closed|filtered", NULL};
static const int states[] = {PORT_OPEN, PORT_FILTERED, PORT_UNFILTERED,
PORT_CLOSED, PORT_OPENFILTERED, PORT_CLOSEDFILTERED};
- Port *p = NULL, port;
+ Port *p = NULL;
+ Port port; /* dummy Port for nextPort */
Target *target = get_target(L, 1);
int protocol = NSE_PROTOCOL[luaL_checkoption(L, 3, NULL, NSE_PROTOCOL_OP)];
int state = states[luaL_checkoption(L, 4, NULL, state_op)];
@@ -487,7 +417,8 @@ static int l_get_ports (lua_State *L)
static int l_get_port_state (lua_State *L)
{
Target *target;
- Port port, *p;
+ Port *p;
+ Port port; /* dummy Port */
target = get_target(L, 1);
p = get_port(L, target, &port, 2);
if (p == NULL)
@@ -522,7 +453,8 @@ static int l_set_port_state (lua_State *L)
static const int opstate[] = {PORT_OPEN, PORT_CLOSED};
static const char *op[] = {"open", "closed", NULL};
Target *target;
- Port port, *p;
+ Port *p;
+ Port port;
target = get_target(L, 1);
if ((p = get_port(L, target, &port, 2)) != NULL)
{
@@ -561,7 +493,8 @@ static int l_set_port_version (lua_State *L)
"incomplete"
};
Target *target;
- Port port, *p;
+ Port *p;
+ Port port;
enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE;
enum serviceprobestate probestate =
opversion[luaL_checkoption(L, 3, "hardmatched", ops)];
@@ -839,19 +772,11 @@ int luaopen_nmap (lua_State *L)
lua_settop(L, 0); // clear stack
luaL_register(L, "nmap", nmaplib);
- lua_newtable(L);
- lua_createtable(L, 0, 1);
- lua_pushliteral(L, "v");
- lua_setfield(L, -2, "__mode");
- lua_setmetatable(L, -2); // Allow closures to be collected (see l_mutex)
+ weak_table(L, 0, 0, "v"); /* allow closures to be collected (see l_mutex) */
lua_pushcclosure(L, l_mutex, 1); /* mutex function */
lua_setfield(L, -2, "mutex");
- lua_newtable(L);
- lua_createtable(L, 0, 1);
- lua_pushliteral(L, "v");
- lua_setfield(L, -2, "__mode");
- lua_setmetatable(L, -2); // Allow closures to be collected (see l_condvar)
+ weak_table(L, 0, 0, "v"); /* allow closures to be collected (see l_condvar) */
lua_pushcclosure(L, l_condvar, 1); // condvar function
lua_setfield(L, -2, "condvar");
@@ -862,6 +787,10 @@ int luaopen_nmap (lua_State *L)
lua_pushliteral(L, "nsock");
lua_call(L, 1, 0);
+ lua_pushcclosure(L, luaopen_dnet, 0);
+ lua_pushliteral(L, "dnet");
+ lua_call(L, 1, 0);
+
lua_settop(L, 1); // just nmap lib on stack
return 1;
diff --git a/nse_nsock.cc b/nse_nsock.cc
index 415b91c1e..8d58801b9 100644
--- a/nse_nsock.cc
+++ b/nse_nsock.cc
@@ -1,20 +1,3 @@
-
-extern "C"
-{
-#include "lua.h"
-#include "lauxlib.h"
-}
-
-#include
-#include
-#include
-#include
-#include
-
-#include "nse_nsock.h"
-#include "nse_main.h"
-#include "nse_ssl_cert.h"
-
#include "nsock.h"
#include "nmap_error.h"
#include "NmapOps.h"
@@ -23,187 +6,100 @@ extern "C"
#include "protocols.h"
#include "libnetutil/netutil.h"
+#include "nse_nsock.h"
+#include "nse_main.h"
+#include "nse_utility.h"
+#include "nse_ssl_cert.h"
+
#if HAVE_OPENSSL
/* See the comments in service_scan.cc for the reason for _WINSOCKAPI_. */
# define _WINSOCKAPI_
# include
#endif
-#define NSOCK_WRAPPER "NSOCK WRAPPER"
-#define NSOCK_WRAPPER_SUCCESS 0
-#define NSOCK_WRAPPER_ERROR 2
+#include
+#include
+#include
-#define NSOCK_WRAPPER_BUFFER_OK 1
-#define NSOCK_WRAPPER_BUFFER_MOREREAD 2
+#include
+#include
-#define FROM 1
-#define TO 2
+#define NMAP_NSOCK_SOCKET "NMAP_NSOCK_SOCKET"
+#define NMAP_NSOCK_PCAP_SOCKET "NMAP_NSOCK_PCAP_SOCKET"
#define DEFAULT_TIMEOUT 30000
+/* Integer keys in Nsock function environments */
+#define THREAD_SOCKETS 1 /* */
+#define CONNECT_WAITING 2 /* Threads waiting to lock */
+#define KEY_PCAP 3 /* keys to pcap sockets */
+
+/* Integer keys in the Nsock userdata environments */
+#define THREAD_I 1 /* The thread that yielded */
+#define BUFFER_I 2 /* Location of Userdata Buffer */
+
extern NmapOps o;
-static int l_nsock_loop(lua_State * L);
-
-static int l_nsock_bind(lua_State * L);
-
-static int l_nsock_connect(lua_State * L);
-
-static int l_nsock_send(lua_State * L);
-
-static int l_nsock_receive(lua_State * L);
-
-static int l_nsock_receive_lines(lua_State * L);
-
-static int l_nsock_receive_bytes(lua_State * L);
-
-static int l_nsock_get_info(lua_State * L);
-
-static int l_nsock_gc(lua_State * L);
-
-static int l_nsock_close(lua_State * L);
-
-static int l_nsock_set_timeout(lua_State * L);
-
-static int l_nsock_receive_buf(lua_State * L);
-
-static int l_nsock_pcap_open(lua_State * L);
-
-static int l_nsock_pcap_close(lua_State * L);
-
-static int l_nsock_pcap_register(lua_State * L);
-
-static int l_nsock_pcap_receive(lua_State * L);
-
-void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *yield);
-
-void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *yield);
-
-void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *yield);
-
-void l_nsock_receive_buf_handler(nsock_pool nsp, nsock_event nse, void *yield);
-
-int l_nsock_check_buf(lua_State * L);
-
-int l_nsock_checkstatus(lua_State * L, nsock_event nse);
-
-void l_nsock_trace(nsock_iod nsiod, const char *message, int direction);
-
-static void l_dnet_open(lua_State * L); /* open dnet metatable */
-
-const char *inet_ntop_both(int af, const void *v_addr, char *ipstring);
-
-unsigned short inet_port_both(int af, const void *v_addr);
-
-static nsock_pool nsp;
-
-/*
- * Structure with nsock pcap descriptor.
- * shared between many lua threads
- */
-struct ncap_socket
+typedef struct nse_nsock_udata
{
- nsock_iod nsiod; /* nsock pcap desc */
- int references; /* how many lua threads use
- * this */
- char *key; /* (free) zero-terminated key
- * used in map to * address
- * this structure. */
-};
-
-struct nsock_yield
-{
- lua_State *thread; /* thread to resume */
- struct l_nsock_udata *udata; /* self reference */
-};
-
-struct ncap_request
-{
- int suspended; /* is the thread suspended?
- * (lua_yield) */
- struct nsock_yield *yield;
- nsock_event_id nseid; /* nse for this specific
- * lua_State */
- struct timeval end_time;
- char *key; /* (free) zero-terminated key
- * used in map to * address
- * this structure (hexified
- * 'test') */
-
- bool received; /* are results ready? */
-
- bool r_success; /* true-> okay,data ready to
- * pass to user * flase-> this
- * statusstring contains error
- * description */
- char *r_status; /* errorstring */
- struct timeval recvtime; /* Time packet was received,
- * if r_success is true */
-
- unsigned char *r_layer2;
- size_t r_layer2_len;
- unsigned char *r_layer3;
- size_t r_layer3_len;
- size_t packetsz;
-
- int ncap_cback_ref; /* just copy of
- * udata->ncap_cback_ref *
- * because we don't have
- * access to udata in place *
- * we need to use this. */
-};
-
-struct l_nsock_udata
-{
- int timeout;
nsock_iod nsiod;
+ unsigned timeout;
+
+ lua_State *thread;
+
+ const char *direction;
+ const char *action;
+
void *ssl_session;
+
struct sockaddr_storage source_addr;
size_t source_addrlen;
- struct nsock_yield yield;
- /* used for buffered reading */
- int bufidx; /* index inside lua's registry
- */
- int bufused;
- int rbuf_args[3]; /* indices in lua registry for
- * receive_buf args */
+ /* PCAP */
+ int is_pcap;
+ nsock_event_id nseid;
+ struct timeval recvtime; /* Time packet was received, if r_success is true */
- struct ncap_socket *ncap_socket;
- struct ncap_request *ncap_request;
- int ncap_cback_ref;
-};
+} nse_nsock_udata;
-/* size_t table_length (lua_State *L, int index)
- *
- * Returns the length of the table at index index.
- * This length is the number of elements, not just array elements.
- */
-static size_t table_length(lua_State * L, int index)
+static int NSOCK_POOL = 0xac1dba11;
+
+static int gc_pool (lua_State *L)
{
- size_t len = 0;
-
- lua_pushvalue(L, index);
- lua_pushnil(L);
- while (lua_next(L, -2) != 0)
- {
- len++;
- lua_pop(L, 1);
- }
- lua_pop(L, 1); // table
- return len;
+ nsock_pool *nsp = (nsock_pool *) lua_touserdata(L, 1);
+ assert(*nsp != NULL);
+ nsp_delete(*nsp);
+ *nsp = NULL;
+ return 0;
}
-static void weak_table(lua_State * L, int narr, int nrec, const char *mode)
+static nsock_pool new_pool (lua_State *L)
{
- lua_createtable(L, narr, nrec);
- lua_createtable(L, 0, 1);
- lua_pushstring(L, mode);
- lua_setfield(L, -2, "__mode");
+ nsock_pool nsp = nsp_new(NULL);
+ nsock_pool *nspp;
+ lua_pushlightuserdata(L, &NSOCK_POOL);
+ nspp = (nsock_pool *) lua_newuserdata(L, sizeof(nsock_pool));
+ *nspp = nsp;
+ lua_newtable(L);
+ lua_pushcfunction(L, gc_pool);
+ lua_setfield(L, -2, "__gc");
lua_setmetatable(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ return nsp;
}
-static std::string hexify(const unsigned char *str, size_t len)
+static nsock_pool get_pool (lua_State *L)
+{
+ nsock_pool *nsp;
+ lua_pushlightuserdata(L, &NSOCK_POOL);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ nsp = (nsock_pool *) lua_touserdata(L, -1);
+ assert(*nsp != NULL);
+ lua_pop(L, 1);
+ return *nsp;
+}
+
+static std::string hexify (const unsigned char *str, size_t len)
{
size_t num = 0;
@@ -241,20 +137,6 @@ static std::string hexify(const unsigned char *str, size_t len)
return ret.str();
}
-/* Thread index in nsock userdata environment.
- */
-#define THREAD_I 1
-
-static void set_thread (lua_State *L, int index, struct l_nsock_udata *n)
-{
- lua_getfenv(L, index);
- lua_pushthread(L);
- lua_rawseti(L, -2, THREAD_I);
- lua_pop(L, 1); /* nsock udata environment */
- n->yield.thread = L;
-}
-
-
/* Some constants used for enforcing a limit on the number of open sockets
* in use by threads. The maximum value between MAX_PARALLELISM and
* o.maxparallelism is the max # of threads that can have connected sockets
@@ -270,8 +152,53 @@ static void set_thread (lua_State *L, int index, struct l_nsock_udata *n)
* The table contains threads waiting to make a socket connection.
*/
#define MAX_PARALLELISM 20
-#define THREAD_SOCKETS 1 /* */
-#define CONNECT_WAITING 2 /* Threads waiting to lock */
+
+/* The Lua 5.2 socket_lock function */
+#if 0
+/* int socket_lock (lua_State *L)
+ *
+ * This function is called by l_connect to get a "lock" on a socket.
+ * When connect calls this function, it expects socket_lock to yield forcing
+ * connect to be restarted when resumed or it succeeds returning normally.
+ */
+static void socket_lock (lua_State *L, int idx)
+{
+ unsigned p = o.max_parallelism == 0 ? MAX_PARALLELISM : o.max_parallelism;
+ int top = lua_gettop(L);
+ lua_rawgeti(L, LUA_ENVIRONINDEX, THREAD_SOCKETS);
+ nse_base(L);
+ lua_rawget(L, -2);
+ if (lua_istable(L, -1))
+ {
+ /* Thread already has a "lock" with open sockets. Place the new socket
+ * in its sockets table */
+ lua_pushvalue(L, idx);
+ lua_pushboolean(L, true);
+ lua_rawset(L, -3);
+ } else if (table_length(L, top+2) <= p)
+ {
+ /* There is room for this thread to open sockets */
+ nse_base(L);
+ weak_table(L, 0, 0, "k"); /* weak socket references */
+ lua_pushvalue(L, idx); /* socket */
+ lua_pushboolean(L, true);
+ lua_rawset(L, -3); /* add to sockets table */
+ lua_rawset(L, top+2); /* add new Pair
+ * to THREAD_SOCKETS */
+ } else
+ {
+ /* Too many threads have sockets open. Add thread to waiting. The caller
+ * is expected to yield. (see the connect function in luaopen_nsock) */
+ lua_rawgeti(L, LUA_ENVIRONINDEX, CONNECT_WAITING);
+ nse_base(L);
+ lua_pushboolean(L, true);
+ lua_settable(L, -3);
+ lua_settop(L, top); /* restore stack to original condition for l_connect */
+ return nse_yield(L, 0, NULL);
+ }
+ lua_settop(L, top); /* restore stack to original condition for l_connect */
+}
+#endif
/* int socket_lock (lua_State *L)
*
@@ -281,7 +208,7 @@ static void set_thread (lua_State *L, int index, struct l_nsock_udata *n)
* This function is called by Lua to get a "lock" on a socket.
* See the connect function (in Lua) in luaopen_nsock.
*/
-static int socket_lock(lua_State * L)
+static int socket_lock (lua_State *L)
{
unsigned p = o.max_parallelism == 0 ? MAX_PARALLELISM : o.max_parallelism;
lua_settop(L, 1);
@@ -313,13 +240,13 @@ static int socket_lock(lua_State * L)
nse_base(L);
lua_pushboolean(L, true);
lua_settable(L, -3);
- return nse_yield(L);
+ return nse_yield(L, 0, NULL);
}
lua_pushboolean(L, true);
return 1;
}
-static void socket_unlock(lua_State * L)
+static void socket_unlock (lua_State *L)
{
int top = lua_gettop(L);
@@ -337,7 +264,7 @@ static void socket_unlock(lua_State * L)
while (lua_next(L, -2) != 0) /* for each socket */
{
lua_pop(L, 1); /* pop garbage boolean */
- if (((struct l_nsock_udata *) lua_touserdata(L, -1))->nsiod != NULL)
+ if (((nse_nsock_udata *) lua_touserdata(L, -1))->nsiod != NULL)
open++;
}
}
@@ -379,174 +306,134 @@ static void socket_unlock(lua_State * L)
lua_settop(L, top);
}
-void l_nsock_clear_buf(lua_State * L, l_nsock_udata * udata);
-
-void l_nsock_ssl_reconnect_handler(nsock_pool nsp, nsock_event nse, void *yield)
+static const char *inet_ntop_both (int af, const void *v_addr, char *ipstring)
{
- struct nsock_yield *y = (struct nsock_yield *) yield;
-
- lua_State *L = y->thread;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- if (o.scriptTrace())
- l_nsock_trace(nse_iod(nse), "SSL RECONNECT", TO);
-
- if (l_nsock_checkstatus(L, nse) == NSOCK_WRAPPER_SUCCESS)
- nse_restore(y->thread, 1);
+ if (af == AF_INET)
+ {
+ inet_ntop(AF_INET, &((struct sockaddr_in *) v_addr)->sin_addr,
+ ipstring, INET6_ADDRSTRLEN);
+ return ipstring;
+ }
+#ifdef HAVE_IPV6
+ else if (af == AF_INET6)
+ {
+ inet_ntop(AF_INET6, &((struct sockaddr_in6 *) v_addr)->sin6_addr,
+ ipstring, INET6_ADDRSTRLEN);
+ return ipstring;
+ }
+#endif
else
- nse_restore(y->thread, 2);
+ return "unknown protocol";
}
-static int l_nsock_reconnect_ssl (lua_State *L)
+static unsigned short inet_port_both (int af, const void *v_addr)
{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
+ int port;
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to reconnect ssl through a closed socket\n");
- return 2;
- }
-#ifndef HAVE_OPENSSL
- if (1)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Sorry, you don't have OpenSSL\n");
- return 2;
- }
+ if (af == AF_INET)
+ port = ((struct sockaddr_in *) v_addr)->sin_port;
+#ifdef HAVE_IPV6
+ else if (af == AF_INET6)
+ port = ((struct sockaddr_in6 *) v_addr)->sin6_port;
#endif
+ else
+ port = 0;
- nsock_reconnect_ssl(nsp, udata->nsiod, l_nsock_ssl_reconnect_handler,
- udata->timeout, &udata->yield, udata->ssl_session);
-
- set_thread(L, 1, udata);
- return nse_yield(L);
+ return ntohs(port);
}
-int luaopen_nsock(lua_State * L)
+#define TO ">"
+#define FROM "<"
+
+static void trace (nsock_iod nsiod, const char *message, const char *dir)
{
- /* nsock:connect(socket, ...) This Lua function is a wrapper around the
- * actual l_nsock_connect. The connect function must get a lock through
- * socket_lock (C function above). Once it has the lock, it can (tail call)
- * return the actual connect function. */
- static const char connect[] =
- "local connect, socket_lock = ...;\n"
- "return function(socket, ...)\n"
- " repeat until socket_lock(socket) == true;\n"
- " return connect(socket, ...);\n" "end";
-
- static const luaL_Reg l_nsock[] = {
- {"bind", l_nsock_bind},
- {"send", l_nsock_send},
- {"receive", l_nsock_receive},
- {"receive_lines", l_nsock_receive_lines},
- {"receive_bytes", l_nsock_receive_bytes},
- {"receive_buf", l_nsock_receive_buf},
- {"get_info", l_nsock_get_info},
- {"close", l_nsock_close},
- {"set_timeout", l_nsock_set_timeout},
- {"pcap_open", l_nsock_pcap_open},
- {"pcap_close", l_nsock_pcap_close},
- {"pcap_register", l_nsock_pcap_register},
- {"pcap_receive", l_nsock_pcap_receive},
- {"get_ssl_certificate", l_get_ssl_certificate},
- {"reconnect_ssl", l_nsock_reconnect_ssl},
- // {"callback_test", l_nsock_pcap_callback_test},
- {NULL, NULL}
- };
-
- /* Set up an environment for all nsock C functions to share.
- * This table particularly contains the THREAD_SOCKETS and
- * CONNECT_WAITING tables.
- * These values are accessed at the Lua pseudo-index LUA_ENVIRONINDEX.
- */
- lua_createtable(L, 2, 0);
- lua_replace(L, LUA_ENVIRONINDEX);
-
- weak_table(L, 0, MAX_PARALLELISM, "k");
- lua_rawseti(L, LUA_ENVIRONINDEX, THREAD_SOCKETS);
-
- weak_table(L, 0, 1000, "k");
- lua_rawseti(L, LUA_ENVIRONINDEX, CONNECT_WAITING);
-
- lua_pushcfunction(L, l_nsock_loop);
- lua_setfield(L, LUA_REGISTRYINDEX, NSE_NSOCK_LOOP);
-
- /* Load the connect function */
- if (luaL_loadstring(L, connect) != 0)
- fatal("connect did not compile!");
- lua_pushcclosure(L, l_nsock_connect, 0);
- lua_pushcclosure(L, socket_lock, 0);
- lua_call(L, 2, 1); // leave connect function on stack...
- lua_pushvalue(L, LUA_GLOBALSINDEX);
- lua_setfenv(L, -2); // set the connect function's
- // environment to _G
-
- /* Create the nsock metatable for sockets */
- luaL_newmetatable(L, "nsock");
- lua_createtable(L, 0, 23);
- luaL_register(L, NULL, l_nsock);
- lua_pushvalue(L, -3); // connect function
- lua_setfield(L, -2, "connect");
- lua_setfield(L, -2, "__index");
- lua_pushcclosure(L, l_nsock_gc, 0);
- lua_setfield(L, -2, "__gc");
- lua_newtable(L);
- lua_setfield(L, -2, "__metatable"); // protect metatable
- lua_pop(L, 1); // nsock metatable
-
- luaL_newmetatable(L, "nsock_proxy");
-
-#if HAVE_OPENSSL
- /* Set up the SSL certificate userdata code in nse_ssl_cert.cc. */
- nse_nsock_init_ssl_cert(L);
-#endif
-
- nsp = nsp_new(NULL);
if (o.scriptTrace())
- nsp_settrace(nsp, NSOCK_TRACE_LEVEL, o.getStartTime());
-#if HAVE_OPENSSL
- /* Value speed over security in SSL connections. */
- nsp_ssl_init_max_speed(nsp);
-#endif
+ {
+ if (!nsi_is_pcap(nsiod))
+ {
+ int status;
+ int protocol;
+ int af;
+ char ipstring_local[INET6_ADDRSTRLEN];
+ char ipstring_remote[INET6_ADDRSTRLEN];
+ struct sockaddr_storage local;
+ struct sockaddr_storage remote;
- l_dnet_open(L); /* open dnet metatable */
-
- return 0;
+ status = nsi_getlastcommunicationinfo(nsiod, &protocol, &af,
+ (sockaddr *) &local, (sockaddr *) &remote, sizeof(sockaddr_storage));
+ log_write(LOG_STDOUT, "%s: %s %s:%d %s %s:%d | %s\n",
+ SCRIPT_ENGINE,
+ IPPROTO2STR_UC(protocol),
+ inet_ntop_both(af, &local, ipstring_local),
+ inet_port_both(af, &local),
+ dir,
+ inet_ntop_both(af, &remote, ipstring_remote),
+ inet_port_both(af, &remote), message);
+ } else {
+ log_write(LOG_STDOUT, "%s: %s | %s\n", SCRIPT_ENGINE, dir, message);
+ }
+ }
}
-int l_nsock_new(lua_State * L)
+static void status (lua_State *L, enum nse_status status)
{
- struct l_nsock_udata *udata;
-
- udata =
- (struct l_nsock_udata *) lua_newuserdata(L, sizeof(struct l_nsock_udata));
- luaL_getmetatable(L, "nsock");
- lua_setmetatable(L, -2);
- lua_createtable(L, 1, 0); /* room for thread in array */
- lua_setfenv(L, -2);
- udata->nsiod = NULL;
- udata->ssl_session = NULL;
- udata->source_addr.ss_family = AF_UNSPEC;
- udata->source_addrlen = sizeof(udata->source_addr);
- udata->timeout = DEFAULT_TIMEOUT;
- udata->bufidx = LUA_NOREF;
- udata->bufused = 0;
- udata->rbuf_args[0] = LUA_NOREF;
- udata->rbuf_args[1] = LUA_NOREF;
- udata->rbuf_args[2] = LUA_NOREF;
- udata->ncap_socket = NULL;
- udata->ncap_request = NULL;
- udata->ncap_cback_ref = 0;
-
- return 1;
+ switch (status)
+ {
+ case NSE_STATUS_SUCCESS:
+ lua_pushboolean(L, true);
+ nse_restore(L, 1);
+ break;
+ case NSE_STATUS_KILL:
+ case NSE_STATUS_CANCELLED:
+ return; /* do nothing! */
+ case NSE_STATUS_EOF:
+ case NSE_STATUS_ERROR:
+ case NSE_STATUS_TIMEOUT:
+ lua_pushnil(L);
+ lua_pushstring(L, nse_status2str(status));
+ nse_restore(L, 2);
+ break;
+ case NSE_STATUS_NONE:
+ default:
+ assert(0);
+ break;
+ }
}
-static int l_nsock_loop(lua_State * L)
+static void callback (nsock_pool nsp, nsock_event nse, void *ud)
{
+ nse_nsock_udata *nu = (nse_nsock_udata *) ud;
+ lua_State *L = nu->thread;
+ assert(lua_status(L) == LUA_YIELD);
+ trace(nse_iod(nse), nu->action, nu->direction);
+ status(L, nse_status(nse));
+}
+
+static int yield (lua_State *L, nse_nsock_udata *nu, const char *action,
+ const char *direction, int ctx, lua_CFunction k)
+{
+ lua_getfenv(L, 1);
+ lua_pushthread(L);
+ lua_rawseti(L, -2, THREAD_I);
+ lua_pop(L, 1); /* nsock udata environment */
+ nu->thread = L;
+ nu->action = action;
+ nu->direction = direction;
+ return nse_yield(L, ctx, k);
+}
+
+static nse_nsock_udata *check_nsock_udata (lua_State *L, int idx, int open)
+{
+ nse_nsock_udata *nu =
+ (nse_nsock_udata *) luaL_checkudata(L, idx, NMAP_NSOCK_SOCKET);
+ if (open && nu->nsiod == NULL)
+ luaL_error(L, "socket must be connected\n");
+ return nu;
+}
+
+static int loop (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
int tout = luaL_checkint(L, 1);
/* clean up old socket locks */
@@ -557,60 +444,303 @@ static int l_nsock_loop(lua_State * L)
return 0;
}
-int l_nsock_checkstatus(lua_State * L, nsock_event nse)
+static int l_reconnect_ssl (lua_State *L)
{
- enum nse_status status = nse_status(nse);
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
- switch (status)
- {
- case NSE_STATUS_SUCCESS:
- lua_pushboolean(L, true);
- return NSOCK_WRAPPER_SUCCESS;
- break;
- case NSE_STATUS_ERROR:
- case NSE_STATUS_TIMEOUT:
- case NSE_STATUS_CANCELLED:
- case NSE_STATUS_KILL:
- case NSE_STATUS_EOF:
- lua_pushnil(L);
- lua_pushstring(L, nse_status2str(status));
- return NSOCK_WRAPPER_ERROR;
- break;
- case NSE_STATUS_NONE:
- default:
- fatal("%s: In: %s:%i This should never happen.",
- NSOCK_WRAPPER, __FILE__, __LINE__);
- break;
+#ifndef HAVE_OPENSSL
+ if (1)
+ return safe_error(L, "sorry, you don't have OpenSSL");
+#endif
+ nsock_reconnect_ssl(nsp, nu->nsiod, callback, nu->timeout,
+ nu, nu->ssl_session);
+
+ return yield(L, nu, "SSL RECONNECT", TO, 0, NULL);
+}
+
+static int l_connect (lua_State *L)
+{
+ enum type {TCP, UDP, SSL};
+ static const char * const op[] = {"tcp", "udp", "ssl", NULL};
+
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
+ const char *addr, *targetname; check_target(L, 2, &addr, &targetname);
+ const char *default_proto = NULL;
+ unsigned short port = check_port(L, 3, &default_proto);
+ if (default_proto == NULL) default_proto = "tcp";
+ int what = luaL_checkoption(L, 4, default_proto, op);
+ struct addrinfo *dest;
+ int error_id;
+
+ /* Lua 5.2 */
+#if 0
+ /* either socket_lock yields and this function is resumed (and restarted)
+ * or it succeeds and we continue.
+ */
+ socket_lock(L);
+#endif
+
+#ifndef HAVE_OPENSSL
+ if (what == SSL)
+ return safe_error(L, "sorry, you don't have OpenSSL");
+#endif
+
+ error_id = getaddrinfo(addr, NULL, NULL, &dest);
+ if (error_id)
+ return safe_error(L, gai_strerror(error_id));
+
+ if (dest == NULL)
+ return safe_error(L, "getaddrinfo returned success but no addresses");
+
+ nu->nsiod = nsi_new(nsp, NULL);
+ if (nu->source_addr.ss_family != AF_UNSPEC) {
+ nsi_set_localaddr(nu->nsiod, &nu->source_addr, nu->source_addrlen);
+ } else if (o.spoofsource) {
+ struct sockaddr_storage ss;
+ size_t sslen;
+
+ o.SourceSockAddr(&ss, &sslen);
+ nsi_set_localaddr(nu->nsiod, &ss, sslen);
+ }
+ if (o.ipoptionslen)
+ nsi_set_ipoptions(nu->nsiod, o.ipoptions, o.ipoptionslen);
+ if (targetname != NULL) {
+ if (nsi_set_hostname(nu->nsiod, targetname) == -1)
+ fatal("nsi_set_hostname(\"%s\" failed in %s()", targetname, __func__);
}
- return -1;
+ switch (what)
+ {
+ case TCP:
+ nsock_connect_tcp(nsp, nu->nsiod, callback, nu->timeout, nu,
+ dest->ai_addr, dest->ai_addrlen, port);
+ break;
+ case UDP:
+ nsock_connect_udp(nsp, nu->nsiod, callback, nu, dest->ai_addr,
+ dest->ai_addrlen, port);
+ break;
+ case SSL:
+ nsock_connect_ssl(nsp, nu->nsiod, callback, nu->timeout, nu,
+ dest->ai_addr, dest->ai_addrlen, IPPROTO_TCP, port, nu->ssl_session);
+ break;
+ }
+
+ freeaddrinfo(dest);
+ return yield(L, nu, "CONNECT", TO, 0, NULL);
}
+static int l_send (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ size_t size;
+ const char *string = luaL_checklstring(L, 2, &size);
+ trace(nu->nsiod, hexify((unsigned char *) string, size).c_str(), TO);
+ nsock_write(nsp, nu->nsiod, callback, nu->timeout, nu, string, size);
+ return yield(L, nu, "SEND", TO, 0, NULL);
+}
+
+static void receive_callback (nsock_pool nsp, nsock_event nse, void *udata)
+{
+ nse_nsock_udata *nu = (nse_nsock_udata *) udata;
+ lua_State *L = nu->thread;
+ assert(lua_status(L) == LUA_YIELD);
+ if (nse_status(nse) == NSE_STATUS_SUCCESS)
+ {
+ int len;
+ const char *str = nse_readbuf(nse, &len);
+ trace(nse_iod(nse), hexify((const unsigned char *) str, len).c_str(), FROM);
+ lua_pushboolean(L, true);
+ lua_pushlstring(L, str, len);
+ nse_restore(L, 2);
+ }
+ else
+ status(L, nse_status(nse)); /* will also restore the thread */
+}
+
+static int l_receive (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ nsock_read(nsp, nu->nsiod, receive_callback, nu->timeout, nu);
+ return yield(L, nu, "RECEIVE", FROM, 0, NULL);
+}
+
+static int l_receive_lines (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ nsock_readlines(nsp, nu->nsiod, receive_callback, nu->timeout, nu,
+ luaL_checkint(L, 2));
+ return yield(L, nu, "RECEIVE LINES", FROM, 0, NULL);
+}
+
+static int l_receive_bytes (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ nsock_readbytes(nsp, nu->nsiod, receive_callback, nu->timeout, nu,
+ luaL_checkint(L, 2));
+ return yield(L, nu, "RECEIVE BYTES", FROM, 0, NULL);
+}
+
+static int l_get_info (lua_State *L)
+{
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ int status;
+ int protocol; // tcp or udp
+ int af; // address family
+ struct sockaddr local;
+ struct sockaddr remote;
+ char *ipstring_local = (char *) lua_newuserdata(L, sizeof(char) * INET6_ADDRSTRLEN);
+ char *ipstring_remote = (char *) lua_newuserdata(L, sizeof(char) * INET6_ADDRSTRLEN);
+
+ status = nsi_getlastcommunicationinfo(nu->nsiod, &protocol, &af,
+ &local, &remote, sizeof(sockaddr));
+
+ lua_pushboolean(L, true);
+ lua_pushstring(L, inet_ntop_both(af, &local, ipstring_local));
+ lua_pushnumber(L, inet_port_both(af, &local));
+ lua_pushstring(L, inet_ntop_both(af, &remote, ipstring_remote));
+ lua_pushnumber(L, inet_port_both(af, &remote));
+ return 5;
+}
+
+static int l_set_timeout (lua_State *L)
+{
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
+ nu->timeout = luaL_checkint(L, 2);
+ return success(L);
+}
+
+#if 0
+/* Lua 5.2 */
+static int l_receive_buf (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1); /* 1 */
+ if (!(lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TSTRING))
+ luaL_typeerror(L, 2, "function/string");
+ luaL_checktype(L, 3, LUA_TBOOLEAN); /* 3 */
+
+ if (lua_getctx(L, NULL) == LUA_OK)
+ {
+ lua_settop(L, 3); /* clear top */
+ lua_getuservalue(L, 1); /* 4 */
+ lua_rawgeti(L, 4, BUFFER_I); /* 5 */
+ }
+ else
+ {
+ /* Here we are returning from nsock_read below.
+ * We have two extra values on the stack pushed by receive_callback.
+ */
+ assert(lua_gettop(L) == 7);
+ if (lua_toboolean(L, 6)) /* success? */
+ {
+ lua_replace(L, 6); /* remove boolean */
+ lua_concat(L, 2); /* concat BUFFER_I with received data */
+ }
+ else /* receive_callback encountered an error */
+ return 2;
+ }
+
+ if (lua_isfunction(L, 2))
+ {
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, 5);
+ lua_call(L, 1, 2); /* we do not allow yields */
+ }
+ else /* string */
+ {
+ lua_getglobal(L, "string");
+ lua_getfield(L, -1, "find");
+ lua_replace(L, -2);
+ lua_pushvalue(L, 5);
+ lua_pushvalue(L, 2);
+ lua_call(L, 2, 2); /* we do not allow yields */
+ }
+
+ if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) /* found end? */
+ {
+ lua_Integer l = lua_tointeger(L, -2), r = lua_tointeger(L, -1);
+ if (l > r || r > (lua_Integer) lua_objlen(L, 5))
+ return luaL_error(L, "invalid indices for match");
+ lua_pushboolean(L, 1);
+ if (lua_toboolean(L, 3))
+ lua_pushlstring(L, lua_tostring(L, 5), r);
+ else
+ lua_pushlstring(L, lua_tostring(L, 5), l-1);
+ lua_pushlstring(L, lua_tostring(L, 5)+r, lua_objlen(L, 5)-r);
+ lua_rawseti(L, 4, BUFFER_I);
+ return 2;
+ }
+ else
+ {
+ lua_pop(L, 2); /* pop 2 results */
+ nsock_read(nsp, nu->nsiod, receive_callback, nu->timeout, nu);
+ return yield(L, nu, "RECEIVE BUF", FROM, 0, l_receive_buf);
+ }
+}
+#endif
+
+static void sleep_callback (nsock_pool nsp, nsock_event nse, void *ud)
+{
+ lua_State *L = (lua_State *) ud;
+ assert(lua_status(L) == LUA_YIELD);
+ assert(nse_status(nse) == NSE_STATUS_SUCCESS);
+ nse_restore(L, 0);
+}
+
+LUALIB_API int l_nsock_sleep (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ double secs = luaL_checknumber(L, 1);
+ int msecs;
+
+ if (secs < 0)
+ luaL_error(L, "argument to sleep (%f) must not be negative\n", secs);
+ /* Convert to milliseconds for nsock_timer_create. */
+ msecs = (int) (secs * 1000 + 0.5);
+ nsock_timer_create(nsp, sleep_callback, msecs, L);
+
+ return nse_yield(L, 0, NULL);
+}
+
+#if HAVE_OPENSSL
+SSL *nse_nsock_get_ssl (lua_State *L)
+{
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
+
+ if (!nsi_checkssl(nu->nsiod))
+ luaL_argerror(L, 1, "not a SSL socket");
+
+ return (SSL *) nsi_getssl(nu->nsiod);
+}
+#else
+/* If HAVE_OPENSSL is defined, this comes from nse_ssl_cert.cc. */
+int get_ssl_certificate (lua_State *L)
+{
+ return luaL_error("SSL is not available");
+}
+#endif
+
/* Set the local address for socket operations. The two optional parameters
after the first (which is the socket object) are a string representing a
numeric address, and a port number. If either optional parameter is omitted
or nil, that part of the address will be left unspecified. */
-static int l_nsock_bind(lua_State * L)
+static int l_bind (lua_State *L)
{
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
struct addrinfo hints = { 0 };
struct addrinfo *results;
- char port_buf[16];
- l_nsock_udata *udata;
- const char *addr_str = NULL;
- const char *port_str = NULL;
+ const char *addr_str = luaL_optstring(L, 2, NULL);
+ luaL_checkint(L, 3);
+ const char *port_str = lua_tostring(L, 3); /* automatic conversion */
int rc;
- udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
- if (!lua_isnoneornil(L, 2))
- addr_str = luaL_checkstring(L, 2);
- if (!lua_isnoneornil(L, 3)) {
- int port;
- port = luaL_checkint(L, 3);
- Snprintf(port_buf, sizeof(port_buf), "%d", port);
- port_str = port_buf;
- }
-
/* If we don't have a string to work with, set our configured address family
to get the proper unspecified address (0.0.0.0 or ::). Otherwise infer the
family from the string. */
@@ -623,1644 +753,320 @@ static int l_nsock_bind(lua_State * L)
hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
rc = getaddrinfo(addr_str, port_str, &hints, &results);
- if (rc != 0) {
- lua_pushnil(L);
- lua_pushstring(L, gai_strerror(rc));
- return 2;
- }
- if (results == NULL) {
- lua_pushnil(L);
- lua_pushstring(L, "getaddrinfo: no results found");
- return 2;
- }
- if (results->ai_addrlen > sizeof(udata->source_addr)) {
+ if (rc != 0)
+ return safe_error(L, gai_strerror(rc));
+ if (results == NULL)
+ return safe_error(L, "getaddrinfo: no results found");
+ if (results->ai_addrlen > sizeof(nu->source_addr)) {
freeaddrinfo(results);
- lua_pushnil(L);
- lua_pushstring(L, "getaddrinfo: result is too big");
- return 2;
+ return safe_error(L, "getaddrinfo: result is too big");
}
/* We ignore any results after the first. */
- /* We would just call nsi_set_localaddr here, but udata->nsiod is not created
+ /* We would just call nsi_set_localaddr here, but nu->nsiod is not created
until connect. So store the address in the userdatum. */
- udata->source_addrlen = results->ai_addrlen;
- memcpy(&udata->source_addr, results->ai_addr, udata->source_addrlen);
+ nu->source_addrlen = results->ai_addrlen;
+ memcpy(&nu->source_addr, results->ai_addr, nu->source_addrlen);
+
+ return success(L);
+}
+
+static void initialize (lua_State *L, int idx, nse_nsock_udata *nu)
+{
+ lua_createtable(L, 2, 0); /* room for thread in array */
+ lua_pushliteral(L, "");
+ lua_rawseti(L, -2, BUFFER_I);
+ lua_setfenv(L, idx);
+ nu->nsiod = NULL;
+ nu->ssl_session = NULL;
+ nu->source_addr.ss_family = AF_UNSPEC;
+ nu->source_addrlen = sizeof(nu->source_addr);
+ nu->timeout = DEFAULT_TIMEOUT;
+ nu->is_pcap = 0;
+ nu->thread = NULL;
+ nu->direction = nu->action = NULL;
+}
+
+LUALIB_API int l_nsock_new (lua_State *L)
+{
+ nse_nsock_udata *nu;
+ lua_settop(L, 0);
+
+ nu = (nse_nsock_udata *) lua_newuserdata(L, sizeof(nse_nsock_udata));
+ luaL_getmetatable(L, NMAP_NSOCK_SOCKET);
+ lua_setmetatable(L, -2);
+ initialize(L, 1, nu);
- lua_pushboolean(L, 1);
return 1;
}
-static int l_nsock_connect(lua_State * L)
+static int l_close (lua_State *L)
{
- enum type {TCP, UDP, SSL};
- static const char * const op[] = {"tcp", "udp", "ssl", NULL};
- const char *default_proto = "tcp";
-
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
- const char *addr, *targetname;
- unsigned short port;
- int what;
-
- addr = NULL;
- targetname = NULL;
-
- /* host argument. */
- if (lua_istable(L, 2)) {
- const char *ip;
-
- ip = NULL;
- targetname = NULL;
-
- lua_getfield(L, 2, "ip");
- ip = lua_tostring(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 2, "targetname");
- targetname = lua_tostring(L, -1);
- lua_pop(L, 1);
-
- if (ip != NULL)
- addr = ip;
- else if (targetname != NULL)
- addr = targetname;
- else
- luaL_error(L, "host table does not have a 'ip' or 'targetname' field");
- } else {
- addr = luaL_checkstring(L, 2);
- targetname = addr;
- }
-
- /* port argument. */
- if (lua_istable(L, 3)) {
- lua_getfield(L, 3, "number");
- if (lua_isnil(L, -1))
- luaL_error(L, "port table does not have a 'number' field");
- else if (!lua_isnumber(L, -1))
- luaL_error(L, "port.number is not numeric");
- port = lua_tointeger(L, -1);
- lua_pop(L, 1);
-
- lua_getfield(L, 3, "protocol");
- /* Make this the default if the "proto" argument isn't given. */
- if (lua_isstring(L, -1))
- default_proto = lua_tostring(L, -1);
- lua_pop(L, 1);
- } else {
- port = (unsigned short) luaL_checkint(L, 3);
- }
-
- /* proto argument. */
- what = luaL_checkoption(L, 4, default_proto, op);
-
- const char *error;
- struct addrinfo *dest;
- int error_id;
-
- l_nsock_clear_buf(L, udata);
-
-#ifndef HAVE_OPENSSL
- if (what == SSL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Sorry, you don't have OpenSSL\n");
- return 2;
- }
-#endif
-
- error_id = getaddrinfo(addr, NULL, NULL, &dest);
- if (error_id)
- {
- error = gai_strerror(error_id);
- lua_pushboolean(L, false);
- lua_pushstring(L, error);
- return 2;
- }
- if (dest == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "getaddrinfo returned success but no addresses");
- return 2;
- }
-
- udata->nsiod = nsi_new(nsp, NULL);
- if (udata->source_addr.ss_family != AF_UNSPEC) {
- nsi_set_localaddr(udata->nsiod, &udata->source_addr, udata->source_addrlen);
- } else if (o.spoofsource) {
- struct sockaddr_storage ss;
- size_t sslen;
-
- o.SourceSockAddr(&ss, &sslen);
- nsi_set_localaddr(udata->nsiod, &ss, sslen);
- }
- if (targetname != NULL) {
- if (nsi_set_hostname(udata->nsiod, targetname) == -1)
- fatal("nsi_set_hostname(\"%s\" failed in %s()", targetname, __func__);
- }
- if (o.ipoptionslen)
- nsi_set_ipoptions(udata->nsiod, o.ipoptions, o.ipoptionslen);
-
- switch (what)
- {
- case TCP:
- nsock_connect_tcp(nsp, udata->nsiod, l_nsock_connect_handler,
- udata->timeout, &udata->yield, dest->ai_addr, dest->ai_addrlen, port);
- break;
- case UDP:
- nsock_connect_udp(nsp, udata->nsiod, l_nsock_connect_handler,
- &udata->yield, dest->ai_addr, dest->ai_addrlen, port);
- break;
- case SSL:
- nsock_connect_ssl(nsp, udata->nsiod, l_nsock_connect_handler,
- udata->timeout, &udata->yield, dest->ai_addr, dest->ai_addrlen,
- IPPROTO_TCP, port, udata->ssl_session);
- break;
- }
-
- freeaddrinfo(dest);
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *yield)
-{
- struct nsock_yield *y = (struct nsock_yield *) yield;
-
- lua_State *L = y->thread;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- if (o.scriptTrace())
- {
- l_nsock_trace(nse_iod(nse), "CONNECT", TO);
- }
-
- if (l_nsock_checkstatus(L, nse) == NSOCK_WRAPPER_SUCCESS)
- {
- nse_restore(y->thread, 1);
- } else
- {
- nse_restore(y->thread, 2);
- }
-}
-
-static int l_nsock_send(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- const char *string = luaL_checkstring(L, 2);
-
- size_t string_len = lua_objlen(L, 2);
-
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to send through a closed socket\n");
- return 2;
- }
-
- if (o.scriptTrace())
- l_nsock_trace(udata->nsiod, hexify((unsigned char *) string,
- string_len).c_str(), TO);
-
- nsock_write(nsp, udata->nsiod, l_nsock_send_handler, udata->timeout,
- &udata->yield, string, string_len);
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *yield)
-{
- struct nsock_yield *y = (struct nsock_yield *) yield;
-
- lua_State *L = y->thread;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- if (l_nsock_checkstatus(L, nse) == NSOCK_WRAPPER_SUCCESS)
- {
- nse_restore(y->thread, 1);
- } else
- {
- nse_restore(y->thread, 2);
- }
-}
-
-static int l_nsock_receive(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to receive through a closed socket\n");
- return 2;
- }
-
- nsock_read(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout,
- &udata->yield);
-
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-static int l_nsock_receive_lines(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- int nlines = (int) luaL_checknumber(L, 2);
-
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to receive lines through a closed socket\n");
- return 2;
- }
-
- nsock_readlines(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout,
- &udata->yield, nlines);
-
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-static int l_nsock_receive_bytes(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- int nbytes = (int) luaL_checknumber(L, 2);
-
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to receive bytes through a closed socket\n");
- return 2;
- }
-
- nsock_readbytes(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout,
- &udata->yield, nbytes);
-
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *yield)
-{
- struct nsock_yield *y = (struct nsock_yield *) yield;
-
- lua_State *L = y->thread;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- char *rcvd_string;
-
- int rcvd_len = 0;
-
- if (l_nsock_checkstatus(L, nse) == NSOCK_WRAPPER_SUCCESS)
- {
- rcvd_string = nse_readbuf(nse, &rcvd_len);
-
- if (o.scriptTrace())
- l_nsock_trace(nse_iod(nse), hexify((unsigned char *) rcvd_string,
- (size_t) rcvd_len).c_str(), FROM);
-
- lua_pushlstring(L, rcvd_string, rcvd_len);
- nse_restore(y->thread, 2);
- } else
- {
- nse_restore(y->thread, 2);
- }
-}
-
-void l_nsock_trace(nsock_iod nsiod, const char *message, int direction)
-{
- int status;
- int protocol;
- int af;
-
- if (!nsi_is_pcap(nsiod)) {
- char ipstring_local[INET6_ADDRSTRLEN];
- char ipstring_remote[INET6_ADDRSTRLEN];
- struct sockaddr_storage local;
- struct sockaddr_storage remote;
-
- status = nsi_getlastcommunicationinfo(nsiod, &protocol, &af,
- (sockaddr *) &local, (sockaddr *) &remote, sizeof(sockaddr_storage));
- log_write(LOG_STDOUT, "%s: %s %s:%d %s %s:%d | %s\n",
- SCRIPT_ENGINE,
- IPPROTO2STR_UC(protocol),
- inet_ntop_both(af, &local, ipstring_local),
- inet_port_both(af, &local),
- (direction == TO) ? ">" : "<",
- inet_ntop_both(af, &remote, ipstring_remote),
- inet_port_both(af, &remote), message);
- } else { // is pcap device
- log_write(LOG_STDOUT, "%s: %s | %s\n",
- SCRIPT_ENGINE, (direction == TO) ? ">" : "<", message);
- }
-}
-
-const char *inet_ntop_both(int af, const void *v_addr, char *ipstring)
-{
- if (af == AF_INET)
- {
- inet_ntop(AF_INET, &((struct sockaddr_in *) v_addr)->sin_addr,
- ipstring, INET6_ADDRSTRLEN);
-
- return ipstring;
- }
-#ifdef HAVE_IPV6
- else if (af == AF_INET6)
- {
- inet_ntop(AF_INET6, &((struct sockaddr_in6 *) v_addr)->sin6_addr,
- ipstring, INET6_ADDRSTRLEN);
- return ipstring;
- }
-#endif
- else
- {
- return "unknown protocol";
- }
-
-}
-
-unsigned short inet_port_both(int af, const void *v_addr)
-{
- int port;
-
- if (af == AF_INET)
- {
- port = ((struct sockaddr_in *) v_addr)->sin_port;
- }
-#ifdef HAVE_IPV6
- else if (af == AF_INET6)
- {
- port = ((struct sockaddr_in6 *) v_addr)->sin6_port;
- }
-#endif
- else
- {
- port = 0;
- }
-
- return ntohs(port);
-}
-
-static int l_nsock_get_info(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- int status;
-
- int protocol; // tcp or udp
-
- int af; // address family
-
- struct sockaddr local;
-
- struct sockaddr remote;
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to get info from a closed socket\n");
- return 2;
- }
-
- status = nsi_getlastcommunicationinfo(udata->nsiod, &protocol, &af,
- &local, &remote, sizeof(sockaddr));
-
- lua_pushboolean(L, true);
-
- char *ipstring_local = (char *) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
- char *ipstring_remote = (char *) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
-
- lua_pushstring(L, inet_ntop_both(af, &local, ipstring_local));
- lua_pushnumber(L, inet_port_both(af, &local));
-
- lua_pushstring(L, inet_ntop_both(af, &remote, ipstring_remote));
- lua_pushnumber(L, inet_port_both(af, &remote));
-
- free(ipstring_local);
- free(ipstring_remote);
- return 5;
-}
-
-static int l_nsock_gc(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- if (udata->nsiod == NULL)
- { // socket obviously got closed already -
- // so no finalization needed
- return 0;
- } else
- {
- // FIXME - check wheter close returned true!!
- for (int i = 0; i < 3; i++)
- luaL_unref(L, LUA_REGISTRYINDEX, udata->rbuf_args[i]);
- l_nsock_close(L);
- }
- return 0;
-}
-
-static int l_nsock_close(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- /* Never ever collect nse-pcap connections. */
- if (udata->ncap_socket)
- {
- return 0;
- }
-
- l_nsock_clear_buf(L, udata);
-
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to close a closed socket\n");
- return 2;
- }
-
- if (o.scriptTrace())
- {
- l_nsock_trace(udata->nsiod, "CLOSE", TO);
- }
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
+ if (nu->nsiod == NULL)
+ return safe_error(L, "socket already closed");
+ trace(nu->nsiod, "CLOSE", TO);
#ifdef HAVE_OPENSSL
- if (udata->ssl_session)
- SSL_SESSION_free((SSL_SESSION *) udata->ssl_session);
- udata->ssl_session = NULL;
+ if (nu->ssl_session)
+ SSL_SESSION_free((SSL_SESSION *) nu->ssl_session);
#endif
-
- nsi_delete(udata->nsiod, NSOCK_PENDING_NOTIFY);
-
- udata->nsiod = NULL;
-
- lua_pushboolean(L, true);
- return 1;
+ if (!nu->is_pcap) /* pcap sockets are closed by pcap_gc */
+ nsi_delete(nu->nsiod, NSOCK_PENDING_NOTIFY);
+ initialize(L, 1, nu);
+ return success(L);
}
-static int l_nsock_set_timeout(lua_State * L)
+static int nsock_gc (lua_State *L)
{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- int timeout = (unsigned short) luaL_checkint(L, 2);
-
- udata->timeout = timeout;
-
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
+ if (nu->nsiod)
+ return l_close(L);
return 0;
}
-/* buffered I/O */
-static int l_nsock_receive_buf(lua_State * L)
+
+/****************** PCAP_SOCKET ***********************************************/
+
+static void dnet_to_pcap_device_name (lua_State *L, const char *device)
{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- lua_settop(L, 3);
- udata->yield.udata = udata;
- for (int i = 0; i < 3; i++)
- { /* compatibility, clean up someday */
- lua_pushvalue(L, i + 1); /* argument 1-3 */
- udata->rbuf_args[i] = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- if (udata->nsiod == NULL)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Trying to receive through a closed socket\n");
- return 2;
- }
- if (udata->bufused == 0)
- {
- lua_pushstring(L, "");
- udata->bufidx = luaL_ref(L, LUA_REGISTRYINDEX);
- udata->bufused = 1;
- nsock_read(nsp, udata->nsiod, l_nsock_receive_buf_handler, udata->timeout,
- &udata->yield);
- } else if (udata->bufused == -1)
- { /* error message is inside the buffer */
- lua_pushboolean(L, false);
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx);
- return 2;
- } else
- { /* buffer contains already some data */
- /* we keep track here of how many calls to receive_buf are made */
- udata->bufused++;
- if (l_nsock_check_buf(L) == NSOCK_WRAPPER_BUFFER_MOREREAD)
- {
- /* if we didn't have enough data in the buffer another nsock_read() was
- * scheduled - its callback will put us in running state again */
- set_thread(L, 1, udata);
- return nse_yield(L);
- }
- return 2;
- }
- set_thread(L, 1, udata);
- return nse_yield(L);
-}
-
-void l_nsock_receive_buf_handler(nsock_pool nsp, nsock_event nse, void *yield)
-{
- struct nsock_yield *y = (struct nsock_yield *) yield;
-
- l_nsock_udata *udata = y->udata;
-
- lua_State *L = y->thread;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- char *rcvd_string;
-
- int rcvd_len = 0;
-
- int tmpidx;
-
- /* set stack values, this all needs fixing... */
- for (int i = 0; i < 3; i++)
- {
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->rbuf_args[i]);
- luaL_unref(L, LUA_REGISTRYINDEX, udata->rbuf_args[i]);
- udata->rbuf_args[i] = LUA_NOREF;
- }
- if (l_nsock_checkstatus(L, nse) == NSOCK_WRAPPER_SUCCESS)
- {
-
- // l_nsock_checkstatus pushes true on the stack in case of success
- // we do this on our own here
- lua_pop(L, 1);
-
- rcvd_string = nse_readbuf(nse, &rcvd_len);
-
- if (o.scriptTrace())
- l_nsock_trace(nse_iod(nse), hexify((unsigned char *) rcvd_string,
- (size_t) rcvd_len).c_str(), FROM);
- /* push the buffer and what we received from nsock on the stack and
- * concatenate both */
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx);
- lua_pushlstring(L, rcvd_string, rcvd_len);
- lua_concat(L, 2);
- luaL_unref(L, LUA_REGISTRYINDEX, udata->bufidx);
- udata->bufidx = luaL_ref(L, LUA_REGISTRYINDEX);
- if (l_nsock_check_buf(L) == NSOCK_WRAPPER_BUFFER_MOREREAD)
- {
- /* if there wasn't enough data in the buffer and we've issued another
- * nsock_read() the next callback will schedule the script for running */
- return;
- }
- nse_restore(y->thread, 2);
- } else
- {
- if (udata->bufused > 1)
- {
- /* error occured after we read into some data into the buffer behave as
- * if there was no error and push the rest of the buffer and clean the
- * buffer afterwards */
- /* save the error message inside the buffer */
- tmpidx = luaL_ref(L, LUA_REGISTRYINDEX);
- /* pop the status (==false) of the stack */
- lua_pop(L, 1);
- lua_pushboolean(L, true);
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx);
- l_nsock_clear_buf(L, udata);
- udata->bufidx = tmpidx;
- udata->bufused = -1;
- nse_restore(y->thread, 2);
- } else
- { /* buffer should be empty */
- nse_restore(y->thread, 2);
- }
- }
-}
-
-int l_nsock_check_buf(lua_State * L)
-{
- l_nsock_udata *udata;
-
- size_t startpos, endpos, bufsize;
-
- const char *tmpbuf;
-
- int tmpidx;
-
- int keeppattern;
-
- /* should we return the string including the pattern or without it */
- keeppattern = lua_toboolean(L, -1);
- lua_pop(L, 1);
- udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
- if (lua_isfunction(L, 2))
- {
- lua_pushvalue(L, 2);
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx); /* the buffer is the
- * only argument to the
- * function */
- if (lua_pcall(L, 1, 2, 0) != 0)
- {
- lua_pushboolean(L, false);
- lua_pushfstring(L, "Error inside splitting-function: %s\n",
- lua_tostring(L, -1));
- return NSOCK_WRAPPER_BUFFER_OK;
- // luaL_error(L,"Error inside splitting-function, given as argument to
- // nsockobj:receive_buf: %s\n", lua_tostring(L,-1));
- }
- } else if (lua_isstring(L, 2))
- {
- lua_getglobal(L, "string");
- lua_getfield(L, -1, "find");
- lua_remove(L, -2); /* drop the string-table, since we don't
- * need it! */
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx);
- lua_pushvalue(L, 2); /* the pattern we are searching for */
- if (lua_pcall(L, 2, 2, 0) != 0)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Error in string.find (nsockobj:receive_buf)!");
- return NSOCK_WRAPPER_BUFFER_OK;
- }
- } else
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Expected either a function or a string!");
- return NSOCK_WRAPPER_BUFFER_OK;
- // luaL_argerror(L,2,"expected either a function or a string!");
- }
- /* the stack contains on top the indices where we want to seperate */
- if (lua_isnil(L, -1))
- { /* not found anything try to read more
- * data */
- lua_pop(L, 2);
- nsock_read(nsp, udata->nsiod, l_nsock_receive_buf_handler, udata->timeout,
- &udata->yield);
- lua_pushboolean(L, keeppattern);
- return NSOCK_WRAPPER_BUFFER_MOREREAD;
- } else
- {
- startpos = (size_t) lua_tointeger(L, -2);
- endpos = (size_t) lua_tointeger(L, -1);
- lua_settop(L, 0); /* clear the stack for returning */
- if (startpos > endpos)
- {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Delimiter has negative size!");
- return NSOCK_WRAPPER_BUFFER_OK;
- } else if (startpos == endpos)
- {
- /* if the delimter has a size of zero we keep it, since otherwise
- * retured string would be trucated */
- keeppattern = 1;
- }
- lua_settop(L, 0); /* clear the stack for returning */
- lua_rawgeti(L, LUA_REGISTRYINDEX, udata->bufidx);
- tmpbuf = lua_tolstring(L, -1, &bufsize);
- lua_pop(L, 1); /* pop the buffer off the stack, should
- * be safe since it it is still in the
- * registry */
- if (tmpbuf == NULL)
- {
- fatal
- ("%s: In: %s:%i The buffer is not a string?! - please report this to nmap-dev@insecure.org.",
- SCRIPT_ENGINE, __FILE__, __LINE__);
- }
- /* first push the remains of the buffer */
- lua_pushlstring(L, tmpbuf + endpos, (bufsize - endpos));
- tmpidx = luaL_ref(L, LUA_REGISTRYINDEX);
- lua_pushboolean(L, true);
- if (keeppattern)
- {
- lua_pushlstring(L, tmpbuf, endpos);
- } else
- {
- lua_pushlstring(L, tmpbuf, startpos - 1);
- }
- luaL_unref(L, LUA_REGISTRYINDEX, udata->bufidx);
- udata->bufidx = tmpidx;
- // l_dumpStack(L);
- return NSOCK_WRAPPER_BUFFER_OK;
- }
- assert(0);
- return 1; // unreachable
-}
-
-void l_nsock_clear_buf(lua_State * L, l_nsock_udata * udata)
-{
- luaL_unref(L, LUA_REGISTRYINDEX, udata->bufidx);
- udata->bufidx = LUA_NOREF;
- udata->bufused = 0;
-}
-
-static void l_nsock_sleep_handler(nsock_pool nsp, nsock_event nse, void *udata)
-{
- lua_State *L = (lua_State *) udata;
-
- if (lua_status(L) != LUA_YIELD) return;
-
- assert(nse_status(nse) == NSE_STATUS_SUCCESS);
- nse_restore(L, 0);
-}
-
-int l_nsock_sleep(lua_State * L)
-{
- double secs = luaL_checknumber(L, 1);
-
- int msecs;
-
- if (secs < 0)
- luaL_error(L, "Argument to sleep (%f) must not be negative\n", secs);
- /* Convert to milliseconds for nsock_timer_create. */
- msecs = (int) (secs * 1000 + 0.5);
- nsock_timer_create(nsp, l_nsock_sleep_handler, msecs, L);
-
- return nse_yield(L);
-}
-
-/****************** NCAP_SOCKET ***********************************************/
-
-/* fuckin' C++ maps stuff */
-/* here we store ncap_sockets */
-std::map < std::string, struct ncap_socket *>ncap_socket_map;
-
-/* receive sthing from socket_map */
-struct ncap_socket *ncap_socket_map_get(char *key)
-{
- std::string skey = key;
- return ncap_socket_map[skey];
-}
-
-/* set sthing on socket_map */
-void ncap_socket_map_set(char *key, struct ncap_socket *ns)
-{
- std::string skey = key;
- ncap_socket_map[skey] = ns;
- return;
-}
-
-/* receive sthing from socket_map */
-void ncap_socket_map_del(char *key)
-{
- std::string skey = key;
- ncap_socket_map.erase(skey);
- return;
-}
-
-/* (static) Dnet-like device name to Pcap-like name */
-char *dnet_to_pcap_device_name(const char *device)
-{
- static char pcapdev[128];
-
if (strcmp(device, "any") == 0)
- return strncpy(pcapdev, "any", sizeof(pcapdev));
-
+ lua_pushliteral(L, "any");
+ else
#ifdef WIN32
- /* Nmap normally uses device names obtained through dnet for interfaces, but
- * Pcap has its own naming system. So the conversion is done here */
- if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev)))
{
- /* Oh crap -- couldn't find the corresponding dev apparently. Let's just
- * go with what we have then ... */
- strncpy(pcapdev, device, sizeof(pcapdev));
+ char pcapdev[4096];
+ /* Nmap normally uses device names obtained through dnet for interfaces,
+ but Pcap has its own naming system. So the conversion is done here */
+ if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev)))
+ lua_pushstring(L, device);
+ else
+ lua_pushstring(L, pcapdev);
}
#else
- strncpy(pcapdev, device, sizeof(pcapdev));
+ lua_pushstring(L, device);
#endif
- return pcapdev;
}
-/* (LUA) Open nsock-pcap socket.
- * 1) device - dnet-style network interface name, or "any"
- * 2) snaplen - maximum number of bytes to be captured for packet
- * 3) promisc - should we set network car in promiscuous mode (0/1)
- * 4) callback- callback function, that will create hash string from packet
- * 5) bpf - berkeley packet filter, see tcpdump(8)
- * */
-static int l_nsock_pcap_open(lua_State * L)
+static int pcap_gc (lua_State *L)
{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
+ nsock_iod *nsiod = (nsock_iod *) lua_touserdata(L, 1);
+ nsi_delete(*nsiod, NSOCK_PENDING_NOTIFY);
+ *nsiod = NULL;
+ return 0;
+}
+static int l_pcap_open (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 0);
const char *device = luaL_checkstring(L, 2);
-
int snaplen = luaL_checkint(L, 3);
+ luaL_checktype(L, 4, LUA_TBOOLEAN); /* promiscuous */
+ const char *bpf = luaL_checkstring(L, 5);
- int promisc = luaL_checkint(L, 4);
+ lua_settop(L, 5);
- luaL_checktype(L, 5, LUA_TFUNCTION); /* callback function that creates hash */
- const char *bpf = luaL_checkstring(L, 6);
+ dnet_to_pcap_device_name(L, device); /* 6 */
+ lua_pushfstring(L, "%s|%d|%d|%s", lua_tostring(L, 6), snaplen,
+ lua_toboolean(L, 4), lua_tostring(L, 5)); /* 7, the pcap socket key */
- if (udata->nsiod || udata->ncap_request || udata->ncap_socket)
+ if (nu->nsiod)
+ luaL_argerror(L, 1, "socket is already open");
+
+ if (lua_objlen(L, 6) == 0)
+ luaL_argerror(L, 2, "bad device name");
+
+ lua_rawgeti(L, LUA_ENVIRONINDEX, KEY_PCAP);
+ lua_pushvalue(L, 7);
+ lua_rawget(L, -2);
+ nsock_iod *nsiod = (nsock_iod *) lua_touserdata(L, -1);
+ if (nsiod == NULL) /* does not exist */
{
- luaL_argerror(L, 1,
- "Trying to open nsock-pcap, but this connection is already opened");
- return 0;
+ nsiod = (nsock_iod *) lua_newuserdata(L, sizeof(nsock_iod));
+ luaL_getmetatable(L, NMAP_NSOCK_PCAP_SOCKET);
+ lua_setmetatable(L, -2);
+ *nsiod = nsi_new(nsp, nu);
+ lua_rawgeti(L, LUA_ENVIRONINDEX, KEY_PCAP);
+ lua_pushvalue(L, 7); /* the pcap socket key */
+ lua_pushvalue(L, -2); /* the pcap socket nsiod */
+ lua_rawset(L, -3); /* _ENV[KEY_PCAP]["dev|snap|promis|bpf"] = pcap_nsiod */
+ lua_pop(L, 1); /* KEY_PCAP */
+ lua_getfenv(L, 1); /* the socket user value */
+ lua_pushvalue(L, -2); /* the pcap socket nsiod */
+ lua_pushboolean(L, 1); /* dummy variable */
+ lua_rawset(L, -3);
+ lua_pop(L, 1); /* the socket user value */
+ char *e = nsock_pcap_open(nsp, *nsiod, lua_tostring(L, 6), snaplen,
+ lua_toboolean(L, 4), bpf);
+ if (e)
+ luaL_error(L, "%s", e);
}
- char *pcapdev = dnet_to_pcap_device_name(device);
-
- if (!strlen(device) || !strlen(pcapdev))
- {
- luaL_argerror(L, 1,
- "Trying to open nsock-pcap, but you're passing empty or wrong device name.");
- return 0;
- }
-
- lua_pop(L, 1); // pop bpf
- /* take func from top of stack and store it in the Registry */
- int hash_func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* push function on the registry-stack */
- lua_rawgeti(L, LUA_REGISTRYINDEX, hash_func_ref);
-
- struct ncap_socket *ns;
-
- /* create key */
- char key[8192];
-
- Snprintf(key, sizeof(key), "%s|%i|%i|%u|%s",
- pcapdev, snaplen, promisc, (unsigned int) strlen(bpf), bpf);
- ns = ncap_socket_map_get(key);
- if (ns == NULL)
- {
- ns = (struct ncap_socket *) safe_zalloc(sizeof(struct ncap_socket));
- ns->nsiod = nsi_new(nsp, ns);
- ns->key = strdup(key);
- /* error messages are passed here */
- char *emsg =
- nsock_pcap_open(nsp, ns->nsiod, pcapdev, snaplen, promisc, bpf);
- if (emsg)
- {
- luaL_argerror(L, 1, emsg);
- return 0;
- }
- ncap_socket_map_set(key, ns);
- }
- ns->references++;
- udata->nsiod = ns->nsiod;
- udata->ncap_socket = ns;
- udata->ncap_cback_ref = hash_func_ref;
+ nu->nsiod = *nsiod;
+ nu->is_pcap = 1;
return 0;
}
-/* (LUA) Close nsock-pcap socket.
- * */
-static int l_nsock_pcap_close(lua_State * L)
+static void pcap_receive_handler (nsock_pool nsp, nsock_event nse, void *ud)
{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
+ nse_nsock_udata *nu = (nse_nsock_udata *) ud;
+ lua_State *L = nu->thread;
- struct ncap_socket *ns = udata->ncap_socket;
-
- if (!udata->nsiod || !udata->ncap_socket)
+ assert(lua_status(L) == LUA_YIELD);
+ if (nse_status(nse) == NSE_STATUS_SUCCESS)
{
- luaL_argerror(L, 1, "Trying to close nsock-pcap, but it was never opened.");
- return 0;
- }
- if (udata->ncap_request)
- {
- luaL_argerror(L, 1, "Trying to close nsock-pcap, but it has active event.");
- return 0;
- }
+ const unsigned char *l2_data, *l3_data;
+ size_t l2_len, l3_len, packet_len;
+ struct timeval tv;
- assert(ns->references > 0);
+ nse_readpcap(nse, &l2_data, &l2_len, &l3_data, &l3_len, &packet_len, &tv);
- ns->references--;
- if (ns->references == 0)
- {
- if (ns->key) {
- ncap_socket_map_del(ns->key);
- free(ns->key);
- }
- nsi_delete(ns->nsiod, NSOCK_PENDING_NOTIFY);
- free(ns);
- }
-
- udata->nsiod = NULL;
- udata->ncap_socket = NULL;
- lua_unref(L, udata->ncap_cback_ref);
- udata->ncap_cback_ref = 0;
-
- lua_pushboolean(L, true);
- return 1;
-}
-
-/* (static) binary string to hex zero-terminated string */
-char *hex(char *str, unsigned int strsz)
-{
- static char x[] =
- { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
- 'e', 'f' };
- static char buf[2048];
-
- unsigned int i;
-
- unsigned char *s;
-
- for (i = 0, s = (unsigned char *) str; i < strsz && i < (sizeof(buf) / 2 - 1);
- i++, s++)
- {
- buf[i * 2] = x[*s / 16];
- buf[i * 2 + 1] = x[*s % 16];
- }
- buf[i * 2] = '\0';
- return (buf);
-}
-
-/****************** NCAP_REQUEST **********************************************/
-
-int ncap_restore_lua(ncap_request * nr);
-
-void ncap_request_set_result(nsock_event nse, struct ncap_request *nr);
-
-int ncap_request_set_results(nsock_event nse, const char *key);
-
-void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse,
- void *userdata);
-
-/* next map, this time it's multimap "key"(from callback)->suspended_lua_threads */
-std::multimap < std::string, struct ncap_request *>ncap_request_map;
-
-typedef std::multimap < std::string,
- struct ncap_request *>::iterator ncap_request_map_iterator;
-typedef std::pair < ncap_request_map_iterator,
- ncap_request_map_iterator > ncap_request_map_ii;
-
-/* del from multimap */
-void ncap_request_map_del(struct ncap_request *nr)
-{
- ncap_request_map_iterator i;
-
- ncap_request_map_ii ii;
-
- std::string s = nr->key;
- ii = ncap_request_map.equal_range(s);
-
- for (i = ii.first; i != ii.second; i++)
- {
- if (i->second == nr)
- {
- i->second = NULL;
- ncap_request_map.erase(i);
- return;
- }
- }
- assert(0);
-}
-
-/* add to multimap */
-void ncap_request_map_add(char *key, struct ncap_request *nr)
-{
- std::string skey = key;
- ncap_request_map.insert(std::pair < std::string, struct ncap_request *>(skey,
- nr));
- return;
-}
-
-/* (LUA) Register event that will wait for one packet matching hash.
- * It's non-blocking method of capturing packets.
- * 1) hash - hash for packet that should be matched. or empty string if you
- * want to receive first packet
- * */
-static int l_nsock_pcap_register(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- size_t testdatasz;
-
- const char *testdata = luaL_checklstring(L, 2, &testdatasz);
-
- struct timeval now = *nsock_gettimeofday();
-
- if (!udata->nsiod || !udata->ncap_socket)
- {
- luaL_argerror(L, 1,
- "You can't register to nsock-pcap if it wasn't opened.");
- return 0;
- }
- if (udata->ncap_request)
- {
- luaL_argerror(L, 1, "You are already registered to this socket.");
- return 0;
- }
-
- struct ncap_request *nr =
- (struct ncap_request *) safe_zalloc(sizeof(struct ncap_request));
-
- udata->ncap_request = nr;
-
- TIMEVAL_MSEC_ADD(nr->end_time, now, udata->timeout);
- nr->key = strdup(hex((char *) testdata, testdatasz));
- nr->yield = &udata->yield;
- set_thread(L, 1, udata);
- udata->yield.udata = udata;
- nr->ncap_cback_ref = udata->ncap_cback_ref;
- /* always create new event. */
- nr->nseid = nsock_pcap_read_packet(nsp,
- udata->nsiod, l_nsock_pcap_receive_handler, udata->timeout, nr);
-
- ncap_request_map_add(nr->key, nr);
-
- /* that's it. return to lua */
- return 0;
-}
-
-/* (LUA) After "register" use this function to block, and wait for packet.
- * If packet is already captured, this function will return immidietly.
- *
- * return values: status(true/false), capture_len/error_msg, layer2data, layer3data
- * */
-int l_nsock_pcap_receive(lua_State * L)
-{
- l_nsock_udata *udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
-
- if (!udata->nsiod || !udata->ncap_socket)
- {
- luaL_argerror(L, 1, "You can't receive to nsock-pcap if it wasn't opened.");
- return 0;
- }
- if (!udata->ncap_request)
- {
- luaL_argerror(L, 1, "You can't it's not registered");
- return 0;
- }
-
- /* and clear udata->ncap_request, we'll never,ever have access to current
- * udata during this request */
- struct ncap_request *nr = udata->ncap_request;
-
- udata->ncap_request = NULL;
- set_thread(L, 1, udata);
- udata->yield.udata = udata;
-
- /* ready to receive data? don't suspend thread */
- if (nr->received) /* data already received */
- return ncap_restore_lua(nr);
-
- /* no data yet? suspend thread */
- nr->suspended = 1;
-
- return nse_yield(L);
-}
-
-/* (free) excute callback function from lua script */
-char *ncap_request_do_callback(nsock_event nse, lua_State * L,
- int ncap_cback_ref)
-{
- const unsigned char *l2_data, *l3_data;
-
- size_t l2_len, l3_len, packet_len;
-
- nse_readpcap(nse, &l2_data, &l2_len, &l3_data, &l3_len, &packet_len, NULL);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, ncap_cback_ref);
- lua_pushnumber(L, packet_len);
- lua_pushlstring(L, (char *) l2_data, l2_len);
- lua_pushlstring(L, (char *) l3_data, l3_len);
-
- lua_call(L, 3, 1);
-
- /* get string from top of the stack */
- size_t testdatasz;
-
- const char *testdata = lua_tolstring(L, -1, &testdatasz);
-
- char *key = strdup(hex((char *) testdata, testdatasz));
-
- return key;
-}
-
-/* callback from nsock */
-void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse,
- void *userdata)
-{
- int this_event_restored = 0;
-
- struct ncap_request *nr = (struct ncap_request *) userdata;
-
- switch (nse_status(nse))
- {
- case NSE_STATUS_SUCCESS:
- {
- char *key =
- ncap_request_do_callback(nse, nr->yield->thread, nr->ncap_cback_ref);
-
- /* processes threads that receive every packet */
- this_event_restored += ncap_request_set_results(nse, "");
-
- /* process everything that matches test */
- this_event_restored += ncap_request_set_results(nse, key);
- free(key);
-
- if (!this_event_restored)
- {
- /* okay, we received event but it wasn't handled by the process that
- * requested this event. We must query for new event with smaller
- * timeout */
- struct timeval now = *nsock_gettimeofday();
-
- /* event was successfull so I assert it occured before pr->end_time */
- int timeout = TIMEVAL_MSEC_SUBTRACT(nr->end_time, now);
-
- if (timeout < 0) /* funny to receive event that should be
- * timeouted in the past. But on windows
- * it can happen */
- timeout = 0;
- nr->nseid = nsock_pcap_read_packet(nsp,
- nse_iod(nse), l_nsock_pcap_receive_handler, timeout, nr);
- /* no need to cancel or delete current nse :) */
- }
- return;
- }
- default:
- /* event timeouted */
- ncap_request_map_del(nr); /* delete from map */
- ncap_request_set_result(nse, nr);
- if (nr->suspended) /* restore thread */
- ncap_restore_lua(nr);
- return;
- }
-}
-
-/* get data from nsock_event, and set result on ncap_requests which mach key */
-int ncap_request_set_results(nsock_event nse, const char *key)
-{
- int this_event_restored = 0;
-
- std::string skey = key;
-
- ncap_request_map_iterator i;
-
- ncap_request_map_ii ii;
-
- ii = ncap_request_map.equal_range(skey);
- for (i = ii.first; i != ii.second; i++)
- {
- /* tests are successfull, so just restore process */
- ncap_request *nr = i->second;
-
- if (nr->nseid == nse_id(nse))
- this_event_restored = 1;
-
- ncap_request_set_result(nse, nr);
- if (nr->suspended)
- ncap_restore_lua(nr);
- }
- ncap_request_map.erase(ii.first, ii.second);
-
- return this_event_restored;
-}
-
-/* get data from nsock_event, and set result ncap_request */
-void ncap_request_set_result(nsock_event nse, struct ncap_request *nr)
-{
- enum nse_status status = nse_status(nse);
-
- nr->received = true;
-
- switch (status)
- {
- case NSE_STATUS_SUCCESS:
- {
- nr->r_success = true;
-
- const unsigned char *l2_data, *l3_data;
-
- size_t l2_len, l3_len, packet_len;
- struct timeval tv;
-
- nse_readpcap(nse, &l2_data, &l2_len, &l3_data, &l3_len,
- &packet_len, &tv);
- char *packet = (char *) safe_malloc(l2_len + l3_len);
-
- nr->r_layer2 = (unsigned char *) packet;
- memcpy(nr->r_layer2, l2_data, l2_len);
- nr->r_layer3 = (unsigned char *) (packet + l2_len);
- memcpy(nr->r_layer3, l3_data, l3_len);
- nr->r_layer2_len = l2_len;
- nr->r_layer3_len = l3_len;
- nr->packetsz = packet_len;
- nr->recvtime = tv;
- break;
- }
- case NSE_STATUS_ERROR:
- case NSE_STATUS_TIMEOUT:
- case NSE_STATUS_CANCELLED:
- case NSE_STATUS_KILL:
- case NSE_STATUS_EOF:
- nr->r_success = false;
- nr->r_status = strdup(nse_status2str(status));
- break;
- case NSE_STATUS_NONE:
- default:
- fatal("%s: In: %s:%i This should never happen.",
- NSOCK_WRAPPER, __FILE__, __LINE__);
- }
-
- if (nr->nseid != nse_id(nse))
- { /* different event, cancel */
- nsock_event_cancel(nsp, nr->nseid, 0); /* Don't send CANCELED event, just
- * cancel */
- nr->nseid = 0;
- } else
- { /* this event -> do nothing */
- }
-
- return;
-}
-
-/* if lua thread was suspended, restore it. If it wasn't, just return results
- * (push them on the stack and return) */
-int ncap_restore_lua(ncap_request * nr)
-{
- lua_State *L = nr->yield->thread;
-
- if (nr->r_success)
- {
- lua_pushboolean(L, true);
- lua_pushnumber(L, nr->packetsz);
- lua_pushlstring(L, (char *) nr->r_layer2, nr->r_layer2_len);
- lua_pushlstring(L, (char *) nr->r_layer3, nr->r_layer3_len);
- lua_pushnumber(L, TIMEVAL_SECS(nr->recvtime));
- } else
- {
- lua_pushnil(L);
- lua_pushstring(L, nr->r_status);
- lua_pushnil(L);
- lua_pushnil(L);
- lua_pushnil(L);
- }
- bool suspended = nr->suspended;
-
- // nr->L = NULL; // FIXME ??
- nr->ncap_cback_ref = 0; /* this ref is freed in different place
- * (on udata->ncap_cback_ref) */
- if (nr->key)
- free(nr->key);
- if (nr->r_status)
- free(nr->r_status);
- if (nr->r_layer2)
- free(nr->r_layer2);
- /* dont' free r_layer3, it's in the same block as r_layer2 */
-
- free(nr);
-
- if (suspended) /* lua process is suspended */
+ lua_pushboolean(L, 1);
+ lua_pushinteger(L, packet_len);
+ lua_pushlstring(L, (const char *) l2_data, l2_len);
+ lua_pushlstring(L, (const char *) l3_data, l3_len);
+ lua_pushnumber(L, TIMEVAL_SECS(tv));
nse_restore(L, 5);
- else /* not suspended, just pass output */
- return 5;
- return 0;
+ }
+ else
+ status(L, nse_status(nse)); /* will also restore the thread */
}
+static int l_pcap_receive (lua_State *L)
+{
+ nsock_pool nsp = get_pool(L);
+ nse_nsock_udata *nu = check_nsock_udata(L, 1, 1);
+ nu->nseid = nsock_pcap_read_packet(nsp, nu->nsiod, pcap_receive_handler,
+ nu->timeout, nu);
+ return yield(L, nu, "PCAP RECEIVE", FROM, 0, NULL);
+}
+
+LUALIB_API int luaopen_nsock (lua_State *L)
+{
+/* These two functions can be implemented in C in Lua 5.2 */
+
+ /* nsock:connect(socket, ...)
+ * This Lua function is a wrapper around the actual l_nsock_connect. The
+ * connect function must get a lock through socket_lock (C function above).
+ * Once it has the lock, it can (tail call) return the actual connect
+ * function.
+ */
+ static const char connect[] =
+"local connect, socket_lock = ...;\n"
+"return function(socket, ...)\n"
+" repeat until socket_lock(socket) == true;\n"
+" return connect(socket, ...);\n"
+"end\n";
+ static const char receive_buf[] =
+"local function receive_buf (socket, fstr, keep)\n"
+" local i, j;\n"
+" local socket_uservalue = debug.getfenv(socket);\n"
+" local buf = socket_uservalue[2];\n"
+" if type(fstr) == 'function' then\n"
+" i, j = fstr(buf);\n"
+" elseif type(fstr) == 'string' then\n"
+" i, j = string.find(buf, fstr)\n"
+" end\n"
+" if type(i) == 'number' and type(j) == 'number' then\n"
+" if i > j or j > #buf then\n"
+" error('invalid indices for match');\n"
+" else\n"
+" socket_uservalue[2] = string.sub(buf, j+1);\n"
+" if keep then\n"
+" return true, string.sub(buf, 1, j);\n"
+" else\n"
+" return true, string.sub(buf, 1, i-1);\n"
+" end\n"
+" end\n"
+" else\n"
+" local status, result = socket:receive();\n"
+" if not status then return status, result end\n"
+" socket_uservalue[2] = socket_uservalue[2]..result;\n"
+" return receive_buf(socket, fstr, keep);\n"
+" end\n"
+"end\n"
+"return receive_buf;\n";
+
+ static const luaL_Reg l_nsock[] = {
+ {"bind", l_bind},
+ {"send", l_send},
+ {"receive", l_receive},
+ {"receive_lines", l_receive_lines},
+ {"receive_bytes", l_receive_bytes},
+ /* {"receive_buf", l_receive_buf}, Lua 5.2 */
+ {"get_info", l_get_info},
+ {"close", l_close},
+ {"set_timeout", l_set_timeout},
+ {"reconnect_ssl", l_reconnect_ssl},
+ {"get_ssl_certificate", l_get_ssl_certificate},
+ {"pcap_open", l_pcap_open},
+ {"pcap_close", l_close},
+ {"pcap_receive", l_pcap_receive},
+ {NULL, NULL}
+ };
+
+ /* Set up an environment for all nsock C functions to share.
+ * This table particularly contains the THREAD_SOCKETS and
+ * CONNECT_WAITING tables.
+ * These values are accessed at the Lua pseudo-index LUA_ENVIRONINDEX.
+ */
+ lua_createtable(L, 3, 0);
+ lua_replace(L, LUA_ENVIRONINDEX);
+
+ weak_table(L, 0, MAX_PARALLELISM, "k");
+ lua_rawseti(L, LUA_ENVIRONINDEX, THREAD_SOCKETS);
+
+ weak_table(L, 0, 1000, "k");
+ lua_rawseti(L, LUA_ENVIRONINDEX, CONNECT_WAITING);
+
+ weak_table(L, 0, 0, "v");
+ lua_rawseti(L, LUA_ENVIRONINDEX, KEY_PCAP);
+
+ lua_pushcfunction(L, loop);
+ lua_setfield(L, LUA_REGISTRYINDEX, NSE_NSOCK_LOOP);
+
+ /* Load the connect function */
+ if (luaL_loadstring(L, connect) != 0)
+ assert(0);
+ lua_pushcfunction(L, l_connect);
+ lua_pushcfunction(L, socket_lock);
+ lua_call(L, 2, 1); // leave connect function on stack...
+
+ /* Create the nsock metatable for sockets */
+ luaL_newmetatable(L, NMAP_NSOCK_SOCKET);
+ lua_createtable(L, 0, 23);
+ luaL_register(L, NULL, l_nsock);
+ lua_pushvalue(L, -3); // connect function
+ lua_setfield(L, -2, "connect");
+ if (luaL_dostring(L, receive_buf))
+ assert(0);
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ lua_setfenv(L, -2);
+ lua_setfield(L, -2, "receive_buf");
+ lua_setfield(L, -2, "__index");
+ lua_pushcfunction(L, nsock_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_newtable(L);
+ lua_setfield(L, -2, "__metatable"); // protect metatable
+ lua_pop(L, 1); // nsock metatable
+
+ /* Create the nsock pcap metatable */
+ luaL_newmetatable(L, NMAP_NSOCK_PCAP_SOCKET);
+ lua_pushcfunction(L, pcap_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_pop(L, 1);
+
#if HAVE_OPENSSL
-SSL *nse_nsock_get_ssl(lua_State *L)
-{
- const l_nsock_udata *udata;
-
- udata = (l_nsock_udata *) luaL_checkudata(L, 1, "nsock");
- if (!nsi_checkssl(udata->nsiod))
- error("Socket is not an SSL socket");
-
- return (SSL *) nsi_getssl(udata->nsiod);
-}
-#else
-/* If HAVE_OPENSSL is defined, this comes from nse_ssl_cert.cc. */
-int l_get_ssl_certificate(lua_State *L)
-{
- error("Socket is not an SSL socket");
-
- return 0;
-}
+ /* Set up the SSL certificate userdata code in nse_ssl_cert.cc. */
+ nse_nsock_init_ssl_cert(L);
#endif
-/****************** DNET ******************************************************/
-static int l_dnet_open_ethernet(lua_State * L);
-static int l_dnet_close_ethernet(lua_State * L);
-static int l_dnet_send_ethernet(lua_State * L);
-static int l_dnet_open_ip(lua_State * L);
-static int l_dnet_close_ip(lua_State * L);
-static int l_dnet_send_ip(lua_State * L);
-
-static luaL_reg l_dnet[] = {
- {"ethernet_open", l_dnet_open_ethernet},
- {"ethernet_close", l_dnet_close_ethernet},
- {"ethernet_send", l_dnet_send_ethernet},
- {"ip_open", l_dnet_open_ip},
- {"ip_close", l_dnet_close_ip},
- {"ip_send", l_dnet_send_ip},
- {NULL, NULL}
-};
-
-void l_dnet_open(lua_State * L)
-{
- luaL_newmetatable(L, "dnet");
- lua_createtable(L, 0, 5);
- luaL_register(L, NULL, l_dnet);
- lua_setfield(L, -2, "__index");
- lua_pushliteral(L, "");
- lua_setfield(L, -2, "__metatable"); // protect metatable
- lua_pop(L, 1);
-}
-
-struct l_dnet_udata
-{
- char *interface;
- eth_t *eth;
- int sock; // raw ip socket
-};
-
-int l_dnet_new(lua_State * L)
-{
- struct l_dnet_udata *udata;
-
- udata =
- (struct l_dnet_udata *) lua_newuserdata(L, sizeof(struct l_dnet_udata));
- luaL_getmetatable(L, "dnet");
- lua_setmetatable(L, -2);
- udata->interface = NULL;
- udata->eth = NULL;
- udata->sock = -1;
-
- return 1;
-}
-
-int l_dnet_get_interface_link(lua_State * L)
-{
- const char *interface_name = luaL_checkstring(L, 1);
-
- struct interface_info *ii = getInterfaceByName((char *) interface_name);
-
- if (!ii)
- {
- lua_pushnil(L);
- return 1;
- }
- const char *s = NULL;
-
- switch (ii->device_type)
- {
- case devt_ethernet:
- s = "ethernet";
- break;
- case devt_loopback:
- s = "loopback";
- break;
- case devt_p2p:
- s = "p2p";
- break;
- case devt_other:
- default:
- s = NULL;
- break;
- }
- if (s)
- lua_pushstring(L, s);
- else
- lua_pushnil(L);
-
- return 1;
-}
-
-typedef struct
-{
- int references;
- eth_t *eth;
-} dnet_eth_map;
-
-std::map < std::string, dnet_eth_map * >dnet_eth_cache;
-
-eth_t *ldnet_eth_open_cached(const char *device)
-{
- assert(device && *device);
-
- std::string key = device;
- dnet_eth_map *dem = dnet_eth_cache[key];
-
- if (dem != NULL)
- {
- dem->references++;
- return dem->eth;
- }
-
- dem = (dnet_eth_map *) safe_zalloc(sizeof(dnet_eth_map));
- dem->eth = eth_open(device);
- if (!dem->eth)
- fatal("Unable to open dnet on ethernet interface %s", device);
- dem->references = 1;
- dnet_eth_cache[key] = dem;
- return dem->eth;
-}
-
-/* See the description for eth_open_cached */
-void ldnet_eth_close_cached(const char *device)
-{
- std::string key = device;
- dnet_eth_map *dem = dnet_eth_cache[key];
-
- assert(dem);
- dem->references--;
- if (dem->references == 0)
- {
- dnet_eth_cache.erase(key);
- eth_close(dem->eth);
- free(dem);
- }
- return;
-}
-
-static int l_dnet_open_ethernet(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
-
- const char *interface_name = luaL_checkstring(L, 2);
-
- struct interface_info *ii = getInterfaceByName((char *) interface_name);
-
- if (!ii || ii->device_type != devt_ethernet)
- {
- luaL_argerror(L, 2, "device is not valid ethernet interface");
- return 0;
- }
- udata->interface = strdup(interface_name);
- udata->eth = ldnet_eth_open_cached(interface_name);
-
- return 0;
-}
-
-static int l_dnet_close_ethernet(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
-
- if (!udata->interface || !udata->eth)
- {
- luaL_argerror(L, 1, "dnet is not valid opened ethernet interface");
- return 0;
- }
-
- udata->eth = NULL;
- ldnet_eth_close_cached(udata->interface);
- free(udata->interface);
- udata->interface = NULL;
- return 0;
-}
-
-static int l_dnet_send_ethernet(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
-
- size_t packetsz = 0;
-
- const char *packet = luaL_checklstring(L, 2, &packetsz);
-
- if (!udata->interface || !udata->eth)
- {
- luaL_argerror(L, 1, "dnet is not valid opened ethernet interface");
- return 0;
- }
- eth_send(udata->eth, packet, packetsz);
- return 0;
-}
-
-static int l_dnet_open_ip(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
-
- udata->sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
-
- if (udata->sock == -1) {
- lua_pushboolean(L, false);
- lua_pushfstring(L, "Failed to open raw socket: %s (errno %d)", socket_strerror(socket_errno()), socket_errno());
- return 2;
- }
-
- broadcast_socket(udata->sock);
-#ifndef WIN32
- sethdrinclude(udata->sock);
+ nsock_pool nsp = new_pool(L);
+ if (o.scriptTrace())
+ nsp_settrace(nsp, NSOCK_TRACE_LEVEL, o.getStartTime());
+#if HAVE_OPENSSL
+ /* Value speed over security in SSL connections. */
+ nsp_ssl_init_max_speed(nsp);
#endif
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
-
-static int l_dnet_close_ip(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
-
- if (udata->sock == -1) {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Raw socket all ready closed");
- return 2;
- }
-
- close(udata->sock);
-
- if (udata->eth && udata->interface) {
- ldnet_eth_close_cached(udata->interface);
- free(udata->interface);
- udata->eth = NULL;
- udata->interface = NULL;
- }
-
- lua_pushboolean(L, true);
- return 1;
-}
-
-static int l_dnet_send_ip(lua_State * L)
-{
- l_dnet_udata *udata = (l_dnet_udata *) luaL_checkudata(L, 1, "dnet");
- size_t packetsz = 0;
- const char *packet = luaL_checklstring(L, 2, &packetsz);
- char dev[16];
- int ret;
-
- if (udata->sock == -1) {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Raw socket not open to send");
- return 2;
- }
-
- if (packetsz < sizeof(struct ip)) {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Won't send: IP packet too short");
- return 2;
- }
-
- *dev = 0;
-
- if ((o.sendpref & PACKET_SEND_ETH)) {
- struct route_nfo route;
- struct sockaddr_storage srcss, dstss, *nexthop;
- struct sockaddr_in *srcsin = (struct sockaddr_in *) &srcss;
- struct sockaddr_in *dstsin = (struct sockaddr_in *) &dstss;
- struct ip *ip = (struct ip *) packet;
- u8 dstmac[6];
- eth_nfo eth;
-
- /* build sockaddr for target from user packet and determine route */
- memset(&dstss, 0, sizeof(dstss));
- dstsin->sin_family = AF_INET;
- dstsin->sin_addr.s_addr = ip->ip_dst.s_addr;
-
- if (!nmap_route_dst(&dstss, &route))
- goto usesock;
-
- strncpy(dev, route.ii.devname, sizeof(dev));
-
- if (route.ii.device_type != devt_ethernet)
- goto usesock;
-
- /* above we fallback to using the raw socket if we can't find an (ethernet)
- * route to the host. From here on out it's ethernet all the way.
- */
-
- /* build sockaddr for source from user packet to determine next hop mac */
- memset(&srcss, 0, sizeof(srcss));
- srcsin->sin_family = AF_INET;
- srcsin->sin_addr.s_addr = ip->ip_src.s_addr;
-
- if (route.direct_connect)
- nexthop = &dstss;
- else
- nexthop = &route.nexthop;
-
- if (!getNextHopMAC(route.ii.devfullname, route.ii.mac, &srcss, nexthop, dstmac)) {
- lua_pushboolean(L, false);
- lua_pushstring(L, "Failed to determine next hop MAC address");
- return 2;
- }
-
- /* Use cached ethernet device, and use udata's eth and interface to keep
- * track of if we're reusing the same device from the previous packet, and
- * close the cached device if not.
- */
- memset(ð, 0, sizeof(eth));
- memcpy(ð.srcmac, route.ii.mac, sizeof(eth.srcmac));
- memcpy(ð.dstmac, dstmac, sizeof(eth.dstmac));
- eth.ethsd = ldnet_eth_open_cached(dev);
- if (!udata->eth) {
- udata->eth = eth.ethsd;
- udata->interface = strdup(route.ii.devname);
- } else if (udata->eth != eth.ethsd) {
- ldnet_eth_close_cached(udata->interface);
- free(udata->interface);
- udata->eth = eth.ethsd;
- udata->interface = strdup(route.ii.devname);
- }
- ret = send_ip_packet(udata->sock, ð, (u8 *) packet, packetsz);
- } else {
-usesock:
-#ifdef WIN32
- if (strlen(dev))
- win32_warn_raw_sockets(dev);
-#endif
- ret = send_ip_packet(udata->sock, NULL, (u8 *) packet, packetsz);
- }
- if (ret == -1) {
- lua_pushboolean(L, false);
- lua_pushfstring(L, "Error while sending: %s (errno %d)", socket_strerror(socket_errno()), socket_errno());
- return 2;
- }
- lua_pushboolean(L, true);
- return 1;
-}
-
diff --git a/nse_nsock.h b/nse_nsock.h
index e8936809c..0193af1dc 100644
--- a/nse_nsock.h
+++ b/nse_nsock.h
@@ -1,12 +1,11 @@
#ifndef NMAP_LUA_NSOCK_H
#define NMAP_LUA_NSOCK_H
-int luaopen_nsock(lua_State *);
-int l_nsock_new(lua_State *);
-int l_nsock_sleep(lua_State *L);
+#include "nse_main.h"
-int l_dnet_new(lua_State *);
-int l_dnet_get_interface_link(lua_State *);
+LUALIB_API int luaopen_nsock (lua_State *);
+LUALIB_API int l_nsock_new (lua_State *);
+LUALIB_API int l_nsock_sleep (lua_State *);
#define NSE_NSOCK_LOOP "NSOCK_LOOP"
diff --git a/nse_utility.cc b/nse_utility.cc
new file mode 100644
index 000000000..4d20e52d1
--- /dev/null
+++ b/nse_utility.cc
@@ -0,0 +1,180 @@
+#include
+
+#include "Target.h"
+#include "portlist.h"
+
+#include "nse_main.h"
+#include "nse_utility.h"
+
+/* size_t table_length (lua_State *L, int index)
+ *
+ * Returns the length of the table at index index.
+ * This length is the number of elements, not just array elements.
+ */
+size_t table_length (lua_State *L, int index)
+{
+ size_t len = 0;
+
+ lua_pushvalue(L, index);
+ lua_pushnil(L);
+ while (lua_next(L, -2))
+ {
+ len++;
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ return len;
+}
+
+void setsfield (lua_State *L, int idx, const char *field, const char *what)
+{
+ lua_pushvalue(L, idx);
+ lua_pushstring(L, what); /* what can be NULL */
+ lua_setfield(L, -2, field);
+ lua_pop(L, 1);
+}
+
+void setnfield (lua_State *L, int idx, const char *field, lua_Number n)
+{
+ lua_pushvalue(L, idx);
+ lua_pushnumber(L, n);
+ lua_setfield(L, -2, field);
+ lua_pop(L, 1);
+}
+
+void setbfield (lua_State *L, int idx, const char *field, int b)
+{
+ lua_pushvalue(L, idx);
+ lua_pushboolean(L, b);
+ lua_setfield(L, -2, field);
+ lua_pop(L, 1);
+}
+
+int success (lua_State *L)
+{
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+int safe_error (lua_State *L, const char *message)
+{
+ lua_pushboolean(L, false);
+ lua_pushstring(L, message);
+ return 2;
+}
+
+void weak_table (lua_State *L, int narr, int nrec, const char *mode)
+{
+ lua_createtable(L, narr, nrec);
+ lua_createtable(L, 0, 1);
+ lua_pushstring(L, mode);
+ lua_setfield(L, -2, "__mode");
+ lua_setmetatable(L, -2);
+}
+
+/* const char *check_target (lua_State *L, int idx)
+ *
+ * Check for a valid target specification at index idx.
+ * This function checks for a string at idx or a table containing
+ * the typical host table fields, 'ip' and 'targetname' in particular.
+ */
+void check_target (lua_State *L, int idx, const char **address, const char **targetname)
+{
+ if (lua_istable(L, idx)) {
+ lua_getfield(L, idx, "ip");
+ *address = lua_tostring(L, -1);
+ lua_getfield(L, idx, "targetname");
+ *targetname = lua_tostring(L, -1);
+ if (address == NULL && targetname == NULL)
+ luaL_argerror(L, idx, "host table lacks 'ip' or 'targetname' fields");
+ *address = *address ? *address : *targetname;
+ lua_pop(L, 2); /* no point replacing idx, need 2 only have 1 */
+ } else {
+ *address = *targetname = luaL_checkstring(L, idx);
+ }
+}
+
+/* unsigned short check_port (lua_State *L, int idx)
+ *
+ * Check for a valid port specification at index idx.
+ */
+unsigned short check_port (lua_State *L, int idx, const char **protocol)
+{
+ unsigned short port;
+
+ if (lua_istable(L, idx)) {
+ lua_getfield(L, idx, "number");
+ if (!lua_isnumber(L, -1))
+ luaL_argerror(L, idx, "port table lacks numeric 'number' field");
+ port = (unsigned short) lua_tointeger(L, -1);
+ lua_getfield(L, idx, "protocol");
+ *protocol = lua_tostring(L, -1);
+ lua_pop(L, 2);
+ } else {
+ port = (unsigned short) luaL_checkint(L, idx);
+ }
+ return port;
+}
+
+/* Target *get_target (lua_State *L, int index)
+ *
+ * This function checks the value at index for a valid host table. It locates
+ * the associated Target (C++) class object associated with the host and
+ * returns it. If the Target is not being scanned then an error will be raised.
+ */
+Target *get_target (lua_State *L, int index)
+{
+ int top = lua_gettop(L);
+ Target *target;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "targetname");
+ lua_getfield(L, index, "ip");
+ if (!(lua_isstring(L, -2) || lua_isstring(L, -1)))
+ luaL_error(L, "host table does not have a 'ip' or 'targetname' field");
+ if (lua_isstring(L, -2)) /* targetname */
+ {
+ nse_gettarget(L, -2); /* use targetname */
+ if (lua_islightuserdata(L, -1))
+ goto done;
+ else
+ lua_pop(L, 1);
+ }
+ if (lua_isstring(L, -1)) /* ip */
+ nse_gettarget(L, -1); /* use ip */
+ if (!lua_islightuserdata(L, -1))
+ luaL_argerror(L, 1, "host is not being processed right now");
+done:
+ target = (Target *) lua_touserdata(L, -1);
+ lua_settop(L, top); /* reset stack */
+ return target;
+}
+
+/* Target *get_port (lua_State *L, Target *target, Port *port, int index)
+ *
+ * This function checks the value at index for a valid port table. It locates
+ * the associated Port (C++) class object associated with the host and
+ * returns it.
+ */
+Port *get_port (lua_State *L, Target *target, Port *port, int index)
+{
+ Port *p = NULL;
+ int portno, protocol;
+ luaL_checktype(L, index, LUA_TTABLE);
+ lua_getfield(L, index, "number");
+ if (!lua_isnumber(L, -1))
+ luaL_error(L, "port 'number' field must be a number");
+ lua_getfield(L, index, "protocol");
+ if (!lua_isstring(L, -1))
+ luaL_error(L, "port 'protocol' field must be a string");
+ portno = (int) lua_tointeger(L, -2);
+ protocol = strcmp(lua_tostring(L, -1), "tcp") == 0 ? IPPROTO_TCP :
+ strcmp(lua_tostring(L, -1), "udp") == 0 ? IPPROTO_UDP :
+ strcmp(lua_tostring(L, -1), "sctp") == 0 ? IPPROTO_SCTP :
+ luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\"");
+ while ((p = target->ports.nextPort(p, port, protocol, PORT_UNKNOWN)) != NULL)
+ if (p->portno == portno)
+ break;
+ lua_pop(L, 2);
+ return p;
+}
diff --git a/nse_utility.h b/nse_utility.h
new file mode 100644
index 000000000..1718b598f
--- /dev/null
+++ b/nse_utility.h
@@ -0,0 +1,19 @@
+#ifndef NMAP_NSE_UTILITY_H
+#define NMAP_NSE_UTILITY_H
+
+size_t table_length (lua_State *, int);
+void setsfield (lua_State *, int, const char *, const char *);
+void setnfield (lua_State *, int, const char *, lua_Number);
+void setbfield (lua_State *, int, const char *, int);
+void weak_table (lua_State *, int, int, const char *);
+
+int success (lua_State *);
+int safe_error (lua_State *, const char *);
+
+void check_target (lua_State *, int, const char **, const char **);
+unsigned short check_port (lua_State *, int, const char **);
+
+Target *get_target (lua_State *, int);
+Port *get_port (lua_State *, Target *, Port *, int);
+
+#endif
diff --git a/nselib/dhcp.lua b/nselib/dhcp.lua
index b30ae09f5..3c9ba2322 100644
--- a/nselib/dhcp.lua
+++ b/nselib/dhcp.lua
@@ -35,12 +35,6 @@ request_types_str[6] = "DHCPNAK"
request_types_str[7] = "DHCPRELEASE"
request_types_str[8] = "DHCPINFORM"
--- This pulls back 4 bytes in the packet that correspond to the transaction id. This should be randomly
--- generated and different for every instance of a script (to prevent collisions)
-pcap_callback = function(packetsz, layer2, layer3)
- return string.sub(layer3, 33, 36)
-end
-
---Read an IP address or a list of IP addresses. Print an error if the length isn't a multiple of 4.
--
--@param data The packet.
@@ -369,9 +363,8 @@ local function dhcp_send(interface, host, packet, transaction_id)
-- Create a pcap socket to listen for the response. I used to consider this a hack, but
-- it really isn't -- it's kinda how this has to be done.
local pcap = nmap.new_socket()
- pcap:pcap_open(interface, 590, 0, pcap_callback, "udp port 68")
+ pcap:pcap_open(interface, 590, false, "udp port 68")
pcap:set_timeout(5000)
- pcap:pcap_register(transaction_id)
stdnse.print_debug(1, "dhcp: Starting listener")
-- Create the UDP socket (TODO: enable SO_BROADCAST if we need to)
@@ -386,7 +379,12 @@ local function dhcp_send(interface, host, packet, transaction_id)
socket:send(packet)
-- Read the response
- local status, err, _, data = pcap:pcap_receive()
+ local status, length, layer2, layer3 = pcap:pcap_receive();
+ -- This pulls back 4 bytes in the packet that correspond to the transaction id. This should be randomly
+ -- generated and different for every instance of a script (to prevent collisions)
+ while status and layer3:sub(33, 36) ~= transaction_id do
+ status, length, layer2, layer3 = pcap:pcap_receive();
+ end
if(status == false) then
stdnse.print_debug(1, "dhcp: Error calling pcap_receive(): %s", err)
return false, "Error calling pcap_receive(): " .. err
diff --git a/nselib/nmap.luadoc b/nselib/nmap.luadoc
index 7925af3f7..b6dda959c 100644
--- a/nselib/nmap.luadoc
+++ b/nselib/nmap.luadoc
@@ -483,8 +483,7 @@ function receive_bytes(n)
-- delimiter string (or matches the function passed in). This function
-- continues to read from the network until the delimiter is found or the
-- function times out. If data is read beyond the delimiter, that data is
--- saved in a buffer for the next call to receive_buf. This
--- buffer is cleared on subsequent calls to other Network I/O API functions.
+-- saved in a buffer for the next call to receive_buf.
--
-- The first argument may be either a pattern or a function. If a pattern, that
-- pattern is used to separate the data. If a function, it must take exactly
@@ -501,12 +500,7 @@ function receive_bytes(n)
--
-- On success the function returns true along with the received data. On failure
-- the function returns false or nil along with an
--- error string. Possible error messages are the same as those that the other
--- receive functions can return, with the addition of
--- * "Error inside splitting-function": The first argument was a function which caused an error while being called.
--- * "Error in string.find (nsockobj:receive_buf)!": A string was provided as the first argument, and string.find() yielded an error while being called.
--- * "Expected either a function or a string!": The first argument was neither a function nor a string.
--- * "Delimiter has negative size!": The returned start offset is greater than the end offset.
+-- receive error string. This function may also throw errors for incorrect usage.
-- @param delimiter A Lua pattern or a function with return values like those of
-- string.find.
-- @param keeppattern Whether to return the delimiter string with any returned
@@ -565,37 +559,19 @@ function set_timeout(t)
--- Opens a socket for raw packet capture.
--
--- The callback function is a function that receives a packet with headers and
--- computes a "packet hash", some value derived from the packet. For example,
--- the callback function could extract the source IP address from a packet. The
--- hash of each packet received is compared against all the strings registered
--- with the pcap_register function.
-- @param device The dnet-style interface name of the device you want to capture
-- from.
-- @param snaplen The length of each packet you want to capture (similar to the
-- -s option to tcpdump)
-- @param promisc Set to 1 if the interface should activate promiscuous mode,
-- and 0 otherwise.
--- @param test_function Callback function used to compute the packet hash.
-- @param bpf A string describing a Berkeley Packet Filter expression (like
-- those provided to tcpdump).
--- @see new_socket, pcap_register, pcap_receive
+-- @see new_socket, pcap_receive
-- @usage
-- local socket = nmap.new_socket()
--- socket:pcap_open("eth0", 64, 0, callback, "tcp")
-function pcap_open(device, snaplen, promisc, test_function, bpf)
-
---- Starts listening for incoming packets.
---
--- The provided packet_hash is a binary string which has to match
--- the hash returned by the test_function parameter provided to
--- pcap_open. If you want to receive all packets, just provide
--- the empty string (""). There has to be a call to
--- pcap_register before a call to pcap_receive.
--- @param packet_hash A binary string that is compared against packet hashes.
--- @see pcap_open, pcap_receive
--- @usage socket:pcap_register("")
-function pcap_register(packet_hash)
+-- socket:pcap_open("eth0", 64, false, "tcp")
+function pcap_open(device, snaplen, promisc, bpf)
--- Receives a captured packet.
--
@@ -609,7 +585,7 @@ function pcap_register(packet_hash)
-- @return Data from the second OSI layer (e.g. ethernet headers).
-- @return Data from the third OSI layer (e.g. IPv4 headers).
-- @return Packet capture time, as floating point seconds since the epoch
--- @see pcap_open, pcap_register
+-- @see pcap_open
-- @usage status, plen, l2_data, l3_data, time = socket:pcap_receive()
function pcap_receive()
diff --git a/nselib/ssh1.lua b/nselib/ssh1.lua
index 784bd4497..f1dcee764 100644
--- a/nselib/ssh1.lua
+++ b/nselib/ssh1.lua
@@ -25,13 +25,14 @@ require "openssl"
-- @return packet_length, packet_length or nil
-- the return is similar to the lua function string:find()
check_packet_length = function( buffer )
+ if #buffer < 4 then return nil end
local payload_length, packet_length, offset
offset, payload_length = bin.unpack( ">I", buffer )
local padding = 8 - payload_length % 8
assert(payload_length)
- packet_length = buffer:len()
- if payload_length + 4 + padding > packet_length then return nil end
- return packet_length, packet_length
+ local total = 4+payload_length+padding;
+ if total > #buffer then return nil end
+ return total, total;
end
--- Receives a complete SSH packet, even if fragmented
@@ -43,7 +44,7 @@ end
-- @return status True or false
-- @return packet The packet received
receive_ssh_packet = function( socket )
- local status, packet = socket:receive_buf(check_packet_length)
+ local status, packet = socket:receive_buf(check_packet_length, true)
return status, packet
end
@@ -76,7 +77,7 @@ fetch_host_key = function(host, port)
padding = 8 - packet_length % 8
offset = offset + padding
- if padding + packet_length + 4 == data:len() then
+ if padding + packet_length + 4 == #data then
-- seems to be a proper SSH1 packet
local msg_code,host_key_bits,exp,mod,length,fp_input
offset, msg_code = bin.unpack( ">c", data, offset )
diff --git a/nselib/ssh2.lua b/nselib/ssh2.lua
index 802820a1c..06720910d 100644
--- a/nselib/ssh2.lua
+++ b/nselib/ssh2.lua
@@ -29,11 +29,12 @@ local SSH2
-- @return packet_length, packet_length or nil
-- the return is similar to the lua function string:find()
check_packet_length = function( buffer )
+ if #buffer < 4 then return nil end -- not enough data in buffer for int
local packet_length, offset
offset, packet_length = bin.unpack( ">I", buffer )
assert(packet_length)
if packet_length + 4 > buffer:len() then return nil end
- return packet_length, packet_length
+ return packet_length+4, packet_length+4
end
--- Receives a complete SSH packet, even if fragmented
@@ -45,7 +46,7 @@ end
-- @return status True or false
-- @return packet The packet received
transport.receive_packet = function( socket )
- local status, packet = socket:receive_buf(check_packet_length)
+ local status, packet = socket:receive_buf(check_packet_length, true)
return status, packet
end
@@ -78,7 +79,9 @@ end
-- @return Payload of the SSH-2 packet.
transport.payload = function( packet )
local packet_length, padding_length, payload_length, payload, offset
- offset, packet_length, padding_length = bin.unpack( ">Ic", packet )
+ offset, packet_length = bin.unpack( ">I", packet )
+ packet = packet:sub(offset);
+ offset, padding_length = bin.unpack( ">c", packet )
assert(packet_length and padding_length)
payload_length = packet_length - padding_length - 1
if packet_length ~= packet:len() then
diff --git a/scripts/firewalk.nse b/scripts/firewalk.nse
index 6751e6fdd..7874d18e2 100644
--- a/scripts/firewalk.nse
+++ b/scripts/firewalk.nse
@@ -84,13 +84,6 @@ local checkpkt = function(reply, orig)
return true
end
---- pcap callback
--- @return destination ip address, the ip protocol and icmp type
-local callback = function(size, layer2, layer3)
- local ip = packet.Packet:new(layer3, layer3:len())
- return bin.pack('ACC', ip.ip_bin_dst, ip.ip_p, ip.icmp_type)
-end
-
--- set destination port and ip ttl to a generic tcp packet
-- @param ip the ip object
-- @param dport the layer 4 destination port
@@ -274,6 +267,13 @@ local portrange = function(ports)
return stdnse.strjoin(",", strrange)
end
+--- pcap check function
+-- @return destination ip address, the ip protocol and icmp type
+local function check (size, layer2, layer3)
+ local ip = packet.Packet:new(layer3, layer3:len())
+ return bin.pack('ACC', ip.ip_bin_dst, ip.ip_p, ip.icmp_type)
+end
+
-- main firewalking logic
action = function(host)
local sock = nmap.new_dnet()
@@ -290,7 +290,7 @@ action = function(host)
end
-- filter for incoming icmp time exceeded replies
- pcap:pcap_open(host.interface, 104, 0, callback, "icmp and dst host " .. saddr)
+ pcap:pcap_open(host.interface, 104, false, "icmp and dst host " .. saddr)
try(sock:ip_open())
@@ -309,11 +309,14 @@ action = function(host)
while retry < MAX_RETRIES do
try(sock:ip_send(pkt.buf))
- pcap:pcap_register(bin.pack('ACC', pkt.ip_bin_src, packet.IPPROTO_ICMP, ICMP_TIME_EXCEEDED))
- local status, _, _, rep = pcap:pcap_receive()
+ local status, length, layer2, layer3 = pcap:pcap_receive();
+ local test = bin.pack('ACC', pkt.ip_bin_src, packet.IPPROTO_ICMP, ICMP_TIME_EXCEEDED);
+ while status and test ~= check(length, layer2, layer3) do
+ status, length, layer2, layer3 = pcap:pcap_receive();
+ end
if status then
- if checkpkt(rep, pkt) then
+ if checkpkt(layer3, pkt) then
stdnse.print_debug(1, "Firewalk: discovered fwd port " .. port)
table.insert(fwdports, port)
break
diff --git a/scripts/ipidseq.nse b/scripts/ipidseq.nse
index 01d262a12..b8dba5cf4 100644
--- a/scripts/ipidseq.nse
+++ b/scripts/ipidseq.nse
@@ -33,9 +33,9 @@ require 'packet'
local NUMPROBES = 6
---- Pcap callback
+--- Pcap check function
-- @return Destination and source IP addresses and TCP ports
-local callback = function(size, layer2, layer3)
+local function check (size, layer2, layer3)
local ip = packet.Packet:new(layer3, layer3:len())
return bin.pack('AA=S=S', ip.ip_bin_dst, ip.ip_bin_src, ip.tcp_dport, ip.tcp_sport)
end
@@ -222,7 +222,7 @@ action = function(host)
try = nmap.new_try(function() sock:ip_close() end)
- pcap:pcap_open(host.interface, 104, 0, callback, "tcp and dst host " .. saddr .. " and src host " .. daddr .. " and src port " .. port)
+ pcap:pcap_open(host.interface, 104, false, "tcp and dst host " .. saddr .. " and src host " .. daddr .. " and src port " .. port)
pcap:set_timeout(host.times.timeout * 1000)
@@ -231,12 +231,14 @@ action = function(host)
while i <= NUMPROBES do
try(sock:ip_send(tcp.buf))
- pcap:pcap_register(bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport))
-
- local status, len, _, pkt = pcap:pcap_receive()
+ local status, len, layer2, layer3 = pcap:pcap_receive()
+ local test = bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport)
+ while status and test ~= check(len, layer2, layer3) do
+ status, len, layer2, layer3 = pcap:pcap_receive()
+ end
if status then
- table.insert(ipids, packet.u16(pkt, 4))
+ table.insert(ipids, packet.u16(layer3, 4))
end
updatepkt(tcp)
diff --git a/scripts/path-mtu.nse b/scripts/path-mtu.nse
index 8d8612eed..d8b713710 100644
--- a/scripts/path-mtu.nse
+++ b/scripts/path-mtu.nse
@@ -145,7 +145,7 @@ end
-- This is all we can use since we can get various protocols back from
-- different hosts
-local callback = function(size, layer2, layer3)
+local function check (size, layer2, layer3)
local ip = packet.Packet:new(layer3, layer3:len())
return bin.pack('A', ip.ip_bin_dst)
end
@@ -306,7 +306,7 @@ action = function(host)
try = nmap.new_try(function() sock:ip_close() end)
- pcap:pcap_open(host.interface, 104, 0, callback, "dst host " .. saddr .. " and (icmp or (" .. proto .. " and src host " .. daddr .. " and src port " .. port .. "))")
+ pcap:pcap_open(host.interface, 104, false, "dst host " .. saddr .. " and (icmp or (" .. proto .. " and src host " .. daddr .. " and src port " .. port .. "))")
-- Since we're sending potentially large amounts of data per packet,
-- simply bump up the host's calculated timeout value. Most replies
@@ -337,12 +337,14 @@ action = function(host)
end
end
- pcap:pcap_register(bin.pack('A', pkt.ip_bin_src))
-
- status, _, _, ip = pcap:pcap_receive()
+ local test = bin.pack('A', pkt.ip_bin_src)
+ local status, length, layer2, layer3 = pcap:pcap_receive()
+ while status and test ~= check(length, layer2, layer3) do
+ status, length, layer2, layer3 = pcap:pcap_receive()
+ end
if status then
- local t, v = checkpkt(ip, pkt)
+ local t, v = checkpkt(layer3, pkt)
if t == "gotreply" then
gotit = true
break
diff --git a/scripts/qscan.nse b/scripts/qscan.nse
index a26585ade..f0d06f7ba 100644
--- a/scripts/qscan.nse
+++ b/scripts/qscan.nse
@@ -157,9 +157,9 @@ local tstat = function(n1, n2, u1, u2, v1, v2)
return math.abs(u1 - u2) / math.sqrt(a * (b / dof))
end
---- Pcap callback
+--- Pcap check
-- @return Destination and source IP addresses and TCP ports
-local callback = function(size, layer2, layer3)
+local function check (size, layer2, layer3)
local ip = packet.Packet:new(layer3, layer3:len())
return bin.pack('AA=S=S', ip.ip_bin_dst, ip.ip_bin_src, ip.tcp_dport, ip.tcp_sport)
end
@@ -418,7 +418,7 @@ action = function(host)
local conf, delay, numtrips = try(getopts())
- pcap:pcap_open(host.interface, 104, 0, callback, "tcp and dst host " .. saddr .. " and src host " .. daddr)
+ pcap:pcap_open(host.interface, 104, false, "tcp and dst host " .. saddr .. " and src host " .. daddr)
try(sock:ip_open())
@@ -452,15 +452,17 @@ action = function(host)
stats[j].fam = -1
end
- pcap:pcap_register(bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport))
-
start = stdnse.clock_us()
try(sock:ip_send(tcp.buf))
stats[j].sent = stats[j].sent + 1
- local status, len, _, pkt, stop = pcap:pcap_receive()
+ local test = bin.pack('AA=S=S', tcp.ip_bin_src, tcp.ip_bin_dst, tcp.tcp_sport, tcp.tcp_dport)
+ local status, length, layer2, layer3, stop = pcap:pcap_receive()
+ while status and test ~= check(length, layer2, layer3) do
+ status, length, layer2, layer3, stop = pcap:pcap_receive()
+ end
if not stop then
-- probably a timeout, just grab current time
diff --git a/scripts/sniffer-detect.nse b/scripts/sniffer-detect.nse
index 89d2ec596..94ed82944 100644
--- a/scripts/sniffer-detect.nse
+++ b/scripts/sniffer-detect.nse
@@ -24,14 +24,13 @@ hostrule = function(host)
nmap.get_interface_link(host.interface) == 'ethernet'
end
-callback = function(packetsz, layer2, layer3)
+local function check (packetsz, layer2, layer3)
return string.sub(layer2, 0, 12)
end
do_test = function(dnet, pcap, host, test)
- local _
- local status
+ local status, length, layer2, layer3
local i = 0
-- ARP requests are send with timeouts: 10ms, 40ms, 90ms
@@ -41,15 +40,21 @@ do_test = function(dnet, pcap, host, test)
-- flush buffers :), wait quite long.
repeat
pcap:set_timeout(100)
- pcap:pcap_register(host.mac_addr_src .. host.mac_addr)
- status ,_,_,_ = pcap:pcap_receive()
+ local test = host.mac_addr_src .. host.mac_addr
+ status, length, layer2, layer3 = pcap:pcap_receive()
+ while status and test ~= check(length, layer2, layer3) do
+ status, length, layer2, layer3 = pcap:pcap_receive()
+ end
until status ~= true
pcap:set_timeout(10 * i*i)
- pcap:pcap_register(host.mac_addr_src .. host.mac_addr)
dnet:ethernet_send(test)
- status ,_,_,_ = pcap:pcap_receive()
+ local test = host.mac_addr_src .. host.mac_addr
+ status, length, layer2, layer3 = pcap:pcap_receive()
+ while status and test ~= check(length, layer2, layer3) do
+ status, length, layer2, layer3 = pcap:pcap_receive()
+ end
if status == true then
-- the basic idea, was to inform user about time, when we got packet
-- so that 1 would mean (0-10ms), 2=(10-40ms) and 3=(40ms-90ms)
@@ -79,7 +84,7 @@ action = function(host)
}
dnet:ethernet_open(host.interface)
- pcap:pcap_open(host.interface, 64, 0, callback, "arp")
+ pcap:pcap_open(host.interface, 64, false, "arp")
local test_static = host.mac_addr_src ..
string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) ..