diff -NraupbwB soc07-5184/nse_init.cc soc07-nse-pcap/nse_init.cc --- soc07-5184/nse_init.cc 2007-07-10 18:15:14.000000000 +0200 +++ soc07-nse-pcap/nse_init.cc 2007-07-11 23:06:41.000000000 +0200 @@ -8,6 +8,8 @@ #include "nbase.h" +#include "nse_nsock.h" + #include "nmap.h" #include "nmap_error.h" #include "NmapOps.h" diff -NraupbwB soc07-5184/nse_init.cc.orig soc07-nse-pcap/nse_init.cc.orig --- soc07-5184/nse_init.cc.orig 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nse_init.cc.orig 2007-07-10 18:15:14.000000000 +0200 @@ -0,0 +1,703 @@ +#include "nse_init.h" +#include "nse_nmaplib.h" +#include "nse_macros.h" +#include "nse_debug.h" + +// 3rd Party libs +#include "nse_pcrelib.h" + +#include "nbase.h" + +#include "nmap.h" +#include "nmap_error.h" +#include "NmapOps.h" + +#ifndef WIN32 + #include "dirent.h" +#endif + +#include "errno.h" + +#include +int init_setlualibpath(lua_State* l); +int init_loadfile(lua_State* l, char* filename); +int init_loaddir(lua_State* l, char* dirname); +int init_loadcategories(lua_State* l, std::vector categories, std::vector &unusedTags); +int init_scandir(char* dirname, std::vector& result, int files_or_dirs); +int init_fetchfile(char *result, size_t result_max_len, char* file); +int init_updatedb(lua_State* l); +int init_pick_default_categories(std::vector& chosenScripts); + +int check_extension(const char* ext, const char* path); + +extern NmapOps o; + +/* open the standard libs */ +int init_lua(lua_State* l) { + + const luaL_Reg lualibs[] = { + {"", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {NSE_PCRELIBNAME, luaopen_pcrelib}, + {NULL, NULL} + }; + + const luaL_Reg* lib; + for (lib = lualibs; lib->func; lib++) { + lua_pushcfunction(l, lib->func); + lua_pushstring(l, lib->name); + SCRIPT_ENGINE_LUA_TRY(lua_pcall(l, 1, 0, 0)); + } + + + /* publish the nmap bindings to the script */ + lua_newtable(l); + SCRIPT_ENGINE_TRY(set_nmaplib(l)); + lua_setglobal(l, "nmap"); + SCRIPT_ENGINE_TRY(init_setlualibpath(l)); + + return SCRIPT_ENGINE_SUCCESS; +} + +/*sets two variables, which control where lua looks for modules (implemented in C or lua */ +int init_setlualibpath(lua_State* l){ + char path[MAX_FILENAME_LEN]; + const char*oldpath, *oldcpath; + std::string luapath, luacpath; + /* set the path lua searches for modules*/ + if(nmap_fetchfile(path, MAX_FILENAME_LEN, SCRIPT_ENGINE_LIB_DIR)!=2){ + /*SCRIPT_ENGINE_LIB_DIR is not a directory - error */ + error("%s: %s not a directory\n", SCRIPT_ENGINE, SCRIPT_ENGINE_LIB_DIR); + return SCRIPT_ENGINE_ERROR; + } + /* the path lua uses to search for modules is setted to the + * SCRIPT_ENGINE_LIBDIR/ *.lua with the default path + * (which is read from the package-module) appended - + * the path for C-modules is as above but it searches for shared libs (*.so) */ + luapath= std::string(path) + "?.lua;"; +#ifdef WIN32 + luacpath= std::string(path) + "?.dll;"; +#else + luacpath= std::string(path) + "?.so;"; +#endif + + lua_getglobal(l,"package"); + if(!lua_istable(l,-1)){ + error("%s: the lua global-variable package is not a table?!", SCRIPT_ENGINE); + return SCRIPT_ENGINE_ERROR; + } + lua_getfield(l,-1, "path"); + lua_getfield(l,-2, "cpath"); + if(!lua_isstring(l,-1)||!lua_isstring(l,-2)){ + error("%s: no default paths setted in package table (needed in %s at line %d) -- probably a problem of the lua-configuration?!", SCRIPT_ENGINE, __FILE__, __LINE__); + return SCRIPT_ENGINE_ERROR; + } + oldcpath= lua_tostring(l,-1); + oldpath = lua_tostring(l,-2); + luacpath= luacpath + oldcpath; + luapath= luapath + oldpath; + lua_pop(l,2); + lua_pushstring(l, luapath.c_str()); + lua_setfield(l, -2, "path"); + lua_pushstring(l, luacpath.c_str()); + lua_setfield(l, -2, "cpath"); + lua_getfield(l,-1, "path"); + lua_getfield(l,-2, "cpath"); + SCRIPT_ENGINE_DEBUGGING(log_write(LOG_STDOUT, "%s: Using %s to search for C-modules and %s for Lua-modules\n", SCRIPT_ENGINE, lua_tostring(l,-1), lua_tostring(l,-2));) + /*pop the two strings (luapath and luacpath) and the package table off + * the stack */ + lua_pop(l,3); + return SCRIPT_ENGINE_SUCCESS; +} + +/* if there were no command line arguments specifying + * which scripts should be run, a default script set is + * chosen + * otherwise the script locators given at the command line + * (either directories with lua files or lua files) are + * loaded + * */ +int init_rules(lua_State* l, std::vector chosenScripts) { + char path[MAX_FILENAME_LEN]; + int type; + char* c_iter; + std::vector unusedTags; + + lua_newtable(l); + lua_setglobal(l, PORTTESTS); + + lua_newtable(l); + lua_setglobal(l, HOSTTESTS); + + SCRIPT_ENGINE_TRY(init_pick_default_categories(chosenScripts)); + + // we try to interpret the choices as categories + SCRIPT_ENGINE_TRY(init_loadcategories(l, chosenScripts, unusedTags)); + + // if there's more, we try to interpret as directory or file + std::vector::iterator iter; + bool extension_not_matched = false; + for(iter = unusedTags.begin(); iter != unusedTags.end(); iter++) { + + c_iter = strdup((*iter).c_str()); + type = init_fetchfile(path, sizeof(path), c_iter); + free(c_iter); + + switch(type) { + case 0: // no such path + error("%s: No such category, file or directory: '%s'", SCRIPT_ENGINE, (*iter).c_str()); + return SCRIPT_ENGINE_ERROR; + break; + case 1: // nmap_fetchfile returned a file + if(check_extension(SCRIPT_ENGINE_EXTENSION, path) != MATCH + && extension_not_matched == false) { + error("%s: Warning: Loading '%s' - the recommended file extension is '.nse'.", + SCRIPT_ENGINE, path); + extension_not_matched = true; + } + SCRIPT_ENGINE_TRY(init_loadfile(l, path)); + break; + case 2: // nmap_fetchfile returned a dir + SCRIPT_ENGINE_TRY(init_loaddir(l, path)); + break; + default: + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + } + } + + // Compute some stats + SCRIPT_ENGINE_DEBUGGING( + int rules_count; + + lua_getglobal(l, HOSTTESTS); + rules_count = lua_objlen(l, -1); + + lua_getglobal(l, PORTTESTS); + rules_count += lua_objlen(l, -1); + lua_pop(l, 2); + log_write(LOG_STDOUT, "%s: Initialized %d rules\n", SCRIPT_ENGINE, rules_count); + ) + + return SCRIPT_ENGINE_SUCCESS; +} + +class ExtensionalCategory { +public: + std::string category; + int option; + + ExtensionalCategory(std::string _category, int _option) { + category = _category; + option = _option; + } +}; + +int init_pick_default_categories(std::vector& chosenScripts) { + std::vector reserved_categories; + std::vector::iterator rcat_iter; + + reserved_categories.push_back(ExtensionalCategory(std::string("version"), o.scriptversion)); + + // if they tried to explicitely select an implicit category, we complain + if(o.script) { + for( rcat_iter = reserved_categories.begin(); + rcat_iter != reserved_categories.end(); + rcat_iter++) { + if( (*rcat_iter).option == 0 + && std::find( + chosenScripts.begin(), + chosenScripts.end(), + (*rcat_iter).category) != chosenScripts.end()) + fatal("%s: specifying the \"%s\" category explicitely is not allowed.", + SCRIPT_ENGINE, (*rcat_iter).category.c_str()); + } + } + + // if no scripts were chosen, we use a default set + if( (o.script == 1 + && chosenScripts.size() == 0) ) + { + chosenScripts.push_back(std::string("safe")); + chosenScripts.push_back(std::string("intrusive")); + // chosenScripts.push_back(std::string("vulnerabilities")); + } + + // we append the implicitely selected categories + for( rcat_iter = reserved_categories.begin(); + rcat_iter != reserved_categories.end(); + rcat_iter++) { + if((*rcat_iter).option == 1) + chosenScripts.push_back((*rcat_iter).category); + } + + return SCRIPT_ENGINE_SUCCESS; +} + +int init_updatedb(lua_State* l) { + char path[MAX_FILENAME_LEN]; + FILE* scriptdb; + std::vector files; + std::vector::iterator iter; + char* c_iter; + + if(nmap_fetchfile(path, sizeof(path)-sizeof(SCRIPT_ENGINE_DATABASE)-1, SCRIPT_ENGINE_LUA_DIR) == 0) { + error("%s: Couldn't find '%s'\n.", SCRIPT_ENGINE, SCRIPT_ENGINE_LUA_DIR); + return SCRIPT_ENGINE_ERROR; + } + + SCRIPT_ENGINE_TRY(init_scandir(path, files, FILES)); + + // we rely on the fact that nmap_fetchfile returned a string which leaves enough room + // to append the db filename (see call to nmap_fetchfile above) + strncat(path, SCRIPT_ENGINE_DATABASE, MAX_FILENAME_LEN-1); + + scriptdb = fopen(path, "w"); + if(scriptdb == NULL) { + error("%s: Could not open '%s' for writing: %s", + SCRIPT_ENGINE, path, strerror(errno)); + return SCRIPT_ENGINE_ERROR; + } + + SCRIPT_ENGINE_DEBUGGING( + log_write(LOG_STDOUT, "%s: Trying to add %d scripts to the database.\n", + SCRIPT_ENGINE, (int) files.size()); + ) + + lua_newtable(l); + /*give the script global namespace access*/ + lua_newtable(l); + lua_getglobal(l, "_G"); + lua_setfield(l, -2, "__index"); + lua_setmetatable(l, -2); + + for(iter = files.begin(); iter != files.end(); iter++) { + c_iter = strdup((*iter).c_str()); + if(check_extension(SCRIPT_ENGINE_EXTENSION, c_iter) == MATCH + && strstr(c_iter, SCRIPT_ENGINE_DATABASE) == NULL) { + + SCRIPT_ENGINE_LUA_TRY(luaL_loadfile(l, c_iter)); + lua_pushvalue(l, -2); + lua_setfenv(l, -2); + SCRIPT_ENGINE_LUA_TRY(lua_pcall(l, 0, 0, 0)); + + lua_getfield(l, -1, "categories"); + if(lua_isnil(l, -1)) { + error("%s: Script '%s' does not contain any category categories.", SCRIPT_ENGINE, c_iter); + return SCRIPT_ENGINE_ERROR; + } + + lua_pushnil(l); + while(lua_next(l, -2) != 0) { + char *filename = path_get_basename(c_iter); + if (filename == NULL) { + error("%s: Could not allocate temporary memory.", SCRIPT_ENGINE); + return SCRIPT_ENGINE_ERROR; + } + fprintf(scriptdb, + "Entry{ category = \"%s\", filename = \"%s\" }\n", + lua_tostring(l, -1), filename); + free(filename); + lua_pop(l, 1); + } + lua_pop(l, 1); // pop the categories table + } + + free(c_iter); + } + lua_pop(l, 1); // pop the closure + + if(fclose(scriptdb) != 0) { + error("%s: Could not close %s: %s", SCRIPT_ENGINE, path, strerror(errno)); + return SCRIPT_ENGINE_ERROR; + } + + return SCRIPT_ENGINE_SUCCESS; +} + +int init_loadcategories(lua_State* l, std::vector categories, std::vector &unusedTags) { + std::vector::iterator iter; + std::vector files; + std::string dbpath = std::string(SCRIPT_ENGINE_LUA_DIR) + std::string(SCRIPT_ENGINE_DATABASE); + char* c_dbpath_buf; + char c_dbpath[MAX_FILENAME_LEN]; + const char* stub = "\ +files = {}\n\ +Entry = function(e)\n\ + if (categories[e.category] ~= nil) then\n\ + categories[e.category] = categories[e.category] + 1\n\ + files[e.filename] = true\n\ + end\n\ + if (categories[\"all\"] ~= nil and e.category ~= \"version\") then\n\ + categories[\"all\"] = categories[\"all\"] + 1\n\ + files[e.filename] = true\n\ + end\n\ +end\n"; + int categories_usage; + char* c_iter; + char script_path[MAX_FILENAME_LEN]; + int type; + + // closure + lua_newtable(l); + + // categories table + lua_newtable(l); + for(iter = categories.begin(); iter != categories.end(); iter++) { + lua_pushinteger(l, 0); + lua_setfield(l, -2, (*iter).c_str()); + } + lua_setfield(l, -2, "categories"); + + // we load the stub + // the strlen is safe in this case because the stub is a constant string + SCRIPT_ENGINE_LUA_TRY(luaL_loadbuffer(l, stub, strlen(stub), "Database Stub")); + lua_pushvalue(l, -2); + lua_setfenv(l, -2); + SCRIPT_ENGINE_LUA_TRY(lua_pcall(l, 0, 0, 0)); + + // if we can't find the database we try to create it + c_dbpath_buf = strdup(dbpath.c_str()); + if(nmap_fetchfile(c_dbpath, sizeof(c_dbpath), c_dbpath_buf) == 0) { + SCRIPT_ENGINE_TRY(init_updatedb(l)); + } + free(c_dbpath_buf); + + SCRIPT_ENGINE_LUA_TRY(luaL_loadfile(l, c_dbpath)); + lua_pushvalue(l, -2); + lua_setfenv(l, -2); + SCRIPT_ENGINE_LUA_TRY(lua_pcall(l, 0, 0, 0)); + + // retrieve the filenames produced by the stub + lua_getfield(l, -1, "files"); + lua_pushnil(l); + while(lua_next(l, -2) != 0) { + if(lua_isstring(l, -2)) + files.push_back(std::string(lua_tostring(l, -2))); + else { + error("%s: One of the filenames in '%s' is not a string?!", + SCRIPT_ENGINE, + SCRIPT_ENGINE_DATABASE); + return SCRIPT_ENGINE_ERROR; + } + lua_pop(l, 1); + } + lua_pop(l, 1); + + // find out which categories didn't produce any filenames + lua_getfield(l, -1, "categories"); + lua_pushnil(l); + while(lua_next(l, -2) != 0) { + categories_usage = lua_tointeger(l, -1); + if(categories_usage == 0) { + unusedTags.push_back(std::string(lua_tostring(l, -2))); + } + lua_pop(l, 1); + } + lua_pop(l, 2); + + // load all the files we have found for the given categories + for(iter = files.begin(); iter != files.end(); iter++) { + c_iter = strdup((*iter).c_str()); + type = init_fetchfile(script_path, sizeof(script_path), c_iter); + + if(type != 1) { + error("%s: %s is not a file.", SCRIPT_ENGINE, c_iter); + return SCRIPT_ENGINE_ERROR; + } + + free(c_iter); + + SCRIPT_ENGINE_TRY(init_loadfile(l, script_path)); + } + + return SCRIPT_ENGINE_SUCCESS; +} + +int init_fetchfile(char *path, size_t path_len, char* file) { + int type; + + type = nmap_fetchfile(path, path_len, file); + + // lets look in /scripts too + if(type == 0) { + char* alt_path = strdup((std::string(SCRIPT_ENGINE_LUA_DIR) + std::string(file)).c_str()); + type = nmap_fetchfile(path, path_len, alt_path); + free(alt_path); + + } + + return type; +} + +/* This is simply the most portable way to check + * if a file has a given extension. + * The portability comes at the price of reduced + * flexibility. + */ +int check_extension(const char* ext, const char* path) { + int pathlen = strlen(path); + int extlen = strlen(ext); + const char* offset; + + if( extlen > pathlen + || pathlen > MAX_FILENAME_LEN) + return -1; + + offset = path + pathlen - extlen; + + if(strcmp(offset, ext) != MATCH) + return 1; + else + return MATCH; +} + +int init_loaddir(lua_State* l, char* dirname) { + std::vector files; + char* c_iter; + + SCRIPT_ENGINE_TRY(init_scandir(dirname, files, FILES)); + + std::vector::iterator iter; + for(iter = files.begin(); iter != files.end(); iter++) { + c_iter = strdup((*iter).c_str()); + SCRIPT_ENGINE_TRY(init_loadfile(l, c_iter)); + free(c_iter); + } + + return SCRIPT_ENGINE_SUCCESS; +} + +#ifdef WIN32 + +int init_scandir(char* dirname, std::vector& result, int files_or_dirs) { + HANDLE dir; + WIN32_FIND_DATA entry; + std::string path; + BOOL morefiles = FALSE; + + dir = FindFirstFile((std::string(dirname) + "\\*").c_str(), &entry); + + if (dir == INVALID_HANDLE_VALUE) + { + error("%s: No files in '%s\\*'", SCRIPT_ENGINE, dirname); + return SCRIPT_ENGINE_ERROR; + } + + while(!(morefiles == FALSE && GetLastError() == ERROR_NO_MORE_FILES)) { + // if we are looking for files and this file doesn't end with .nse or + // is a directory, then we don't look further at it + if(files_or_dirs == FILES) { + if(!( + (check_extension(SCRIPT_ENGINE_EXTENSION, entry.cFileName) == MATCH) + && !(entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + )) { + morefiles = FindNextFile(dir, &entry); + continue; + } + + // if we are looking for dirs and this dir + // isn't a directory, then we don't look further at it + } else if(files_or_dirs == DIRS) { + if(!( + (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + )) { + morefiles = FindNextFile(dir, &entry); + continue; + } + + // they have passed an invalid value for files_or_dirs + } else { + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + } + + // otherwise we add it to the results + // we assume that dirname ends with a directory separator of some kind + path = std::string(dirname) + std::string(entry.cFileName); + result.push_back(path); + morefiles = FindNextFile(dir, &entry); + } + + + return SCRIPT_ENGINE_SUCCESS; +} + +#else + +int init_scandir(char* dirname, std::vector& result, int files_or_dirs) { + DIR* dir; + struct dirent* entry; + std::string path; + struct stat stat_entry; + + dir = opendir(dirname); + if(dir == NULL) { + error("%s: Could not open directory '%s'.", SCRIPT_ENGINE, dirname); + return SCRIPT_ENGINE_ERROR; + } + + // note that if there is a symlink in the dir, we have to rely on + // the .nse extension + // if they provide a symlink to a dir which ends with .nse, things + // break :/ + while((entry = readdir(dir)) != NULL) { + path = std::string(dirname) + "/" + std::string(entry->d_name); + + if(stat(path.c_str(), &stat_entry) != 0) + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + + // if we are looking for files and this file doesn't end with .nse and + // isn't a file or a link, then we don't look further at it + if(files_or_dirs == FILES) { + if(!( + (check_extension(SCRIPT_ENGINE_EXTENSION, entry->d_name) == MATCH) + && (S_ISREG(stat_entry.st_mode) + || S_ISLNK(stat_entry.st_mode)) + )) { + continue; + } + + // if we are looking for dirs and this dir + // isn't a dir or a link, then we don't look further at it + } else if(files_or_dirs == DIRS) { + if(!( + (S_ISDIR(stat_entry.st_mode) + || S_ISLNK(stat_entry.st_mode)) + )) { + continue; + } + + // they have passed an invalid value for files_or_dirs + } else { + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + } + + // otherwise we add it to the results + result.push_back(path); + } + + closedir(dir); + + return SCRIPT_ENGINE_SUCCESS; +} + +#endif + +/* load an nmap-lua script + * create a new closure to store the script + * tell the closure where to find the standard + * lua libs and the nmap bindings + * we do some error checking to make sure that + * the script is well formed + * the script is then added to either the hostrules + * or the portrules + * */ +int init_loadfile(lua_State* l, char* filename) { + int rule_count; + + /* create a closure for encapsuled execution + * give the closure access to the global enviroment + */ + lua_newtable(l); + + /* tell the script about its filename */ + lua_pushstring(l, filename); + lua_setfield(l, -2, "filename"); + + /* we give the script access to the global name space + * */ + lua_newtable(l); + lua_getglobal(l, "_G"); + lua_setfield(l, -2, "__index"); + lua_setmetatable(l, -2); + + /* load the *.nse file, set the closure and execute (init) the test + * */ + SCRIPT_ENGINE_LUA_TRY(luaL_loadfile(l, filename)); + lua_pushvalue(l, -2); + lua_setfenv(l, -2); + SCRIPT_ENGINE_LUA_TRY(lua_pcall(l, 0, 0, 0)); + + /* look at the runlevel, if it is not set, we set it to 1.0 + * */ + lua_getfield(l, -1, RUNLEVEL); + if(lua_isnil(l, -1)) { + lua_pushnumber(l, 1.0); + lua_setfield(l, -3, RUNLEVEL); + } + lua_pop(l, 1); + + /* finally we make sure nobody tampers with the global name space any more + * and prepare for runlevel sorting + * */ + lua_getmetatable(l, -1); + + std::string buf = + (std::string("err = \"Attempted to change the global '\" .. select(2, ...) .. \"' in ") + + std::string(filename) + + std::string(" - use nmap.registry if you really want to share data between scripts.\"") + + std::string("error(err)")); + SCRIPT_ENGINE_LUA_TRY(luaL_loadbuffer(l, buf.c_str(), buf.length(), "Global Access")); + lua_setfield(l, -2, "__newindex"); + + lua_setmetatable(l, -2); + + /* store the initialized test in either + * the hosttests or the porttests + * */ + lua_getfield(l, -1, PORTRULE); + lua_getfield(l, -2, HOSTRULE); + + /* if we are looking at a portrule then store it in the porttestsets table + * if it is a hostrule, then it goes into the hosttestsets table + * otherwise we fail + * if there is no action in the script we also fail + * */ + if(lua_isnil(l, -2) == 0) { + lua_pop(l, 2); + lua_getglobal(l, PORTTESTS); + rule_count = lua_objlen(l, -1); + lua_pushvalue(l, -2); + lua_rawseti(l, -2, (rule_count + 1)); + lua_pop(l, 1); // pop the porttests table + } else if(lua_isnil(l, -1) == 0) { + lua_pop(l, 2); + lua_getglobal(l, HOSTTESTS); + rule_count = lua_objlen(l, -1); + lua_pushvalue(l, -2); + lua_rawseti(l, -2, (rule_count + 1)); + lua_pop(l, 1); // pop the hosttests table + } else { + error("%s: No rules in script '%s'.", SCRIPT_ENGINE, filename); + return SCRIPT_ENGINE_ERROR; + } + + std::vector required_fields; + required_fields.push_back(std::string(ACTION)); + required_fields.push_back(std::string(DESCRIPTION)); + + std::vector::iterator iter; + for(iter = required_fields.begin(); iter != required_fields.end(); iter++) { + lua_getfield(l, -1, (*iter).c_str()); + if(lua_isnil(l, -1) == 1) { + error("%s: No '%s' field in script '%s'.", SCRIPT_ENGINE, (*iter).c_str(), filename); + return SCRIPT_ENGINE_ERROR; + } + lua_pop(l, 1); // pop the action + } + + + lua_pop(l, 1); // pop the closure + + return SCRIPT_ENGINE_SUCCESS; +} + diff -NraupbwB soc07-5184/nse_nmaplib.cc soc07-nse-pcap/nse_nmaplib.cc --- soc07-5184/nse_nmaplib.cc 2007-07-10 18:15:14.000000000 +0200 +++ soc07-nse-pcap/nse_nmaplib.cc 2007-07-11 23:06:41.000000000 +0200 @@ -37,6 +37,8 @@ static int l_get_port_state(lua_State* l static int l_set_port_state(lua_State* l, Target* target, Port* port); static int l_set_port_version(lua_State* l, Target* target, Port* port); +int l_clock_ms(lua_State* l); + /* register the nmap lib * we assume that we can write to a table at -1 on the stack * */ @@ -46,6 +48,9 @@ int set_nmaplib(lua_State* l) { {"set_port_state", l_port_accessor}, {"set_port_version", l_port_accessor}, {"new_socket", l_nsock_new}, + {"new_dnet", l_dnet_new}, + {"get_interface_link", l_dnet_get_interface_link}, + {"clock_ms", l_clock_ms}, {"print_debug_unformatted", l_print_debug_unformatted}, {"new_try", l_exc_newtry}, {NULL, NULL} @@ -61,6 +66,7 @@ int set_nmaplib(lua_State* l) { lua_setfield(l, -2, "registry"); SCRIPT_ENGINE_TRY(l_nsock_open(l)); + SCRIPT_ENGINE_TRY(l_dnet_open(l)); return SCRIPT_ENGINE_SUCCESS; } @@ -181,6 +187,33 @@ void set_hostinfo(lua_State* l, Target * lua_pushstring(l, strncpy(hostname, currenths->HostName(), 1024)); lua_setfield(l, -2, "name"); + if(currenths->directlyConnectedOrUnset() != -1){ + lua_pushboolean(l, currenths->directlyConnectedOrUnset()); + lua_setfield(l, -2, "directly_connected"); + } + + if(currenths->MACAddress()){ // else nil + lua_pushlstring (l, (const char*)currenths->MACAddress() , 6); + lua_setfield(l, -2, "mac_addr"); + } + if(currenths->SrcMACAddress()){ // else nil + lua_pushlstring(l, (const char*)currenths->SrcMACAddress(), 6); + lua_setfield(l, -2, "mac_addr_src"); + } + if(currenths->deviceName()){ + lua_pushstring(l, strncpy(hostname, currenths->deviceName(), 1024)); + lua_setfield(l, -2, "interface"); + } + if( (u32)(currenths->v4host().s_addr) ){ + struct in_addr adr = currenths->v4host(); + lua_pushlstring(l, (char*)&adr, 4); + lua_setfield(l, -2, "bin_ip"); + } + if( (u32)(currenths->v4source().s_addr) ){ + struct in_addr adr = currenths->v4source(); + lua_pushlstring(l, (char*)&adr, 4); + lua_setfield(l, -2, "bin_ip_src"); + } FingerPrintResults *FPR = NULL; int osscanSys; diff -NraupbwB soc07-5184/nse_nmaplib.cc.orig soc07-nse-pcap/nse_nmaplib.cc.orig --- soc07-5184/nse_nmaplib.cc.orig 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nse_nmaplib.cc.orig 2007-07-10 18:15:14.000000000 +0200 @@ -0,0 +1,446 @@ +#include "nse_nmaplib.h" +#include "nse_nsock.h" +#include "nse_macros.h" +#include "nse_debug.h" + +#include "nmap_error.h" +#include "osscan.h" +#include "NmapOps.h" +#include "nmap_rpc.h" +#include "Target.h" +#include "output.h" +#include "portlist.h" + +#define SCRIPT_ENGINE_GETSTRING(name) \ + char* name; \ + lua_getfield(l, -1, #name); \ + if(lua_isnil(l, -1)) \ + name = NULL; \ + else \ + name = strdup(lua_tostring(l, -1)); \ + lua_pop(l, 1); \ + +#define SCRIPT_ENGINE_PUSHSTRING_NOTNULL(c_str, str) if(c_str != NULL) {\ + lua_pushstring(l, c_str); \ + lua_setfield(l, -2, str); \ +} + +extern NmapOps o; +extern std::map current_hosts; + +void set_version(lua_State* l, struct serviceDeductions sd); + +static int l_exc_newtry(lua_State *l); +static int l_port_accessor(lua_State* l); +static int l_print_debug_unformatted(lua_State *l); +static int l_get_port_state(lua_State* l, Target* target, Port* port); +static int l_set_port_state(lua_State* l, Target* target, Port* port); +static int l_set_port_version(lua_State* l, Target* target, Port* port); + +/* register the nmap lib + * we assume that we can write to a table at -1 on the stack + * */ +int set_nmaplib(lua_State* l) { + static luaL_reg nmaplib [] = { + {"get_port_state", l_port_accessor}, + {"set_port_state", l_port_accessor}, + {"set_port_version", l_port_accessor}, + {"new_socket", l_nsock_new}, + {"print_debug_unformatted", l_print_debug_unformatted}, + {"new_try", l_exc_newtry}, + {NULL, NULL} + }; + + const luaL_Reg* lib; + for (lib = nmaplib; lib->func; lib++) { + lua_pushcfunction(l, lib->func); + lua_setfield(l, -2, lib->name); + } + + lua_newtable(l); + lua_setfield(l, -2, "registry"); + + SCRIPT_ENGINE_TRY(l_nsock_open(l)); + + return SCRIPT_ENGINE_SUCCESS; +} + +/* set some port state information onto the + * table which is currently on the stack + * */ +void set_portinfo(lua_State* l, Port* port) { + struct serviceDeductions sd; + + port->getServiceDeductions(&sd); + + lua_pushnumber(l, (double) port->portno); + lua_setfield(l, -2, "number"); + + lua_pushstring(l, sd.name); + lua_setfield(l, -2, "service"); + + lua_pushstring(l, (port->proto == IPPROTO_TCP)? "tcp": "udp"); + lua_setfield(l, -2, "protocol"); + + lua_newtable(l); + set_version(l, sd); + lua_setfield(l, -2, "version"); + + lua_pushstring(l, statenum2str(port->state)); + lua_setfield(l, -2, "state"); +} + +void set_version(lua_State* l, struct serviceDeductions sd) { + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.name, "name"); + + lua_pushnumber(l, sd.name_confidence); + lua_setfield(l, -2, "name_confidence"); + + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.product, "product"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.version, "version"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.extrainfo, "extrainfo"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.hostname, "hostname"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.ostype, "ostype"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.devicetype, "devicetype"); + + switch(sd.service_tunnel) { + case(SERVICE_TUNNEL_NONE): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("none", "service_tunnel"); + break; + case(SERVICE_TUNNEL_SSL): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("ssl", "service_tunnel"); + break; + default: + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + break; + } + + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.service_fp, "service_fp"); + + switch(sd.dtype) { + case(SERVICE_DETECTION_TABLE): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("table", "service_fp"); + break; + case(SERVICE_DETECTION_PROBED): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("probed", "service_fp"); + break; + default: + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + break; + } + + switch(sd.rpc_status) { + case(RPC_STATUS_UNTESTED): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("untested", "rpc_status"); + break; + case(RPC_STATUS_UNKNOWN): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("unknown", "rpc_status"); + break; + case(RPC_STATUS_GOOD_PROG): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("good_prog", "rpc_status"); + break; + case(RPC_STATUS_NOT_RPC): + SCRIPT_ENGINE_PUSHSTRING_NOTNULL("not_rpc", "rpc_status"); + break; + default: + fatal("%s: In: %s:%i This should never happen.", + SCRIPT_ENGINE, __FILE__, __LINE__); + break; + } + + if(sd.rpc_status == RPC_STATUS_GOOD_PROG) { + lua_pushnumber(l, sd.rpc_program); + lua_setfield(l, -2, "rpc_program"); + + lua_pushnumber(l, sd.rpc_lowver); + lua_setfield(l, -2, "rpc_lowver"); + + lua_pushnumber(l, sd.rpc_highver); + lua_setfield(l, -2, "rpc_highver"); + } +} + +/* set host ip and host name onto the + * table which is currently on the stack + * set name of the os run by the host onto the + * table which is currently on the stack + * the os name is really an array with perfect + * matches + * if an os scan wasn't performed, the array + * points to nil! + * */ +void set_hostinfo(lua_State* l, Target *currenths) { + unsigned int i; + char hostname[1024]; + + lua_pushstring(l, strncpy(hostname, currenths->targetipstr(), 1024)); + lua_setfield(l, -2, "ip"); + + lua_pushstring(l, strncpy(hostname, currenths->HostName(), 1024)); + lua_setfield(l, -2, "name"); + + + FingerPrintResults *FPR = NULL; + int osscanSys; + + if (currenths->FPR != NULL && currenths->FPR1 == NULL) { + osscanSys = 2; + FPR = currenths->FPR; + } else if(currenths->FPR == NULL && currenths->FPR1 != NULL) { + osscanSys = 1; + FPR = currenths->FPR1; + } + + /* if there has been an os scan which returned a pretty certain + * result, we will use it in the scripts + * matches which aren't perfect are not needed in the scripts + */ + if( currenths->osscanPerformed() && + FPR != NULL && + FPR->overall_results == OSSCAN_SUCCESS && + FPR->num_perfect_matches > 0 && + FPR->num_perfect_matches <= 8 ) { + + lua_newtable(l); + + // this will run at least one time and at most 8 times, see if condition + for(i = 0; FPR->accuracy[i] == 1; i++) { + lua_pushstring(l, FPR->prints[i]->OS_name); + lua_rawseti(l, -2, i); + } + lua_setfield(l, -2, "os"); + } +} + +static int l_port_accessor(lua_State* l) { + int retvalues = 0; + + char* function_name; + char* target_ip; + int portno; + int proto; + + Target* target; + PortList* plist; + Port* port; + + lua_Debug ldebug; + lua_getstack(l, 0, &ldebug); + lua_getinfo(l, "n", &ldebug); + function_name = strdup(ldebug.name); + + luaL_checktype(l, 1, LUA_TTABLE); + luaL_checktype(l, 2, LUA_TTABLE); + + lua_getfield(l, 1, "ip"); + luaL_checktype(l, -1, LUA_TSTRING); + target_ip = strdup(lua_tostring(l, -1)); + lua_pop(l, 1); + + lua_getfield(l, 2, "number"); + luaL_checktype(l, -1, LUA_TNUMBER); + portno = lua_tointeger(l, -1); + lua_pop(l, 1); + + lua_getfield(l, 2, "protocol"); + luaL_checktype(l, -1, LUA_TSTRING); + proto = (strcmp(lua_tostring(l, -1), "tcp") == 0)? IPPROTO_TCP : IPPROTO_UDP; + lua_pop(l, 1); + + std::string key = std::string(target_ip); + std::map::iterator iter = current_hosts.find(key); + if(iter == current_hosts.end()) { + luaL_argerror (l, 1, "Host isn't being processed right now."); + return 0; + } else { + target = (Target*) iter->second; + } + + plist = &(target->ports); + port = NULL; + + while((port = plist->nextPort(port, proto, PORT_UNKNOWN)) != NULL) { + if(port->portno == portno) + break; + } + + // if the port wasn't scanned we return nil + if(port == NULL) + return 0; + + if(strcmp(function_name, "set_port_state") == MATCH) + retvalues = l_set_port_state(l, target, port); + else if(strcmp(function_name, "set_port_version") == MATCH) + retvalues = l_set_port_version(l, target, port); + else if(strcmp(function_name, "get_port_state") == MATCH) + retvalues = l_get_port_state(l, target, port); + + // remove host and port argument from the stack + lua_remove(l, 2); + lua_remove(l, 1); + free(target_ip); + free(function_name); + return retvalues; +} + +/* this function can be called from lua to obtain the port state + * of a port different from the one the script rule is matched + * against + * it retrieves the host.ip of the host on which the script is + * currently running, looks up the host in the table of currently + * processed hosts and returns a table containing the state of + * the port we have been asked for + * this function is useful if we want rules which want to know + * the state of more than one port + * */ +static int l_get_port_state(lua_State* l, Target* target, Port* port) { + lua_newtable(l); + set_portinfo(l, port); + + return 1; +} + +/* unlike set_portinfo() this function sets the port state in nmap. + * if for example a udp port was seen by the script as open instead of + * filtered, the script is free to say so. + * */ +static int l_set_port_state(lua_State* l, Target* target, Port* port) { + char* state; + PortList* plist = &(target->ports); + + luaL_checktype(l, -1, LUA_TSTRING); + state = strdup(lua_tostring(l, -1)); + lua_pop(l, 1); + + switch(state[0]) { + case 'o': + if (strcmp(state, "open")) + luaL_argerror (l, 4, "Invalid port state."); + plist->addPort(port->portno, port->proto, NULL, PORT_OPEN); + port->state = PORT_OPEN; + break; + case 'c': + if (strcmp(state, "closed")) + luaL_argerror (l, 4, "Invalid port state."); + plist->addPort(port->portno, port->proto, NULL, PORT_CLOSED); + port->state = PORT_CLOSED; + break; + default: + luaL_argerror (l, 4, "Invalid port state."); + } + + free(state); + return 0; +} + +static int l_set_port_version(lua_State* l, Target* target, Port* port) { + luaL_checktype(l, 3, LUA_TSTRING); + char* c_probestate = strdup(lua_tostring(l, -1)); + lua_pop(l, 1); + + enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE; + enum serviceprobestate probestate = PROBESTATE_INITIAL; + + lua_getfield(l, -1, "version"); + SCRIPT_ENGINE_GETSTRING(name); + SCRIPT_ENGINE_GETSTRING(product); + SCRIPT_ENGINE_GETSTRING(version); + SCRIPT_ENGINE_GETSTRING(extrainfo); + SCRIPT_ENGINE_GETSTRING(hostname); + SCRIPT_ENGINE_GETSTRING(ostype); + SCRIPT_ENGINE_GETSTRING(devicetype); + // SCRIPT_ENGINE_GETSTRING(fingerprint); + + SCRIPT_ENGINE_GETSTRING(service_tunnel); + if(strcmp(service_tunnel, "none") == 0) + tunnel = SERVICE_TUNNEL_NONE; + else if(strcmp(service_tunnel, "ssl") == 0) + tunnel = SERVICE_TUNNEL_SSL; + else + luaL_argerror(l, 2, "Invalid value for port.version.service_tunnel"); + lua_pop(l, 1); + + if(strcmp(c_probestate, "hardmatched") == 0) + probestate = PROBESTATE_FINISHED_HARDMATCHED; + else if(strcmp(c_probestate, "softmatched") == 0) + probestate = PROBESTATE_FINISHED_SOFTMATCHED; + else if(strcmp(c_probestate, "nomatch") == 0) + probestate = PROBESTATE_FINISHED_NOMATCH; + else if(strcmp(c_probestate, "tcpwrapped") == 0) + probestate = PROBESTATE_FINISHED_TCPWRAPPED; + else if(strcmp(c_probestate, "incomplete") == 0) + probestate = PROBESTATE_INCOMPLETE; + else + luaL_argerror(l, 3, "Invalid value for probestate."); + +// port->setServiceProbeResults(probestate, name, +// tunnel, product, version, +// extrainfo, hostname, ostype, +// devicetype, fingerprint); + port->setServiceProbeResults(probestate, name, + tunnel, product, version, + extrainfo, hostname, ostype, + devicetype, NULL); + + + + free(service_tunnel); + free(name); + free(product); + free(version); + free(extrainfo); + free(hostname); + free(ostype); + free(devicetype); +// free(fingerprint); + return 0; +} + +static int l_print_debug_unformatted(lua_State *l) { + int verbosity=1; + const char *out; + + if (lua_gettop(l) != 2) return luaL_error(l, "Incorrect number of arguments\n"); + + verbosity = luaL_checkinteger(l, 1); + if (verbosity > o.verbose) return 0; + out = luaL_checkstring(l, 2); + + log_write(LOG_STDOUT, "%s DEBUG: %s\n", SCRIPT_ENGINE, out); + + return 0; +} + +static int l_exc_finalize(lua_State *l) { + if (lua_isnil(l, 1)) { + lua_pushvalue(l, lua_upvalueindex(1)); + lua_call(l, 0, 0); + lua_settop(l, 2); + lua_error(l); + return 0; + } else if(lua_toboolean(l, 1)) { + lua_remove(l, 1); + return lua_gettop(l); + } else { + fatal("%s: In: %s:%i Trying to finalize a non conforming function. Are you sure you return true on success followed by the remaining return values and nil on failure followed by an error string?", + SCRIPT_ENGINE, __FILE__, __LINE__); + + return 0; + } +} + +static int l_exc_do_nothing(lua_State *l) { + (void) l; + return 0; +} + +static int l_exc_newtry(lua_State *l) { + lua_settop(l, 1); + if (lua_isnil(l, 1)) + lua_pushcfunction(l, l_exc_do_nothing); + lua_pushcclosure(l, l_exc_finalize, 1); + return 1; +} + diff -NraupbwB soc07-5184/nse_nsock.cc soc07-nse-pcap/nse_nsock.cc --- soc07-5184/nse_nsock.cc 2007-07-10 18:15:14.000000000 +0200 +++ soc07-nse-pcap/nse_nsock.cc 2007-07-11 23:41:14.000000000 +0200 @@ -6,6 +6,9 @@ #include "nsock.h" #include "nmap_error.h" #include "NmapOps.h" +#include "utils.h" +#include "dnet.h" +#include "tcpip.h" #include #include @@ -41,6 +44,12 @@ 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_ncap_open(lua_State* l); +static int l_nsock_ncap_close(lua_State* l); +static int l_nsock_ncap_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 *lua_state); void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *lua_state); void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state); @@ -61,15 +70,65 @@ static luaL_reg l_nsock [] = { {"close", l_nsock_close}, {"set_timeout", l_nsock_set_timeout}, {"__gc",l_nsock_gc}, + {"pcap_open", l_nsock_ncap_open}, + {"pcap_close", l_nsock_ncap_close}, + {"pcap_register", l_nsock_ncap_register}, + {"pcap_receive", l_nsock_pcap_receive}, +// {"callback_test", l_nsock_pcap_callback_test}, {NULL, NULL} }; static nsock_pool nsp; +/* + * Structure with nsock pcap descriptor. + * shared between many lua threads + */ +struct ncap_socket{ + 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 ncap_request{ + int suspended; /* is the thread suspended? (lua_yield) */ + lua_State *l; /* lua_State of current process + * or NULL if process isn't suspended */ + 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 */ + + 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; void *ssl_session; + + struct ncap_socket *ncap_socket; + struct ncap_request *ncap_request; + int ncap_cback_ref; }; int l_nsock_open(lua_State* l) { @@ -90,6 +149,9 @@ int l_nsock_new(lua_State* l) { udata->nsiod = NULL; udata->ssl_session = NULL; udata->timeout = DEFAULT_TIMEOUT; + udata->ncap_socket = NULL; + udata->ncap_request = NULL; + udata->ncap_cback_ref = 0; return 1; } @@ -303,9 +365,9 @@ void l_nsock_trace(nsock_iod nsiod, char char* ipstring_local = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); char* ipstring_remote = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + if(!nsi_is_pcap(nsiod)){ status = nsi_getlastcommunicationinfo(nsiod, &protocol, &af, &local, &remote, sizeof(sockaddr)); - log_write(LOG_STDOUT, "SCRIPT ENGINE: %s %s:%d %s %s:%d | %s\n", (protocol == IPPROTO_TCP)? "TCP" : "UDP", inet_ntop_both(af, &local, ipstring_local), @@ -317,6 +379,11 @@ void l_nsock_trace(nsock_iod nsiod, char free(ipstring_local); free(ipstring_remote); + }else{ // is pcap device + log_write(LOG_STDOUT, "SCRIPT ENGINE: %s | %s\n", + (direction == TO)? ">" : "<", + message); + } } char* inet_ntop_both(int af, const void* v_addr, char* ipstring) { @@ -394,10 +461,16 @@ static int l_nsock_gc(lua_State* l){ l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); if(udata->nsiod == NULL) { //socket obviously got closed already - so no finalization needed return 0; - }else{ + } + + /* Never ever collect nse-pcap connections. */ + if(udata->ncap_socket){ + return 0; + } + //FIXME - check wheter close returned true!! l_nsock_close(l); - } + return 0; } static int l_nsock_close(lua_State* l) { @@ -436,3 +509,612 @@ static int l_nsock_set_timeout(lua_State return 0; } +/****************** NCAP_SOCKET ***********************************************/ +#ifdef WIN32 +/* From tcpip.cc. Gets pcap device name from dnet name. */ +bool DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen); +#endif + +/* fuckin' C++ maps stuff */ +/* here we store ncap_sockets */ +std::map 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)); + + #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)); + } + #else + strncpy(pcapdev, device, sizeof(pcapdev)); + #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_ncap_open(lua_State* l){ + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + const char* device = luaL_checkstring(l, 2); + int snaplen = luaL_checkint(l, 3); + int promisc = luaL_checkint(l, 4); + luaL_checktype(l, 5, LUA_TFUNCTION); /* callback function that creates hash */ + const char* bpf = luaL_checkstring(l, 6); + + if(udata->nsiod || udata->ncap_request || udata->ncap_socket) { + luaL_argerror(l, 1, "Trying to open nsock-pcap, but this connection is already opened"); + return 0; + } + 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; + return 0; +} + +/* (LUA) Close nsock-pcap socket. + * */ +static int l_nsock_ncap_close(lua_State* l){ + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + struct ncap_socket *ns = udata->ncap_socket; + + if(!udata->nsiod || !udata->ncap_socket) { + 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; + } + + assert(ns->references > 0); + + ns->references--; + if(ns->references == 0){ + ncap_socket_map_del(ns->key); + if(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; isuspended_lua_threads */ +std::multimap ncap_request_map; +typedef std::multimap::iterator ncap_request_map_iterator; +typedef std::pair 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(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_ncap_register(lua_State *l){ + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + 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->l = l; + 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*) auxiliar_checkclass(l, "nsock", 1); + 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; + + /* 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 lua_yield(l, 0); +} + +/* (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); + // lua_pop(l, 1);/* just in case [nope, it's not needed]*/ + + 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->l, 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, 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; + nse_readpcap(nse, &l2_data, &l2_len, &l3_data, &l3_len, + &packet_len, NULL); + char *packet = (char*) malloc(l2_len + l3_len); + nr->r_layer2 = (unsigned char*)memcpy(&packet[0], l2_data, l2_len); + nr->r_layer3 = (unsigned char*)memcpy(&packet[l2_len], l3_data, l3_len); + nr->r_layer2_len = l2_len; + nr->r_layer3_len = l3_len; + nr->packetsz = packet_len; + 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->l; + + 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); + }else{ + lua_pushnil(l); + lua_pushstring(l, nr->r_status); + lua_pushnil(l); + lua_pushnil(l); + } + bool suspended = nr->suspended; + nr->l = NULL; + 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 */ + return process_waiting2running(l, 4); + else /* not suspended, just pass output */ + return 4; +} + + + + +/****************** 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 luaL_reg l_dnet [] = { + {"ethernet_open", l_dnet_open_ethernet}, + {"ethernet_close", l_dnet_close_ethernet}, + {"ethernet_send", l_dnet_send_ethernet}, + {NULL, NULL} +}; + +int l_dnet_open(lua_State* l) { + auxiliar_newclass(l, "dnet", l_dnet); + return NSOCK_WRAPPER_SUCCESS; +} + +struct l_dnet_udata { + char *interface; + eth_t *eth; +}; + +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)); + auxiliar_setclass(l, "dnet", -1); + udata->interface= NULL; + udata->eth = NULL; + + 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; + } + 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 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*) auxiliar_checkclass(l, "dnet", 1); + 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*) auxiliar_checkclass(l, "dnet", 1); + 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*) auxiliar_checkclass(l, "dnet", 1); + 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; +} + +int l_clock_ms(lua_State* l){ + struct timeval tv; + gettimeofday(&tv, NULL); + // no rounding error + // unless the number is greater than 100,000,000,000,000 + double usec = 0.0; //MAX_INT*1000 = 4 294 967 296 000 <- miliseconds since epoch should fit + usec = tv.tv_sec*1000; + usec += (int)(tv.tv_usec/1000); // make sure it's integer. + + lua_pushnumber(l, usec); + return 1; +} + + + + + diff -NraupbwB soc07-5184/nse_nsock.cc.orig soc07-nse-pcap/nse_nsock.cc.orig --- soc07-5184/nse_nsock.cc.orig 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nse_nsock.cc.orig 2007-07-10 18:15:14.000000000 +0200 @@ -0,0 +1,438 @@ +#include "nse_nsock.h" +#include "nse_auxiliar.h" +#include "nse_macros.h" +#include "nse_string.h" + +#include "nsock.h" +#include "nmap_error.h" +#include "NmapOps.h" + +#include +#include +#include + +#if HAVE_OPENSSL +#include +#endif + +#define SCRIPT_ENGINE "SCRIPT ENGINE" +#define NSOCK_WRAPPER "NSOCK WRAPPER" +#define NSOCK_WRAPPER_SUCCESS 0 +#define NSOCK_WRAPPER_ERROR 2 + +#define FROM 1 +#define TO 2 + +#define DEFAULT_TIMEOUT 30000 + +extern NmapOps o; + +// defined in nse_main.cc but also declared here +// to keep the .h files clean +int process_waiting2running(lua_State* l, int resume_arguments); + +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); + +void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *lua_state); +void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *lua_state); +void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state); + +int l_nsock_checkstatus(lua_State* l, nsock_event nse); + +void l_nsock_trace(nsock_iod nsiod, char* message, int direction); +char* inet_ntop_both(int af, const void* v_addr, char* ipstring); +unsigned short inet_port_both(int af, const void* v_addr); + +static luaL_reg l_nsock [] = { + {"connect", l_nsock_connect}, + {"send", l_nsock_send}, + {"receive", l_nsock_receive}, + {"receive_lines", l_nsock_receive_lines}, + {"receive_bytes", l_nsock_receive_bytes}, + {"get_info", l_nsock_get_info}, + {"close", l_nsock_close}, + {"set_timeout", l_nsock_set_timeout}, + {"__gc",l_nsock_gc}, + {NULL, NULL} +}; + +static nsock_pool nsp; + +struct l_nsock_udata { + int timeout; + nsock_iod nsiod; + void *ssl_session; +}; + +int l_nsock_open(lua_State* l) { + auxiliar_newclass(l, "nsock", l_nsock); + + nsp = nsp_new(NULL); + + if (o.scriptTrace()) + nsp_settrace(nsp, 5, o.getStartTime()); + + return NSOCK_WRAPPER_SUCCESS; +} + +int l_nsock_new(lua_State* l) { + struct l_nsock_udata* udata; + udata = (struct l_nsock_udata*) lua_newuserdata(l, sizeof(struct l_nsock_udata)); + auxiliar_setclass(l, "nsock", -1); + udata->nsiod = NULL; + udata->ssl_session = NULL; + udata->timeout = DEFAULT_TIMEOUT; + return 1; +} + +int l_nsock_loop(int tout) { + return nsock_loop(nsp, tout); +} + +int l_nsock_checkstatus(lua_State* l, nsock_event nse) { + enum nse_status status = nse_status(nse); + + 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; + + } + + return -1; +} + +static int l_nsock_connect(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + const char* addr = luaL_checkstring(l, 2); + unsigned short port = (unsigned short) luaL_checkint(l, 3); + const char *how = luaL_optstring(l, 4, "tcp"); + + const char* error; + struct addrinfo *dest; + int error_id; + + + 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; + } + + udata->nsiod = nsi_new(nsp, NULL); + + switch (how[0]) { + case 't': + if (strcmp(how, "tcp")) goto error; + nsock_connect_tcp(nsp, udata->nsiod, l_nsock_connect_handler, + udata->timeout, l, dest->ai_addr, dest->ai_addrlen, port); + break; + case 'u': + if (strcmp(how, "udp")) goto error; + nsock_connect_udp(nsp, udata->nsiod, l_nsock_connect_handler, + l, dest->ai_addr, dest->ai_addrlen, port); + break; + case 's': + if (strcmp(how, "ssl")) goto error; +#ifdef HAVE_OPENSSL + nsock_connect_ssl(nsp, udata->nsiod, l_nsock_connect_handler, + udata->timeout, l, dest->ai_addr, dest->ai_addrlen, port, + udata->ssl_session); + break; +#else + luaL_argerror(l, 4, "Sorry, you don't have openssl."); + return 0; +#endif + default: + goto error; + break; + } + + freeaddrinfo(dest); + return lua_yield(l, 0); + +error: + freeaddrinfo(dest); + luaL_argerror(l, 4, "invalid connection method"); + return 0; +} + +void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *lua_state) { + lua_State* l = (lua_State*) lua_state; + + if(o.scriptTrace()) { + l_nsock_trace(nse_iod(nse), "CONNECT", TO); + } + + if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) { + process_waiting2running((lua_State*) lua_state, 1); + } else { + process_waiting2running((lua_State*) lua_state, 2); + } +} + +static int l_nsock_send(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + const char* string = luaL_checkstring(l, 2); + size_t string_len = lua_objlen (l, 2); + char* hexified; + + if(udata->nsiod == NULL) { + lua_pushboolean(l, false); + lua_pushstring(l, "Trying to send through a closed socket\n"); + return 2; + } + + if(o.scriptTrace()) { + hexified = nse_hexify((const void*)string, string_len); + l_nsock_trace(udata->nsiod, hexified, TO); + free(hexified); + } + + nsock_write(nsp, udata->nsiod, l_nsock_send_handler, udata->timeout, l, string, string_len); + return lua_yield(l, 0); +} + +void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *lua_state) { + lua_State* l = (lua_State*) lua_state; + + if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) { + process_waiting2running((lua_State*) lua_state, 1); + } else { + process_waiting2running((lua_State*) lua_state, 2); + } +} + +static int l_nsock_receive(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + + 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, l); + + return lua_yield(l, 0); +} + +static int l_nsock_receive_lines(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + int nlines = (int) luaL_checknumber(l, 2); + + 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, l, nlines); + + return lua_yield(l, 0); +} + +static int l_nsock_receive_bytes(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + int nbytes = (int) luaL_checknumber(l, 2); + + 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, l, nbytes); + + return lua_yield(l, 0); +} + +void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state) { + lua_State* l = (lua_State*) lua_state; + char* rcvd_string; + int rcvd_len = 0; + char* hexified; + + if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) { + rcvd_string = nse_readbuf(nse, &rcvd_len); + + if(o.scriptTrace()) { + hexified = nse_hexify((const void*) rcvd_string, (size_t) rcvd_len); + l_nsock_trace(nse_iod(nse), hexified, FROM); + free(hexified); + } + + lua_pushlstring(l, rcvd_string, rcvd_len); + process_waiting2running((lua_State*) lua_state, 2); + } else { + process_waiting2running((lua_State*) lua_state, 2); + } +} + +void l_nsock_trace(nsock_iod nsiod, char* message, int direction) { + int status; + int protocol; + int af; + struct sockaddr local; + struct sockaddr remote; + char* ipstring_local = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + char* ipstring_remote = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + + status = nsi_getlastcommunicationinfo(nsiod, &protocol, &af, + &local, &remote, sizeof(sockaddr)); + + log_write(LOG_STDOUT, "SCRIPT ENGINE: %s %s:%d %s %s:%d | %s\n", + (protocol == IPPROTO_TCP)? "TCP" : "UDP", + 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); + + free(ipstring_local); + free(ipstring_remote); +} + +char* inet_ntop_both(int af, const void* v_addr, char* ipstring) { +// char* ipstring = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + + 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*) auxiliar_checkclass(l, "nsock", 1); + int status; + + int protocol; // tcp or udp + int af; // address family + struct sockaddr local; + struct sockaddr remote; + char* ipstring_local = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + char* ipstring_remote = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN); + + 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); + + 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*) auxiliar_checkclass(l, "nsock", 1); + if(udata->nsiod == NULL) { //socket obviously got closed already - so no finalization needed + return 0; + }else{ + //FIXME - check wheter close returned true!! + l_nsock_close(l); + } + return 0; +} +static int l_nsock_close(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + + 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); + } + +#ifdef HAVE_OPENSSL + if (udata->ssl_session) + SSL_SESSION_free((SSL_SESSION*)udata->ssl_session); + udata->ssl_session=NULL; +#endif + + nsi_delete(udata->nsiod, NSOCK_PENDING_NOTIFY); + + udata->nsiod = NULL; + + lua_pushboolean(l, true); + return 1; +} + +static int l_nsock_set_timeout(lua_State* l) { + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + int timeout = (unsigned short) luaL_checkint(l, 2); + + udata->timeout = timeout; + + return 0; +} + diff -NraupbwB soc07-5184/nse_nsock.h soc07-nse-pcap/nse_nsock.h --- soc07-5184/nse_nsock.h 2007-07-10 18:15:14.000000000 +0200 +++ soc07-nse-pcap/nse_nsock.h 2007-07-11 23:06:41.000000000 +0200 @@ -11,5 +11,9 @@ int l_nsock_open(lua_State* l); int l_nsock_new(lua_State* l); int l_nsock_loop(int tout); +int l_dnet_new(lua_State* l); +int l_dnet_open(lua_State* l); +int l_dnet_get_interface_link(lua_State* l); + #endif diff -NraupbwB soc07-5184/nsock/examples/Makefile soc07-nse-pcap/nsock/examples/Makefile --- soc07-5184/nsock/examples/Makefile 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/examples/Makefile 2007-07-11 23:06:41.000000000 +0200 @@ -8,6 +8,8 @@ OPENSSLLIB=-lssl -lcrypt INCLS = -I../include -I$(NBASEDIR) CFLAGS = -I/usr/local/include -Wall -g $(CCOPT) $(DEFS) $(INCLS) LDFLAGS = +PCAPBASEDIR=../../libpcap +PCAPLIB=$(PCAPBASEDIR)/libpcap.a RM = rm -f TARGETS = nsock_telnet nsock_test_timers @@ -20,5 +22,8 @@ nsock_telnet: nsock_telnet.o $(NSOCKLIB) nsock_test_timers: nsock_test_timers.o $(NSOCKLIB) $(CC) -o $@ $(CFLAGS) nsock_test_timers.o $(NSOCKLIB) $(NBASELIB) $(OPENSSLLIB) +nsock_pcap: nsock_pcap.o $(NSOCKLIB) $(PCAPLIB) + $(CC) -o $@ $(CFLAGS) nsock_pcap.o $(NSOCKLIB) $(NBASELIB) $(OPENSSLLIB) $(PCAPLIB) + clean: $(RM) *.o $(TARGETS) diff -NraupbwB soc07-5184/nsock/examples/nsock_pcap.c soc07-nse-pcap/nsock/examples/nsock_pcap.c --- soc07-5184/nsock/examples/nsock_pcap.c 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nsock/examples/nsock_pcap.c 2007-07-11 23:06:41.000000000 +0200 @@ -0,0 +1,94 @@ +#include "nsock.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + + @@ -239,6 +243,10 @@ > + + diff -NraupbwB soc07-5184/nsock/src/configure.ac soc07-nse-pcap/nsock/src/configure.ac --- soc07-5184/nsock/src/configure.ac 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/configure.ac 2007-07-11 23:06:41.000000000 +0200 @@ -4,6 +4,88 @@ AC_PREREQ(2.13) dnl Process this file with autoconf to produce a configure script. AC_INIT(nsock_core.c) +dnl use nsock_config.h instad of -D macros +AC_CONFIG_HEADER(nsock_config.h) + +dnl Host specific hacks +AC_CANONICAL_HOST + +linux=no +macosx=no +needs_cpp_precomp=no + +case "$host" in + *alpha-dec-osf*) + AC_DEFINE(DEC) + ;; + *-netbsd* | *-knetbsd*-gnu) + AC_DEFINE(NETBSD) + ;; + *-openbsd*) + AC_DEFINE(OPENBSD) + ;; + *-sgi-irix5*) + AC_DEFINE(IRIX) + ;; + *-sgi-irix6*) + AC_DEFINE(IRIX) + ;; + *-hpux*) + AC_DEFINE(HPUX) + ;; + *-solaris2.0*) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.[[1-9]][[0-9]]*) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.1*) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.2*) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.3*) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.4*) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris2.5.1) + AC_DEFINE(STUPID_SOLARIS_CHECKSUM_BUG) + AC_DEFINE(SOLARIS) + ;; + *-solaris*) + AC_DEFINE(SOLARIS) + ;; + *-sunos4*) + AC_DEFINE(SUNOS) + AC_DEFINE(SPRINTF_RETURNS_STRING) + ;; + *-linux*) + linux=yes + AC_DEFINE(LINUX) + AC_DEFINE(PCAP_TIMEOUT_IGNORED) # libpcap doesn't even LOOK at + # the timeout you give it under Linux + ;; + *-freebsd* | *-kfreebsd*-gnu | *-dragonfly*) + AC_DEFINE(FREEBSD) + ;; + *-bsdi*) + AC_DEFINE(BSDI) + ;; + *-apple-darwin*) + macosx=yes + AC_DEFINE(MACOSX) + ;; +esac + + AC_ARG_WITH(localdirs, [ --with-localdirs Explicitly ask compiler to use /usr/local/{include,libs} if they exist ], [ case "$with_localdirs" in @@ -26,9 +108,6 @@ if test "$user_localdirs" = 1; then fi fi -dnl use nsock_config.h instad of -D macros -AC_CONFIG_HEADER(nsock_config.h) - dnl Checks for programs. AC_PROG_CC if test -n "$GCC"; then @@ -41,9 +120,6 @@ dnl AC_PATH_PROG(MAKEDEPEND, makedepend) AC_SUBST(COMPAT_OBJS) AC_SUBST(COMPAT_SRCS) -dnl Host specific hacks -AC_CANONICAL_HOST - dnl Checks for libraries. dnl AC_CHECK_LIB(m, pow) diff -NraupbwB soc07-5184/nsock/src/error.c soc07-nse-pcap/nsock/src/error.c --- soc07-5184/nsock/src/error.c 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/error.c 2007-07-11 23:06:41.000000000 +0200 @@ -64,15 +64,6 @@ fflush(stdout);vfprintf(stderr, fmt, ap) fprintf(stderr, "\n");va_end(ap); exit(1);} -void myerror(char *fmt, ...) { -va_list ap;va_start(ap, fmt); -fflush(stdout); -vfprintf(stderr, fmt, ap); -fprintf(stderr, "\n"); -va_end(ap); -return; -} - void pfatal(char *fmt, ...) { va_list ap;va_start(ap, fmt); fflush(stdout); diff -NraupbwB soc07-5184/nsock/src/Makefile.in soc07-nse-pcap/nsock/src/Makefile.in --- soc07-5184/nsock/src/Makefile.in 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/Makefile.in 2007-07-11 23:06:41.000000000 +0200 @@ -1,17 +1,18 @@ -NSOCK_VERSION = 0.01 +NSOCK_VERSION = 0.02 prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ mandir = @mandir@ srcdir = @srcdir@ +datarootdir = @datarootdir@ CC = @CC@ AR = ar RANLIB = @RANLIB@ CCOPT = DEFS = @DEFS@ -DNSOCK_VERSION=\"$(NSOCK_VERSION)\" -INCLS = -I../include +INCLS = -I../include -I../../libpcap CFLAGS = @CFLAGS@ $(CCOPT) $(DEFS) $(INCLS) # CFLAGS = -g -Wall $(DEFS) $(INCLS) CPPFLAGS = @CPPFLAGS@ @@ -28,11 +29,11 @@ NBASEDIR=@NBASEDIR@ TARGET = libnsock.a -SRCS = error.c filespace.c gh_list.c nsock_connect.c nsock_core.c nsock_iod.c nsock_read.c nsock_timers.c nsock_write.c nsock_ssl.c nsock_utils.c nsock_event.c nsock_pool.c netutils.c @COMPAT_SRCS@ +SRCS = error.c filespace.c gh_list.c nsock_connect.c nsock_core.c nsock_iod.c nsock_read.c nsock_timers.c nsock_write.c nsock_ssl.c nsock_utils.c nsock_event.c nsock_pool.c netutils.c nsock_pcap.c @COMPAT_SRCS@ -OBJS = error.o filespace.o gh_list.o nsock_connect.o nsock_core.o nsock_iod.o nsock_read.o nsock_timers.o nsock_write.o nsock_ssl.o nsock_utils.o nsock_event.o nsock_pool.o netutils.o @COMPAT_OBJS@ +OBJS = error.o filespace.o gh_list.o nsock_connect.o nsock_core.o nsock_iod.o nsock_read.o nsock_timers.o nsock_write.o nsock_ssl.o nsock_utils.o nsock_event.o nsock_pool.o netutils.o nsock_pcap.o @COMPAT_OBJS@ -DEPS = error.h filespace.h gh_list.h nsock_internal.h nsock_utils.h netutils.h ../include/nsock.h $(NBASEDIR)/libnbase.a +DEPS = error.h filespace.h gh_list.h nsock_internal.h nsock_utils.h netutils.h nsock_pcap.h ../include/nsock.h $(NBASEDIR)/libnbase.a .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ diff -NraupbwB soc07-5184/nsock/src/nsock_config.h.in soc07-nse-pcap/nsock/src/nsock_config.h.in --- soc07-5184/nsock/src/nsock_config.h.in 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_config.h.in 2007-07-11 23:06:41.000000000 +0200 @@ -63,3 +63,14 @@ #undef SPRINTF_RETURNS_STRING +#undef DEC +#undef LINUX +#undef FREEBSD +#undef OPENBSD +#undef SOLARIS +#undef SUNOS +#undef BSDI +#undef IRIX +#undef HPUX +#undef NETBSD +#undef MACOSX diff -NraupbwB soc07-5184/nsock/src/nsock_core.c soc07-nse-pcap/nsock/src/nsock_core.c --- soc07-5184/nsock/src/nsock_core.c 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_core.c 2007-07-11 23:06:41.000000000 +0200 @@ -81,6 +81,11 @@ #include "netutils.h" +#if HAVE_PCAP +#include "nsock_pcap.h" +static int pcap_read_on_nonselect(mspool *nsp); +#endif + /* Msock time of day -- we update this at least once per nsock_loop round (and after most calls that are likely to block). Other nsock files should grab this @@ -105,6 +110,9 @@ static int wait_for_events(mspool *ms, i return 0; /* No need to wait on 0 events ... */ do { + if (ms->tracelevel > 3) + nsock_trace(ms, "wait_for_events"); + if (ms->evl.next_ev.tv_sec == 0) { event_msecs = -1; /* None of the events specified a timeout */ } else { @@ -131,6 +139,7 @@ static int wait_for_events(mspool *ms, i select_tv_p = NULL; } + /* Figure out whether there are any FDs in the sets, as @$@!$# Windows returns WSAINVAL (10022) if you call a select() with no FDs, even though the Linux man page says that doing so is a @@ -144,6 +153,13 @@ static int wait_for_events(mspool *ms, i else ms->mioi.max_sd--; } +#if HAVE_PCAP + /* do non-blocking read on pcap devices that doesn't support select() + * If there is anything read, don't do usleep() or select(), just leave this loop */ + if (pcap_read_on_nonselect(ms)) { + /* okay, something was read. */ + } else +#endif if (ms->mioi.max_sd < 0) { ms->mioi.results_left = 0; if (combined_msecs > 0) @@ -161,7 +177,7 @@ static int wait_for_events(mspool *ms, i } gettimeofday(&nsock_tod, NULL); /* Due to usleep or select delay */ - } while (ms->mioi.results_left == -1 && sock_err == EINTR); + } while (ms->mioi.results_left == -1 && sock_err == EINTR);// repeat only if signal occured if (ms->mioi.results_left == -1 && sock_err != EINTR) { ms->errnum = sock_err; @@ -650,6 +666,77 @@ void handle_read_result(mspool *ms, msev return; } +#if HAVE_PCAP +void handle_pcap_read_result(mspool *ms, msevent *nse, + enum nse_status status) +{ + msiod *iod = nse->iod; + mspcap *mp = (mspcap *) iod->pcap; + + + if (status == NSE_STATUS_TIMEOUT) { + nse->status = NSE_STATUS_TIMEOUT; + nse->event_done = 1; + } else if (status == NSE_STATUS_CANCELLED) { + nse->status = NSE_STATUS_CANCELLED; + nse->event_done = 1; + } else if (status == NSE_STATUS_SUCCESS) { + /* check if we already have something read */ + if(FILESPACE_LENGTH(&(nse->iobuf)) == 0){ + nse->status = NSE_STATUS_TIMEOUT; + nse->event_done = 0; + }else{ + nse->status = NSE_STATUS_SUCCESS;/* we have full buffer */ + nse->event_done = 1; + } + } else { + assert(0); /* Currently we only know about TIMEOUT, CANCELLED, and SUCCESS callbacks */ + } + + /* If we asked for an event dispatch, we are done reading on the socket so + we can take it off the descriptor list ... */ + if (nse->event_done && mp->pcap_desc >= 0) { + FD_CLR(mp->pcap_desc, &ms->mioi.fds_master_r); + FD_CLR(mp->pcap_desc, &ms->mioi.fds_results_r); + } + return; +} + +/* + * returns number of descriptors on which data was read + * */ +static int pcap_read_on_nonselect(mspool *nsp) +{ + gh_list *event_list = &nsp->evl.pcap_read_events; + gh_list_elem *current, *next; + msevent *nse; + int rc; + int ret = 0; + + if (nsp->tracelevel > 3) + nsock_trace(nsp, "PCAP read_on_nonselect"); + + for(current = GH_LIST_FIRST_ELEM(event_list); + current != NULL; current = next) { + + nse = (msevent *) GH_LIST_ELEM_DATA(current); + rc = do_actual_pcap_read(nse); + if(rc==1){ /* something received */ + ret++; + break; + } + next = GH_LIST_ELEM_NEXT(current); + } + if (nsp->tracelevel > 3) + nsock_trace(nsp, "PCAP END read_on_nonselect"); + + return(ret); +} +#endif // HAVE_PCAP + + + + /* Iterate through all the event lists (such as connect_events, read_events, timer_events, etc) and take action for those that have completed (due to timeout, i/o, etc) */ @@ -665,6 +752,9 @@ static void iterate_through_event_lists( &nsp->evl.read_events, &nsp->evl.write_events, &nsp->evl.timer_events, + #if HAVE_PCAP + &nsp->evl.pcap_read_events, + #endif 0 }; int current_list_idx; @@ -682,9 +772,20 @@ static void iterate_through_event_lists( */ /* foreach list */ + if (nsp->tracelevel > 7){ + for(current_list_idx = 0; event_lists[current_list_idx] != NULL; + current_list_idx++) { + nsock_trace(nsp, "before iterating, list %i", current_list_idx); + for(current = GH_LIST_FIRST_ELEM(event_lists[current_list_idx]); + current != NULL; current = GH_LIST_ELEM_NEXT(current)) { + nse = (msevent *) GH_LIST_ELEM_DATA(current); + nsock_trace(nsp, "before iterating %lu",nse->id); + } + } + } + /* foreach list */ for(current_list_idx = 0; event_lists[current_list_idx] != NULL; current_list_idx++) { - /* foreach element in the list */ for(current = GH_LIST_FIRST_ELEM(event_lists[current_list_idx]); current != NULL; current = next) { @@ -688,8 +789,10 @@ static void iterate_through_event_lists( /* foreach element in the list */ for(current = GH_LIST_FIRST_ELEM(event_lists[current_list_idx]); current != NULL; current = next) { - nse = (msevent *) GH_LIST_ELEM_DATA(current); + if (nsp->tracelevel > 7) + nsock_trace(nsp, "list %i, iterating %lu",current_list_idx, nse->id); + if ( ! nse->event_done) { switch(nse->type) { case NSE_TYPE_CONNECT: @@ -751,6 +854,49 @@ static void iterate_through_event_lists( } break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ:{ + if (nsp->tracelevel > 5) + nsock_trace(nsp, "PCAP iterating %lu",nse->id); + + /* buffer empty? check it! */ + if ( FILESPACE_LENGTH(&(nse->iobuf))==0 ) + do_actual_pcap_read(nse); + + /* if already received smth */ + if ( FILESPACE_LENGTH(&(nse->iobuf))>0 ) + handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS); + + if (!nse->event_done && nse->timeout.tv_sec && + TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod) <= 0) + handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT); + + #if PCAP_BSD_SELECT_HACK + /* If event occured, and we're in BSD_HACK mode, than this event was added + * to two queues. evl.read_event and evl.pcap_read_event + * Of coure we should destroy it only once. + * I assume we're now in evl.read_event, co just unlink this event from + * evl.pcap_read_event */ + if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 && + nse->event_done && + event_lists[current_list_idx] == &nsp->evl.read_events){ + /* event is done, list is read_events and we're in BSD_HACK mode. + * So unlink event from pcap_read_events */ + gh_list_remove(&nsp->evl.pcap_read_events, nse); + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); + } + if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 && + nse->event_done && + event_lists[current_list_idx] == &nsp->evl.pcap_read_events){ + gh_list_remove(&nsp->evl.read_events, nse); + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); + } + #endif + break; + } +#endif default: fatal("Event has unknown type (%d)", nse->type); break; /* unreached */ @@ -758,6 +904,9 @@ static void iterate_through_event_lists( } if (nse->event_done) { + if (nsp->tracelevel > 8) + nsock_trace(nsp, "NSE #%lu: Removing event from event_lists[%i]", nse->id, current_list_idx); + /* WooHoo! The event is ready to be sent */ msevent_dispatch_and_delete(nsp, nse, 1); next = GH_LIST_ELEM_NEXT(current); @@ -862,6 +1011,8 @@ const struct timeval *nsock_gettimeofday such as adjusting the descriptor select/poll lists, registering the timeout value, etc. */ void nsp_add_event(mspool *nsp, msevent *nse) { + if (nsp->tracelevel > 5) + nsock_trace(nsp, "NSE #%lu: Adding event", nse->id); /* First lets do the event-type independant stuff -- starting with timeouts */ @@ -918,6 +1069,36 @@ void nsp_add_event(mspool *nsp, msevent gh_list_prepend(&nsp->evl.timer_events, nse); break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ:{ + mspcap *mp = (mspcap *) nse->iod->pcap; + assert(mp); + if(mp->pcap_desc >= 0){ /* pcap descriptor present */ + if(!nse->event_done){ + FD_SET(mp->pcap_desc, &nsp->mioi.fds_master_r); + nsp->mioi.max_sd = MAX(nsp->mioi.max_sd, mp->pcap_desc); + } + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id); + gh_list_prepend(&nsp->evl.read_events, nse); + + #if PCAP_BSD_SELECT_HACK + /* when using BSD hack we must do pcap_next() after select(). + * Let's insert this pcap to bot queues, to selectable and nonselectable. + * This will result in doing pcap_next_ex() just before select() */ + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); + gh_list_prepend(&nsp->evl.pcap_read_events, nse); + #endif + }else{ /* pcap isn't selectable. Add it to pcap-specific queue. */ + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id); + gh_list_prepend(&nsp->evl.pcap_read_events, nse); + } + break; + } +#endif + default: assert(0); break; /* unreached */ @@ -1010,6 +1191,17 @@ void nsock_trace_handler_callback(mspool nsock_trace(ms, "Callback: %s %s %sfor EID %li", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); + + break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + nsock_trace(ms, "Callback: %s %s %sfor EID %li ", + nse_type2str(nse->type), nse_status2str(nse->status), + errstr, nse->id); + break; +#endif + default: + assert(0); break; } diff -NraupbwB soc07-5184/nsock/src/nsock_event.c soc07-nse-pcap/nsock/src/nsock_event.c --- soc07-5184/nsock/src/nsock_event.c 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_event.c 2007-07-11 23:06:41.000000000 +0200 @@ -61,6 +61,10 @@ #include "nsock_internal.h" #include "gh_list.h" +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + #include extern struct timeval nsock_tod; @@ -125,6 +129,7 @@ int nsock_event_cancel(nsock_pool ms_poo mspool *nsp = (mspool *) ms_pool; enum nse_type type = get_event_id_type(id); gh_list *event_list = NULL; + gh_list *event_list2 = NULL; gh_list_elem *current, *next; msevent *nse = NULL; @@ -148,6 +153,12 @@ int nsock_event_cancel(nsock_pool ms_poo case NSE_TYPE_TIMER: event_list = &nsp->evl.timer_events; break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + event_list = &nsp->evl.read_events; + event_list2 = &nsp->evl.pcap_read_events; + break; +#endif default: fatal("Bogus event type in nsock_event_cancel"); break; } @@ -161,6 +172,16 @@ int nsock_event_cancel(nsock_pool ms_poo break; } + if (current == NULL && event_list2){ + event_list = event_list2; + for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL; + current = next) { + next = GH_LIST_ELEM_NEXT(current); + nse = (msevent *) GH_LIST_ELEM_DATA(current); + if (nse->id == id) + break; + } + } if (current == NULL) return 0; @@ -201,10 +222,51 @@ int msevent_cancel(mspool *nsp, msevent case NSE_TYPE_TIMER: handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED); break; +#if HAVE_PCAP + case NSE_TYPE_PCAP_READ: + handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED); + break; +#endif + default: + assert(0); } assert(nse->event_done); gh_list_remove_elem(event_list, elem); + if (nsp->tracelevel > 8) + nsock_trace(nsp, "NSE #%lu: Removing event from some event_list", nse->id); + +#if HAVE_PCAP +#if PCAP_BSD_SELECT_HACK + if(nse->type==NSE_TYPE_PCAP_READ){ + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: CANCELL TEST el.pcap=%x el.read=%x el.curr=%x sd=%i", + nse->id, &nsp->evl.pcap_read_events, &nsp->evl.read_events, event_list,((mspcap *) nse->iod->pcap)->pcap_desc ); + /* If event occured, and we're in BSD_HACK mode, than this event was added + * to two queues. evl.read_event and evl.pcap_read_event + * Of coure we should destroy it only once. + * I assume we're now in evl.read_event, co just unlink this event from + * evl.pcap_read_event */ + + if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 && + event_list == &nsp->evl.read_events){ + /* event is done, list is read_events and we're in BSD_HACK mode. + * So unlink event from pcap_read_events */ + gh_list_remove(&nsp->evl.pcap_read_events, nse); + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); + } + if(((mspcap *) nse->iod->pcap)->pcap_desc >= 0 && + event_list == &nsp->evl.pcap_read_events){ + /* event is done, list is read_events and we're in BSD_HACK mode. + * So unlink event from pcap_read_events */ + gh_list_remove(&nsp->evl.read_events, nse); + if (nsp->tracelevel > 8) + nsock_trace(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); + } + } +#endif +#endif msevent_dispatch_and_delete(nsp, nse, notify); @@ -252,7 +314,7 @@ nsock_event_id get_new_event_id(mspool * unsigned long serial = ms->next_event_serial++; unsigned long max_serial_allowed; int shiftbits; - assert(type <= 4); + assert(type < NSE_TYPE_MAX); shiftbits = sizeof(nsock_event_id) * 8 - TYPE_CODE_NUM_BITS; max_serial_allowed = ( 1 << shiftbits ) - 1; @@ -299,6 +361,15 @@ msevent *msevent_new(mspool *nsp, enum n if (type == NSE_TYPE_READ || type == NSE_TYPE_WRITE) { filespace_init(&(nse->iobuf), 1024); } +#if HAVE_SSL + if (type == NSE_TYPE_PCAP_READ) { + mspcap *mp = (mspcap *) nsi->pcap; + assert(mp); + int sz = mp->snaplen+1 + sizeof(nsock_pcap); + filespace_init(&(nse->iobuf), sz); + } +#endif + if (timeout_msecs != -1) { assert(timeout_msecs >= 0); TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs); @@ -307,6 +378,12 @@ msevent *msevent_new(mspool *nsp, enum n nse->handler = handler; nse->userdata = userdata; nse->time_created = nsock_tod; + + if (nsp->tracelevel > 3) + nsock_trace(nsp, "msevent_new (IOD #%li) (EID #%li)", + nse->iod->id, + nse->id); + return nse; } @@ -317,10 +394,22 @@ msevent *msevent_new(mspool *nsp, enum n remember to do this if you call msevent_delete() directly */ void msevent_delete(mspool *nsp, msevent *nse) { + if (nsp->tracelevel > 3) + nsock_trace(nsp, "msevent_delete (IOD #%li) (EID #%li)", + nse->iod->id, + nse->id); + /* First free the IOBuf inside it if neccessary */ if (nse->type == NSE_TYPE_READ || nse->type == NSE_TYPE_WRITE) { fs_free(&nse->iobuf); } + #if HAVE_PCAP + if (nse->type == NSE_TYPE_PCAP_READ) { + fs_free(&nse->iobuf); + if (nsp->tracelevel > 5) + nsock_trace(nsp, "PCAP removed %lu\n",nse->id); + } + #endif /* Now we add the event back into the free pool */ gh_list_prepend(&nsp->evl.free_events, nse); @@ -337,6 +426,7 @@ const char *nse_type2str(enum nse_type t case NSE_TYPE_READ: return "READ"; case NSE_TYPE_WRITE: return "WRITE"; case NSE_TYPE_TIMER: return "TIMER"; + case NSE_TYPE_PCAP_READ: return "READ-PCAP"; default: return "UNKNOWN!"; } diff -NraupbwB soc07-5184/nsock/src/nsock_internal.h soc07-nse-pcap/nsock/src/nsock_internal.h --- soc07-5184/nsock/src/nsock_internal.h 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_internal.h 2007-07-11 23:06:41.000000000 +0200 @@ -136,6 +136,9 @@ struct event_lists { gh_list read_events; gh_list write_events; gh_list timer_events; + #if HAVE_PCAP + gh_list pcap_read_events; + #endif gh_list free_events; /* When an event is deleted, we stick it here for later reuse */ struct timeval next_ev; /* The soonest time that either a timer event goes @@ -226,6 +229,8 @@ struct msiod { unsigned long id; /* Every iod has an id which is always unique for the same nspool (unless you create billions of them) */ void *userdata; + + void *pcap; /* Pointer to mspcap struct (used only if pcap support is included) */ }; @@ -321,6 +326,11 @@ void handle_write_result(mspool *ms, mse void handle_timer_result(mspool *ms, msevent *nse, enum nse_status status); +#if HAVE_PCAP +void handle_pcap_read_result(mspool *ms, msevent *nse, + enum nse_status status); +#endif + void nsock_trace(mspool *ms, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); diff -NraupbwB soc07-5184/nsock/src/nsock_iod.c soc07-nse-pcap/nsock/src/nsock_iod.c --- soc07-5184/nsock/src/nsock_iod.c 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_iod.c 2007-07-11 23:06:41.000000000 +0200 @@ -63,6 +63,10 @@ #include "gh_list.h" #include "netutils.h" +#if HAVE_PCAP +#include "nsock_pcap.h" +#endif + #include /* nsock_iod is like a "file descriptor" for the nsock library. You @@ -207,6 +211,26 @@ void nsi_delete(nsock_iod nsockiod, int nsi->state = NSIOD_STATE_DELETED; nsi->userdata = NULL; +#if HAVE_PCAP + if(nsi->pcap){ + mspcap *mp = (mspcap *) nsi->pcap; + if(mp->pt){ + pcap_close(mp->pt); + mp->pt=NULL; + } + if(mp->pcap_desc){ + // Should I close pcap_desc or pcap_close does this for me? + mp->pcap_desc = -1; + } + if(mp->pcap_device){ + free(mp->pcap_device); + mp->pcap_device = NULL; + } + free(mp); + nsi->pcap = NULL; + } +#endif + gh_list_remove_elem(&nsi->nsp->active_iods, nsi->entry_in_nsp_active_iods); gh_list_prepend(&nsi->nsp->free_iods, nsi); diff -NraupbwB soc07-5184/nsock/src/nsock_pcap.c soc07-nse-pcap/nsock/src/nsock_pcap.c --- soc07-5184/nsock/src/nsock_pcap.c 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nsock/src/nsock_pcap.c 2007-07-11 23:06:41.000000000 +0200 @@ -0,0 +1,370 @@ +#include "nsock.h" +#include "nsock_internal.h" +#include "nsock_pcap.h" +#include + +#if HAVE_PCAP +static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl); +char * nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf); + +/* + * Convert new nsiod to pcap descriptor. Other parameters have the + * same meaning as for pcap_open_live in pcap(3). + * device : pcap-style device name + * snaplen : size of packet to be copied to hanler + * promisc : whether to open device in promiscous mode + * bpf_fmt : berkeley filter + * return value: NULL if everything was okay, or error string if error occurred + * */ +char* nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, + const char *pcap_device, int snaplen, int promisc, + const char *bpf_fmt, ...) + +{ + msiod *nsi = (msiod *) nsiod; + mspool *ms = (mspool *) nsp; + mspcap *mp = (mspcap *) nsi->pcap; + static char errorbuf[128]; + + if(mp) return "nsock-pcap: this nsi already has pcap device opened"; + + mp = (mspcap *)safe_malloc(sizeof(mspcap)); + nsi->pcap = (void*)mp; + + char err0r[PCAP_ERRBUF_SIZE]; + + #ifdef PCAP_CAN_DO_SELECT + #if PCAP_BSD_SELECT_HACK + /* MacOsX reports error if to_ms is too big (like INT_MAX) with error + * FAILED. Reported error: BIOCSRTIMEOUT: Invalid argument + * INT_MAX/6 (=357913941) seems to be working...*/ + int to_ms = 357913941; + #else + int to_ms = 200; + #endif + #else + int to_ms = 1; + #endif + + /* packet filter string */ + char bpf[4096]; + va_list ap; + + va_start(ap, bpf_fmt); + if(vsnprintf(bpf, sizeof(bpf), bpf_fmt, ap) >= (int) sizeof(bpf)){ + va_end(ap); + return "nsock-pcap: nsock_pcap_open called with too-large bpf filter arg"; + } + va_end(ap); + + if (ms->tracelevel > 0) + nsock_trace(ms, "PCAP requested on device '%s' with berkeley filter '%s' (promisc=%i snaplen=%i to_ms=%i) (IOD #%li)", + pcap_device,bpf, promisc, snaplen, to_ms, nsi->id); + + int failed = 0; + do { + mp->pt = pcap_open_live((char*)pcap_device, snaplen, promisc, to_ms, err0r); + if (mp->pt) /* okay, opened!*/ + break; + /* sorry, something failed*/ + if (++failed >= 3) { + fprintf(stderr, + "Call to pcap_open_live(%s, %d, %d, %d) failed three times. Reported error: %s\n" + "There are several possible reasons for this, depending on your operating system:\n" + "LINUX: If you are getting Socket type not supported, try modprobe af_packet or recompile your kernel with SOCK_PACKET enabled.\n" + "*BSD: If you are getting device not configured, you need to recompile your kernel with Berkeley Packet Filter support. If you are getting No such file or directory, try creating the device (eg cd /dev; MAKEDEV ; or use mknod).\n" + "*WINDOWS: Nmap only supports ethernet interfaces on Windows for most operations because Microsoft disabled raw sockets as of Windows XP SP2. Depending on the reason for this error, it is possible that the --unprivileged command-line argument will help.\n" + "SOLARIS: If you are trying to scan localhost and getting '/dev/lo0: No such file or directory', complain to Sun. I don't think Solaris can support advanced localhost scans. You can probably use \"-P0 -sT localhost\" though.\n\n", + pcap_device, snaplen, promisc, to_ms, err0r); + return "nsock-pcap: can't open pcap! are you root?"; + } + + fprintf(stderr, "pcap_open_live(%s, %d, %d, %d) FAILED. Reported error: %s. Will wait %d seconds then retry.\n", + pcap_device, snaplen, promisc, to_ms, err0r, 4*failed); + sleep(4* failed); + }while(1); + + char *e = nsock_pcap_set_filter(mp->pt, pcap_device, bpf); + if(e) return e; + + + #ifdef WIN32 + /* We want any responses back ASAP */ + pcap_setmintocopy(mp->pt, 1); + + /* If there are no packets left to read exit after to_ms miliseconds*/ + PacketSetReadTimeout(mp->pt->adapter, to_ms); + #endif + + int datalink; + mp->l3_offset = nsock_pcap_get_l3_offset(mp->pt, &datalink); + mp->snaplen = snaplen; + mp->datalink = datalink; + mp->pcap_device = strdup(pcap_device); + #ifdef PCAP_CAN_DO_SELECT + mp->pcap_desc = pcap_get_selectable_fd(mp->pt); + #else + mp->pcap_desc = -1; + #endif + + /* Set device non-blocking */ + if(pcap_setnonblock(mp->pt, 1, err0r) < 0){ + /* I can't do select() on pcap! blockig + no_select is fatal */ + if(mp->pcap_desc < 0){ + snprintf(errorbuf, sizeof(errorbuf),"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); + return errorbuf; + } + + /* When we use bsd hack we also need to set non-blocking */ + #ifdef PCAP_BSD_SELECT_HACK + snprintf(errorbuf, sizeof(errorbuf),"nsock-pcap: Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); + return errorbuf; + #endif + + /* in other case, we can accept blocking pcap */ + fprintf(stderr, "Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); + } + + if (ms->tracelevel > 0) + nsock_trace(ms, "PCAP created successfully on device '%s' (pcap_desc=%i bsd_hack=%i to_valid=%i l3_offset=%i) (IOD #%li)", + pcap_device, + mp->pcap_desc, + #if PCAP_BSD_SELECT_HACK + 1, + #else + 0, + #endif + #if PCAP_RECV_TIMEVAL_VALID + 1, + #else + 0, + #endif + mp->l3_offset, + nsi->id); + return NULL; +} + +char *nsock_pcap_set_filter(pcap_t *pt, const char *device, const char *bpf) +{ + struct bpf_program fcode; + #ifndef __amigaos__ + unsigned int localnet, netmask; + #else + bpf_u_int32 localnet, netmask; + #endif + char err0r[PCAP_ERRBUF_SIZE]; + static char errorbuf[128]; + + // Cast below is becaue OpenBSD apparently has a version that takes a + // non-const device (hopefully they don't actually write to it). + if (pcap_lookupnet( (char *) device, &localnet, &netmask, err0r) < 0){ + snprintf(errorbuf, sizeof(errorbuf), "Failed to lookup subnet/netmask for device (%s): %s", device, err0r); + return errorbuf; + } + + // log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", device, buf); + + if (pcap_compile(pt, &fcode, (char*)bpf, 1, netmask) < 0){ + snprintf(errorbuf, sizeof(errorbuf), "Error compiling our pcap filter: %s\n", pcap_geterr(pt)); + return errorbuf; + } + + if (pcap_setfilter(pt, &fcode) < 0 ){ + snprintf(errorbuf, sizeof(errorbuf),"Failed to set the pcap filter: %s\n", pcap_geterr(pt)); + return errorbuf; + } + + pcap_freecode(&fcode); + return NULL; +} + +static int nsock_pcap_get_l3_offset(pcap_t *pt, int *dl){ + int datalink; + unsigned int offset = 0; + + /* New packet capture device, need to recompute offset */ + if ( (datalink = pcap_datalink(pt)) < 0) + fatal("Cannot obtain datalink information: %s", pcap_geterr(pt)); + + /* NOTE: IF A NEW OFFSET EVER EXCEEDS THE CURRENT MAX (24), ADJUST + MAX_LINK_HEADERSZ in tcpip.h */ + switch(datalink) { + case DLT_EN10MB: offset = 14; break; + case DLT_IEEE802: offset = 22; break; + #ifdef __amigaos__ + case DLT_MIAMI: offset = 16; break; + #endif + #ifdef DLT_LOOP + case DLT_LOOP: + #endif + case DLT_NULL: offset = 4; break; + + case DLT_SLIP: + #ifdef DLT_SLIP_BSDOS + case DLT_SLIP_BSDOS: + #endif + #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX) + offset = 16;break; + #else + offset = 24;break; /* Anyone use this??? */ + #endif + + case DLT_PPP: + #ifdef DLT_PPP_BSDOS + case DLT_PPP_BSDOS: + #endif + #ifdef DLT_PPP_SERIAL + case DLT_PPP_SERIAL: + #endif + #ifdef DLT_PPP_ETHER + case DLT_PPP_ETHER: + #endif + #if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX) + offset = 4;break; + #else + #ifdef SOLARIS + offset = 8;break; + #else + offset = 24;break; /* Anyone use this? */ + #endif /* ifdef solaris */ + #endif /* if freebsd || openbsd || netbsd || bsdi */ + case DLT_RAW: offset = 0; break; + case DLT_FDDI: offset = 21; break; + #ifdef DLT_ENC + case DLT_ENC: offset = 12; break; + #endif /* DLT_ENC */ + #ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: offset = 16; break; + #endif + + default: /* Sorry, link type is unknown. */ + fatal("Unknown datalink type %d.\n", datalink); + } + if(dl) + *dl = datalink; + return(offset); +} + + +/* + * Requests exacly one packet to be captured. + * */ +nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, int timeout_msecs, + void *userdata) +{ + msiod *nsi = (msiod *) nsiod; + mspool *ms = (mspool *) nsp; + msevent *nse; + + nse = msevent_new(ms, NSE_TYPE_PCAP_READ, nsi, timeout_msecs, handler, userdata); + assert(nse); + + if (ms->tracelevel > 0) { + nsock_trace(ms, "Pcap read request from IOD #%li EID %li", + nsi->id, nse->id); + } + + nsp_add_event(ms, nse); + + return nse->id; +} + +/* + * Remember that pcap descriptor is in nonblocking state. */ +int do_actual_pcap_read(msevent *nse) +{ + msiod *iod = nse->iod; + mspcap *mp = (mspcap *) iod->pcap; + + nsock_pcap npp; + nsock_pcap *n; + memset(&npp, 0, sizeof(nsock_pcap)); + + if (nse->iod->nsp->tracelevel > 2) + nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read TEST (IOD #%li) (EID #%li)", + nse->iod->id, nse->id); + + assert( FILESPACE_LENGTH(&(nse->iobuf)) == 0 ); + + struct pcap_pkthdr *pkt_header; + const unsigned char *pkt_data = NULL; + int rc = pcap_next_ex(mp->pt, &pkt_header, &pkt_data); + switch(rc){ + case 1: /* read good packet */ + #ifdef PCAP_RECV_TIMEVAL_VALID + npp.ts = pkt_header->ts; + #else + /* on these platforms time received from pcap is invalid. It's better to set current time */ + memcpy(&npp.ts, nsock_gettimeofday(), sizeof(struct timeval)); + #endif + npp.len = pkt_header->len; + npp.caplen = pkt_header->caplen; + npp.packet = pkt_data; + fscat(&(nse->iobuf), (char*)&npp, sizeof(npp)); + fscat(&(nse->iobuf), (char*)pkt_data, npp.caplen); + n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf)); + n->packet = (unsigned char*)FILESPACE_STR(&(nse->iobuf))+sizeof(npp); + if (nse->iod->nsp->tracelevel > 2) + nsock_trace(nse->iod->nsp, "PCAP do_actual_pcap_read READ (IOD #%li) (EID #%li) size=%i", + nse->iod->id, nse->id, pkt_header->caplen); + return(1); + case 0: /* timeout */ + return(0); + case -1: /* error */ + fatal("pcap_next_ex() fatal error while reading from pcap: %s\n", pcap_geterr(mp->pt)); + break; + case -2: /* no more packets in savefile (if reading from one) */ + default: + assert(0); + } + return 0; +} + +void nse_readpcap(nsock_event nsee, + const unsigned char **l2_data, size_t *l2_len, + const unsigned char **l3_data, size_t *l3_len, + size_t *packet_len, struct timeval *ts) +{ + msevent *nse = (msevent *)nsee; + msiod *iod = nse->iod; + mspcap *mp = (mspcap *) iod->pcap; + + nsock_pcap *n = (nsock_pcap *) FILESPACE_STR(&(nse->iobuf)); + if(FILESPACE_LENGTH(&(nse->iobuf)) < sizeof(nsock_pcap)){ + if(l2_data) *l2_data = NULL; + if(l2_len ) *l2_len = 0; + if(l3_data) *l3_data = NULL; + if(l3_len ) *l3_len = 0; + if(packet_len) *packet_len = 0; + return; + } + + size_t l2l = MIN(mp->l3_offset, n->caplen); + size_t l3l = MAX(0, n->caplen-mp->l3_offset); + + if(l2_data) *l2_data = n->packet; + if(l2_len ) *l2_len = l2l; + if(l3_data) *l3_data = l3l>0? n->packet+l2l : NULL; + if(l3_len ) *l3_len = l3l; + if(packet_len) *packet_len = n->len; + if(ts) *ts = n->ts; + return; +} + +int nsi_pcap_linktype(nsock_iod nsiod){ + msiod *nsi = (msiod *) nsiod; + mspcap *mp = (mspcap *) nsi->pcap; + assert(mp); + return(mp->datalink); +} + +int nsi_is_pcap(nsock_iod nsiod){ + msiod *nsi = (msiod *) nsiod; + mspcap *mp = (mspcap *) nsi->pcap; + return(mp!=NULL); +} + + +#endif // HAVE_PCAP + diff -NraupbwB soc07-5184/nsock/src/nsock_pcap.h soc07-nse-pcap/nsock/src/nsock_pcap.h --- soc07-5184/nsock/src/nsock_pcap.h 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/nsock/src/nsock_pcap.h 2007-07-11 23:06:41.000000000 +0200 @@ -0,0 +1,85 @@ +#ifndef NSOCK_PCAP_H +#define NSOCK_PCAP_H + +#include "nsock_internal.h" +#ifdef HAVE_PCAP + +#ifdef WIN32 +#include "mswin32\winclude.h" +#include "pcap-int.h" +#endif + +#include "pcap.h" + +#include +#include + + +/* + * There are three possible ways of reading packets from pcap descriptor: + * do select() on descriptor -> this one is of course the best, but + * there are systems that don't support this like WIN32 + * This works perfectly for Linux. + * do select() but whith some hacks -> this one is hack for older bsd + * systems, Descriptor *must* be set in nonblocking mode. + * never do select() -> this one is for WIN32 and other systems that + * return descriptor -1 from pcap_get_selectable_fd() + * In this case descriptor *must* be set in nonblocking mode. + * If that fails than we can't do any sniffing from that box. + * + * In all cases we try to set descriptor to non-blocking mode. + * */ + +// Returns whether the system supports pcap_get_selectable_fd() properly +#if !defined(WIN32) +#define PCAP_CAN_DO_SELECT 1 +#endif + +/* + * Note that on most versions of most BSDs (including Mac OS X) select() and poll() do not work + * correctly on BPF devices; pcap_get_selectable_fd() will return a file descriptor on most of those + * versions (the exceptions being FreeBSD 4.3 and 4.4), a simple select() or poll() will + * not return even after a timeout specified in pcap_open_live() expires. To work around + * this, an application that uses select() or poll() to wait for packets to arrive must put + * the pcap_t in non-blocking mode, and must arrange that the select() or poll() have a timeout + * less than or equal to the timeout specified in pcap_open_live(), and must try to read packets + * after that timeout expires, regardless of whether select() or poll() indicated that the file + * descriptor for the pcap_t is ready to be read or not. (That workaround will not work in + * FreeBSD 4.3 and later; however, in FreeBSD 4.6 and later, select() and poll() work correctly + * on BPF devices, so the workaround isn't necessary, although it does no harm.) + */ +#if defined(MACOSX) || defined(FREEBSD) || defined(OPENBSD) +// Well, now select() is not receiving any pcap events on MACOSX, but maybe it will someday :) +// in both cases. It never hurts to enable this feature. It just has performance penalty. +#define PCAP_BSD_SELECT_HACK 1 +#endif + +// Returns whether the packet receive time value obtained from libpcap +// (and thus by readip_pcap()) should be considered valid. When +// invalid (Windows and Amiga), readip_pcap returns the time you called it. +#if !defined(WIN32) && !defined(__amigaos__) +#define PCAP_RECV_TIMEVAL_VALID 1 +#endif + + +typedef struct{ + pcap_t *pt; + int pcap_desc; + int datalink; + int l3_offset; + int snaplen; + char *pcap_device; +} mspcap; + + +typedef struct{ + struct timeval ts; + int caplen; + int len; + const unsigned char *packet; // caplen bytes +} nsock_pcap; + +int do_actual_pcap_read(msevent *nse); + +#endif /* HAVE_PCAP */ +#endif /* NSOCK_PCAP_H */ diff -NraupbwB soc07-5184/nsock/src/nsock_pool.c soc07-nse-pcap/nsock/src/nsock_pool.c --- soc07-5184/nsock/src/nsock_pool.c 2007-07-10 18:15:24.000000000 +0200 +++ soc07-nse-pcap/nsock/src/nsock_pool.c 2007-07-11 23:06:41.000000000 +0200 @@ -168,6 +168,9 @@ nsock_pool nsp_new(void *userdata) { gh_list_init(&nsp->evl.read_events); gh_list_init(&nsp->evl.write_events); gh_list_init(&nsp->evl.timer_events); + #if HAVE_PCAP + gh_list_init(&nsp->evl.pcap_read_events); + #endif gh_list_init(&nsp->evl.free_events); nsp->evl.next_ev.tv_sec = 0; nsp->evl.events_pending = 0; @@ -192,6 +195,9 @@ void nsp_delete(nsock_pool ms_pool) { &nsp->evl.read_events, &nsp->evl.write_events, &nsp->evl.timer_events, + #if HAVE_PCAP + &nsp->evl.pcap_read_events, + #endif 0 }; int current_list_idx; diff -NraupbwB soc07-5184/scripts/p0fa.fp soc07-nse-pcap/scripts/p0fa.fp --- soc07-5184/scripts/p0fa.fp 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/scripts/p0fa.fp 2007-07-11 23:06:41.000000000 +0200 @@ -0,0 +1,208 @@ +# +# p0f - SYN+ACK fingerprints +# -------------------------- +# +# .-------------------------------------------------------------------------. +# | The purpose of this file is to cover signatures for outgoing TCP/IP | +# | connections (SYN+ACK packets). This mode of operation can be enabled | +# | with -A option. Please refer to p0f.fp for information on the metrics | +# | used to create a signature, and for a guide on adding new entries to | +# | those files. This database is somewhat neglected, and is looking for a | +# | caring maintainer. | +# `-------------------------------------------------------------------------' +# +# (C) Copyright 2000-2006 by Michal Zalewski +# +# Plenty of signatures contributed in bulk by rain forest puppy, Paul Woo and +# Michael Bauer. +# +# Submit all additions to the authors. Read p0f.fp before adding any +# signatures. Run p0f -A -C after making any modifications. This file is +# NOT compatible with SYN, RST+, or stray ACK modes. Use only with -A option. +# +# Feel like contributing? You can run p0f -A -K, then test/tryid -iR nnn... +# +# IMPORTANT INFORMATION ABOUT THE INTERDEPENDENCY OF SYNs AND SYN+ACKs +# -------------------------------------------------------------------- +# +# Some systems would have different SYN+ACK fingerprints depending on +# the system that sent SYN. More specifically, RFC1323, RFC2018 and +# RFC1644 extensions sometimes show up only if SYN had them enabled. +# +# Also, some silly systems may copy WSS from the SYN packet you've sent, +# in which case, you need to wildcard the value. Use test/sendsyn.c, which +# uses a distinct WSS of 12345, to test for this condition if unsure. +# +# IMPORTANT INFORMATION ABOUT DIFFERENCES IN COMPARISON TO p0f.fp: +# ---------------------------------------------------------------- +# +# - 'A' quirk would be present on almost every signature here. ACK number +# is unusual for SYN packets, but is a commonplace in SYN+ACK packets, +# of course. It is still possible to have a signature without 'A', when +# the ACK flag is present but the value is zero - this, however, is +# very uncommon. +# +# - 'T' quirk would show up on almost all signatures for systems implementing +# RFC1323. The second timestamp is only unusual for SYN packets. SYN+ACK +# are expected to have it set. +# + +########################## +# Standard OS signatures # +########################## + +# ---------------- Linux ------------------- + +32736:64:0:44:M*:A:Linux:2.0 +S22:64:1:60:M*,S,T,N,W0:AT:Linux:2.2 +S22:64:1:52:M*,N,N,S,N,W0:A:Linux:2.2 w/o timestamps + +5792:64:1:60:M*,S,T,N,W0:AT:Linux:older 2.4 +5792:64:1:60:M*,S,T,N,W0:ZAT:Linux:recent 2.4 (1) +S4:64:1:44:M*:ZA:Linux:recent 2.4 (2) +5792:64:1:44:M*:ZA:Linux:recent 2.4 (3) + +S4:64:1:52:M*,N,N,S,N,W0:ZA:Linux:2.4 w/o timestamps + +# --------------- Windows ------------------ + +65535:128:1:64:M*,N,W0,N,N,T0,N,N,S:A:Windows:2000 SP4 +S44:128:1:64:M*,N,W0,N,N,T0,N,N,S:A:Windows:XP SP1 +S12:128:1:64:M*,N,W0,N,N,T0,N,N,S:A:Windows:2000 (SP1+) +S6:128:1:44:M*:A:Windows:NT 4.0 SP1+ +65535:128:1:48:M*,N,N,S:A:Windows:98 (SE) +65535:128:1:44:M*:A:Windows:2000 (1) +16616:128:1:44:M*:A:Windows:2003 +16384:128:1:44:M*:A:Windows:2000 (2) +S16:128:1:44:M*:A:Windows:2000 (3) + +# ------------------- OpenBSD -------------- + +17376:64:1:64:M*,N,N,S,N,W0,N,N,T:AT:OpenBSD:3.3 + +# ------------------- NetBSD ---------------- + +16384:64:0:60:M*,N,W0,N,N,T0:AT:NetBSD:1.6 + +# ----------------- HP/UX ------------------ + +32768:64:1:44:M*:A:HPUX:10.20 + +# ----------------- Tru64 ------------------ + +S23:60:0:48:M*,N,W0:A:Tru64:5.0 (1) +65535:64:0:44:M*:A:Tru64:5.0 (2) + +# ----------------- Novell ----------------- + +6144:128:1:52:M*,W0,N,S,N,N:A:Novell:Netware 6.0 (SP3) +32768:128:1:44:M*:A:Novell:Netware 5.1 + +# ------------------ IRIX ------------------ + +60816:60:1:60:M*,N,W0,N,N,T:AT:IRIX:6.5.0 + +# ----------------- Solaris ---------------- + +49232:64:1:64:N,N,T,M*,N,W0,N,N,S:AT:Solaris:9 (1) +S1:255:1:60:N,N,T,N,W0,M*:AT:Solaris:7 +24656:64:1:44:M*:A:Solaris:8 +33304:64:1:60:N,N,T,M*,N,W1:AT:Solaris:9 (2) + +# ----------------- FreeBSD ---------------- + +65535:64:1:60:M*,N,W1,N,N,T:AT:FreeBSD:5.0 +57344:64:1:44:M*:A:FreeBSD:4.6-4.8 +65535:64:1:44:M*:A:FreeBSD:4.4 + +57344:64:1:48:M1460,N,W0:A:FreeBSD:4.6-4.8 (wscale) +57344:64:1:60:M1460,N,W0,N,N,T:AT:FreeBSD:4.6-4.8 (RFC1323) + +# ------------------- AIX ------------------ + +S17:255:1:44:M536:A:AIX:4.2 + +S12:64:0:44:M1460:A:AIX:5.2 ML04 (1) +S42:64:0:44:M1460:A:AIX:5.2 ML04 (2) + +# ------------------ BSD/OS ---------------- + +S6:64:1:60:M1460,N,W0,N,N,T:AT:BSD/OS:4.0.x + +# ------------------ OS/390 ---------------- + +2048:64:0:44:M1460:A:OS/390:? + +# ------------------ Novell ---------------- + +6144:128:1:44:M1400:A:Novell:iChain 2.2 + +# ------------------ MacOS ----------------- + +33304:64:1:60:M*,N,W0,N,N,T:AT:MacOS:X 10.2.6 + +################################################################# +# Contributed by Ryan Kruse - trial run # +################################################################# + +# S4:255:0:44:M1024:A:Cisco:LocalDirector +# 1024:255:0:44:M536:A:Cisco,3COM,Nortel:CatIOS,SuperStack,BayStack +# S16:64:0:44:M512:A:Nortel:Contivity +# 8192:64:0:44:M1460:A:Cisco,Nortel,SonicWall,Tasman:Aironet,BayStack Switch,Soho,1200 +# 4096:255:0:44:M1460:A:Cisco:PIX,CatOS +# 8192:128:0:44:M1460:A:Cisco:VPN Concentrator +# 8192:128:0:60:M1460,N,W0,N,N,T:AT:Cisco:VPN Concentrator +# 4096:32:0:44:M1460:A:Cisco,3COM,Extreme,Nortel:Catalyst Switch CatOS,CoreBuilder,Summit,Passport +# S4:255:0:44:M536:ZA:Cisco:IOS +# 1024:32:0:44:M1480:UA:Nortel:BayStack Switch +# 4096:60:0:44:M1460:A:Adtran:NetVanta +# 4096:64:0:44:M1008:A:Adtran:TSU +# S4:32:0:44:M1024:A:Alcatel:Switch +# S8:255:0:44:M536:ZA:Cisco:IOS +# 50:255:0:44:M536:ZA:Cisco:CatIOS +# 512:64:0:40:.:A:Dell:Switch +# 4096:64:0:40:.:A:Enterasys:Vertical Horizon Switch +# 17640:64:1:44:M1460:A:F5,Juniper,RiverStone:BigIP,Juniper OS,Router 7.0+ +# 16384:64:0:44:M1460:A:Foundry,SonicWall:BigIron,TZ +# 4096:64:0:44:M1452:A:HP:ProCurve Switch +# 1024:64:0:44:M1260:A:Marconi:ES +# 10240:30:0:44:M1460:A:Milan:Switch +# 4096:64:0:44:M1380:A:NetScreen:Firewall +# S32:64:0:44:M512:A:Nokia:CheckPoint +# 1024:64:0:44:M536:A:Nortel:BayStack Switch +# 4128:255:0:44:M*:ZA:Cisco:IOS +# 1024:16:0:44:M536:A:Nortel:BayStack Switch +# 1024:30:0:44:M1480:A:Nortel:BayStack Switch +# S4:64:0:44:M1460:A:Symbol:Spectrum Access Point +# S2:255:0:44:M512:A:ZyXEL:Prestige +# S16:255:0:44:M1024:A:ZyXEL:ZyAI + +########################################### +# Appliance / embedded / other signatures # +########################################### + +16384:64:1:44:M1460:A:F5:BigIP LB 4.1.x (sometimes FreeBSD) +4128:255:0:44:M*:ZA:Cisco:Catalyst 2900 12.0(5) +4096:60:0:44:M*:A:Brother:HL-1270N +S1:30:0:44:M1730:A:Cyclades:PR3000 +8192:64:1:44:M1460:A:NetApp:Data OnTap 6.x +5792:64:1:60:W0,N,N,N,T,M1460:ZAT:FortiNet:FortiGate 50 +S1:64:1:44:M1460:A:NetCache:5.3.1 +S1:64:0:44:M512:A:Printer:controller (?) +4096:128:0:40:.:A:Sequent:DYNIX 4.2.x +S16:64:0:44:M512:A:3Com:NBX PBX (BSD/OS 2.1) +16000:64:0:44:M1442:A:CastleNet:DSL router +S2:64:0:44:M32728:A:D-Link:DSL-500 +S4:60:0:44:M1460:A:HP:JetDirect A.05.32 +8576:64:1:44:M*:A:Raptor:firewall +S12:64:1:44:M1400:A:Cequrux Firewall:4.x +2048:255:0:44:M1400:A:Netgear:MR814 +16384:128:0:64:M1460,N,W0,N,N,T0,N,N,S:A:Akamai:??? (1) +16384:128:0:60:M1460,N,W0,N,N,T0:A:Akamai:??? (2) + +8190:255:0:44:M1452:A:Citrix:Netscaler 6.1 + +# Whatever they run. EOL boys... +S6:128:1:48:M1460,E:PA:@Slashdot:or BusinessWeek (???) + + diff -NraupbwB soc07-5184/scripts/p0f.nse soc07-nse-pcap/scripts/p0f.nse --- soc07-5184/scripts/p0f.nse 1970-01-01 01:00:00.000000000 +0100 +++ soc07-nse-pcap/scripts/p0f.nse 2007-07-11 23:06:49.000000000 +0200 @@ -0,0 +1,614 @@ +id = "p0f signature" +description = "Guesses target os per each opened port, instead of standard per host tests." +author = "Marek Majkowski " +license = "See nmaps COPYING for licence" + +require "bit" + +--[[ + it's just an implementation of lcamtuf's p0f SYN+ACK scan +]]-- + +categories = {"safe"} -- intrusive? + +---------------------------------------------------------------------------------------------------------------- +Tcp = {} + +function Tcp:new(packet, packet_len) + local o = setmetatable({}, {__index = Tcp}) + o.buf = packet + o.packet_len = packet_len + if not o:parse_ip() then + return nil + end + if not o:parse_tcp() then + return nil + end + return o +end +function u8(b, i) + return string.byte(b, i+1) +end +function u16(b, i) + local b1,b2 + b1, b2 = string.byte(b, i+1), string.byte(b, i+2) + -- 2^8 2^0 + return b1*256 + b2 +end +function u32(b,i) + local b1,b2,b3,b4 + b1, b2 = string.byte(b, i+1), string.byte(b, i+2) + b3, b4 = string.byte(b, i+3), string.byte(b, i+4) + -- 2^24 2^16 2^8 2^0 + return b1*16777216 + b2*65536 + b3*256 + b4 +end + +function Tcp:u8(index) + return u8(self.buf, index) +end +function Tcp:u16(index) + return u16(self.buf, index) +end +function Tcp:u32(index) + return u32(self.buf, index) +end +function Tcp:raw(index, length) + return string.char(string.byte(self.buf, index+1, index+1+length-1)) + +end +function Tcp:parse_options(offset, length) -- parse ip/tcp options to dict structure + local options = {} + local op = 1 + local opt_ptr = 0 + while opt_ptr < length do + local t, l, d + options[op] = {} + + t = self:u8(offset + opt_ptr) + options[op].type = t + if t==0 or t==1 then + l = 1 + d = nil + else + l = self:u8(offset + opt_ptr + 1) + if l > 2 then + d = self:raw(offset + opt_ptr + 2, l-2) + end + end + options[op].len = l + options[op