diff -Nraupbw nmap-diman-4516/liblua/Makefile nmap-diman-nse-pcap/liblua/Makefile --- nmap-diman-4516/liblua/Makefile 2007-02-26 15:45:07.000000000 +0100 +++ nmap-diman-nse-pcap/liblua/Makefile 2007-02-26 16:05:09.816063250 +0100 @@ -8,11 +8,11 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -g -O2 -Wall $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS= -lm $(MYLIBS) +LIBS= -lm -g $(MYLIBS) MYCFLAGS= MYLDFLAGS= diff -Nraupbw nmap-diman-4516/nse_init.cc nmap-diman-nse-pcap/nse_init.cc --- nmap-diman-4516/nse_init.cc 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/nse_init.cc 2007-02-26 16:05:09.820063500 +0100 @@ -9,6 +9,8 @@ #include "nse_bitlib.h" #include "nse_pcrelib.h" +#include "nse_nsock.h" + #include "nmap.h" #include "nmap_error.h" #include "NmapOps.h" @@ -48,6 +50,7 @@ int init_lua(lua_State* l) { {LUA_DBLIBNAME, luaopen_debug}, {NSE_BITLIBNAME, luaopen_bitlib}, {NSE_PCRELIBNAME, luaopen_pcrelib}, + {NSE_DNETLIBNAME, luaopen_dnet}, {NULL, NULL} }; diff -Nraupbw nmap-diman-4516/nse_nmaplib.cc nmap-diman-nse-pcap/nse_nmaplib.cc --- nmap-diman-4516/nse_nmaplib.cc 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/nse_nmaplib.cc 2007-02-26 16:05:09.820063500 +0100 @@ -35,6 +35,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 * */ @@ -44,6 +46,8 @@ 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}, + {"clock_ms", l_clock_ms}, {"print_debug_unformatted", l_print_debug_unformatted}, {"new_try", l_exc_newtry}, {NULL, NULL} @@ -59,6 +63,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; } @@ -179,6 +184,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 -Nraupbw nmap-diman-4516/nse_nsock.cc nmap-diman-nse-pcap/nse_nsock.cc --- nmap-diman-4516/nse_nsock.cc 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/nse_nsock.cc 2007-02-26 16:09:55.237901000 +0100 @@ -43,6 +43,10 @@ static int l_nsock_get_info(lua_State* l static int l_nsock_close(lua_State* l); static int l_nsock_set_timeout(lua_State* l); +static int l_nsock_pcap_open(lua_State* l); +static int l_nsock_pcap_close(lua_State* l); +static int l_nsock_pcap_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); @@ -62,15 +66,40 @@ static luaL_reg l_nsock [] = { {"get_info", l_nsock_get_info}, {"close", l_nsock_close}, {"set_timeout", l_nsock_set_timeout}, + {"pcap_open", l_nsock_pcap_open}, + {"pcap_close", l_nsock_pcap_close}, + {"pcap_receive", l_nsock_pcap_receive}, {NULL, NULL} }; static nsock_pool nsp; +/* + * Structure with nsock pcap descriptor. + */ +typedef struct{ + nsock_iod nsiod; /* nsock pcap desc */ + int references; /* how many lua threads use this */ + int test_off; /* Test offset in packet (offset from layer2) */ + size_t test_len; /* How many bytes are to be checked */ + char *key; /* Key used in map to address this structure. */ + /* The key is string that's created for all the + * nsock_pcap_open parameters. I mean : + * device|test_off|test_len|berkeley filter. + * So I suppose that there'll be one opened descriptor per + * lua script (and no matter how many times this script will + * be runned). */ +} pcap_nsiod_cache; + +/* The map. Handles key to sturcture pcap_nsiod_cache relation. */ +std::map pcap_nsiod_map; + + struct l_nsock_udata { int timeout; nsock_iod nsiod; void *ssl_session; + pcap_nsiod_cache *pnc; /* Pointer to pcap_nsiod_cache, if nsiod is nsock_pcap descriptor */ }; int l_nsock_open(lua_State* l) { @@ -89,6 +118,7 @@ int l_nsock_new(lua_State* l) { udata->nsiod = NULL; udata->ssl_session = NULL; udata->timeout = DEFAULT_TIMEOUT; + udata->pnc = NULL; return 1; } @@ -302,9 +332,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), @@ -316,6 +346,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) { @@ -425,5 +460,503 @@ static int l_nsock_set_timeout(lua_State return 0; } +/***************************************/ +#ifdef WIN32 +/* From tcpip.cc. Gets pcap device name from dnet name. */ +bool DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen); +#endif + +static int l_nsock_pcap_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); + int test_off = luaL_checkint(l, 5); + int test_len = luaL_checkint(l, 6); + const char* bpf = luaL_checkstring(l, 7); + char pcapdev[128]; + + + #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 + + pcap_nsiod_cache *pnc; + /* create cache key */ + char kbuf[8192]; // key buffer + snprintf(kbuf, sizeof(kbuf), "%s|%i|%i|%s|%u|%i|%i",pcapdev,snaplen,promisc,bpf,strlen(bpf),test_off,test_len); + std::string key = kbuf; + + pnc = pcap_nsiod_map[key]; + if(pnc == NULL){ + pnc = (pcap_nsiod_cache*)safe_zalloc(sizeof(pcap_nsiod_cache)); + pnc->nsiod = nsi_new(nsp, pnc); + pnc->test_off = test_off; + pnc->test_len = test_len; + pnc->key = strdup(kbuf); + nsock_pcap_open(nsp, pnc->nsiod, pcapdev, snaplen, promisc, bpf); + pcap_nsiod_map[key] = pnc; + } + pnc->references++; + udata->nsiod = pnc->nsiod; + udata->pnc = pnc; + + if(o.scripttrace && o.debugging>2) { + l_nsock_trace(udata->nsiod, "PCAP OPEN", TO); + } + + return 0; +} + +static int l_nsock_pcap_close(lua_State* l){ + l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1); + + if(o.scripttrace && o.debugging>2) { + l_nsock_trace(udata->nsiod, "PCAP CLOSE", TO); + } + + pcap_nsiod_cache *pnc = udata->pnc; + + assert(pnc); + pnc->references--; + if(pnc->references==0){ + std::string key = pnc->key; + pcap_nsiod_map.erase(key); + if(pnc->key) + free(pnc->key); + nsi_delete(pnc->nsiod, NSOCK_PENDING_NOTIFY); + free(pnc); + } + + udata->nsiod = NULL; + udata->pnc = NULL; + lua_pushboolean(l, true); + return 1; +} + +void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state); + +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 pcap_request_map; +typedef std::multimap::iterator pcap_request_map_iterator; + +void pcap_request_delete(pcap_request *pr){ + pcap_request_map_iterator i; + std::pair ii; + std::string s = pr->key; + ii = pcap_request_map.equal_range(s); + + for(i=ii.first ; i!=ii.second ;i++){ + if(i->second == pr){ + if(pr->testdata) + free(pr->testdata); + if(pr->key) + free(pr->key); + free(pr); + i->second = NULL; + pcap_request_map.erase(i); + return; + } + } + assert(0); +} + +void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse, void *pcap_req_iter); +void l_nsock_pcap_receive_handler_restore_lua(nsock_pool nsp, nsock_event nse, void *lua_state); + +int l_nsock_pcap_receive(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); + if(udata->nsiod == NULL) { + lua_pushboolean(l, false); + lua_pushstring(l, "Trying to receive bytes through a closed socket\n"); + return 2; + } + + struct timeval now = *nsock_gettimeofday(); + pcap_request *pr = (pcap_request*)safe_zalloc(sizeof(pcap_request)); + + TIMEVAL_MSEC_ADD(pr->end_time, now, udata->timeout); + pr->testdata = (char*) safe_malloc(testdatasz); + memcpy(pr->testdata, testdata, testdatasz); + pr->testdatasz = MIN(udata->pnc->test_len, testdatasz); + pr->l = l; + + + /* add to multimap */ + char *k = hex(pr->testdata, pr->testdatasz); + std::string s = k; + pcap_request_map.insert(std::pair(s, pr)); + pr->key = strdup(k); + + /* always we create new event. */ + pr->nse = nsock_pcap_read_packet(nsp, udata->nsiod, l_nsock_pcap_receive_handler, udata->timeout, pr); + + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf), "PCAP Thread %x is waiting for data (NSE=%lu)", + (unsigned int)l, pr->nse); + l_nsock_trace(udata->nsiod, buf, TO); + } + + return lua_yield(l, 0); +} + + + +void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse, void *pcap_req) { + pcap_request *pr = (pcap_request*) pcap_req; + + int this_event_restored = 0; + std::pair ii; + pcap_request_map_iterator i; + pcap_request_map_iterator in; + const unsigned char *l2_data; + size_t l2_len, l3_len; + + assert(pr); + + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf),"PCAP Got event %s for thread %x (NSE=%lu)", + nse_status2str(nse_status(nse)), (unsigned int)pr->l, nse_id(nse) ); + l_nsock_trace(nse_iod(nse),buf , TO); + } + + pcap_nsiod_cache *pnc = (pcap_nsiod_cache*)nsi_getud(nse_iod(nse)); + + switch(nse_status(nse)) { + case NSE_STATUS_SUCCESS:{ + /* processes that receive everything */ + std::string s = ""; + ii = pcap_request_map.equal_range(s); + + for(i = ii.first; i != ii.second; i=in) { + /* tests are successfull, so just restore process */ + pcap_request *pi = i->second; + in = i; in++; + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf),"PCAP Thread %x restored (it receives all packets) (NSE=%lu) (event owner=%i)", + (unsigned int)pi->l, nse_id(nse), pr==pi ); + l_nsock_trace(nse_iod(nse),buf , TO); + } + l_nsock_pcap_receive_handler_restore_lua(nsp, nse, pi->l); + + /* is current event connected to current lua process? */ + if(pr == pi){ + this_event_restored = 1; + } else { + /* else: delete events for processes that were restored */ + nsock_event_cancel(nsp, pi->nse, 0); /* Don't send CANCELED event, just cancel */ + } + if(pi->testdata)free(pi->testdata); + if(pi->key)free(pi->key); + free(pi); + } + pcap_request_map.erase(ii.first, ii.second); + + /* process everything that matches test */ + nse_readpcap(nse, &l2_data, &l2_len, NULL, &l3_len, NULL, NULL); + if( pnc->test_len>0 && + ((l2_len + l3_len) >= (pnc->test_off + pnc->test_len))){ + char *a = hex((char*)&l2_data[pnc->test_off], pnc->test_len); + s = a; + ii = pcap_request_map.equal_range(s); + for(i = ii.first; i != ii.second; i=in) { + /* tests are successfull, so just restore process */ + pcap_request *pi = i->second; + in = i; in++; + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf),"PCAP Thread %x restored (test successful) (NSE=%lu) (event owner=%i) (canceled NSE=%lu)", + (unsigned int)pi->l, nse_id(nse), pr==pi, pi->nse); + l_nsock_trace(nse_iod(nse),buf , TO); + } + l_nsock_pcap_receive_handler_restore_lua(nsp, nse, pi->l); + + /* is current event connected to current lua process? */ + if(pr == pi){ + this_event_restored = 1; + } else { + /* else: delete events for processes that were restored */ + nsock_event_cancel(nsp, pi->nse, 0); /* Don't send CANCELED event, just cancel */ + } + if(pi->testdata)free(pi->testdata); + if(pi->key)free(pi->key); + free(pi); + } + pcap_request_map.erase(ii.first, ii.second); + } + + 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(pr->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; + pr->nse = nsock_pcap_read_packet(nsp, nse_iod(nse), l_nsock_pcap_receive_handler, timeout, pr); + /* no need to cancel or delete current nse :) */ + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf),"PCAP Event owner didn't handled event. We're creating new one. Thread %x (NSE=%lu), (new NSE=%lu)", + (unsigned int)pr->l, nse_id(nse), pr->nse); + l_nsock_trace(nse_iod(nse),buf , TO); + } + } + return; + } + default: + if(o.scripttrace && o.debugging>2) { + char buf[128]; + snprintf(buf, sizeof(buf),"PCAP Event is not success. just pass it to handler. Thread %x (NSE=%lu)", + (unsigned int)pr->l, nse_id(nse)); + l_nsock_trace(nse_iod(nse),buf , TO); + } + l_nsock_pcap_receive_handler_restore_lua(nsp, nse, pr->l); + pcap_request_delete(pr); + return; + } + + +} + +void l_nsock_pcap_receive_handler_restore_lua(nsock_pool nsp, nsock_event nse, void *lua_state) { + lua_State* l = (lua_State*) lua_state; + char* hexified; + const unsigned char *l2_data, *l3_data; + size_t l2_len, l3_len, packet_len; + if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) { + nse_readpcap(nse, &l2_data, &l2_len, &l3_data, &l3_len, &packet_len, NULL); + if(o.scripttrace) { + } + if(o.scripttrace) { + char buf[128]; + snprintf(buf, sizeof(buf),"packet l2len=%u l3len=%u packet_len=%u",l2_len, l3_len, packet_len); + l_nsock_trace(nse_iod(nse), buf, TO); + hexified = nse_hexify((const void*) l2_data, (size_t) l2_len+l3_len); + l_nsock_trace(nse_iod(nse), hexified, FROM); + free(hexified); + } + + lua_pushnumber(l, packet_len); + lua_pushlstring(l, (char*)l2_data, l2_len); + lua_pushlstring(l, (char*)l3_data, l3_len); + process_waiting2running((lua_State*) lua_state, 4); + } else { + lua_pushnil(l); + lua_pushnil(l); + process_waiting2running((lua_State*) lua_state, 4); + } +} + + + +static int l_dnet_get_interface_link(lua_State* l); +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 [] = { + {"get_interface_link", l_dnet_get_interface_link}, + {"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; +} + +LUALIB_API int luaopen_dnet (lua_State *L) { + + + luaL_openlib(L, NSE_DNETLIBNAME, l_dnet, 0); + return 1; +} + + +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; +} + +static int l_dnet_get_interface_link(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){ + 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; +} + + + #endif /* NOLUA */ diff -Nraupbw nmap-diman-4516/nse_nsock.h nmap-diman-nse-pcap/nse_nsock.h --- nmap-diman-4516/nse_nsock.h 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/nse_nsock.h 2007-02-26 16:05:09.820063500 +0100 @@ -11,5 +11,13 @@ int l_nsock_open(lua_State* l); int l_nsock_new(lua_State* l); int l_nsock_loop(int tout); + +#define NSE_DNETLIBNAME "dnet" + +LUALIB_API int luaopen_dnet (lua_State *L); +int l_dnet_new(lua_State* l); + +int l_dnet_open(lua_State* l); + #endif diff -Nraupbw nmap-diman-4516/nsock/examples/Makefile nmap-diman-nse-pcap/nsock/examples/Makefile --- nmap-diman-4516/nsock/examples/Makefile 2007-02-26 15:46:09.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/examples/Makefile 2007-02-26 16:05:09.820063500 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/examples/nsock_pcap.c nmap-diman-nse-pcap/nsock/examples/nsock_pcap.c --- nmap-diman-4516/nsock/examples/nsock_pcap.c 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/examples/nsock_pcap.c 2007-02-26 16:05:09.820063500 +0100 @@ -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 #ifndef WIN32 #include @@ -179,9 +186,15 @@ void nsp_delete(nsock_pool nsp); /* IF YOU ADD NEW NSE_TYPES YOU MUST INCREASE TYPE_CODE_NUM_BITS SO THAT IT IS ALWAYS log2(maximum_nse_type_value + 1) */ #define TYPE_CODE_NUM_BITS 3 -enum nse_type { NSE_TYPE_CONNECT=0, NSE_TYPE_CONNECT_SSL=1, NSE_TYPE_READ=2, NSE_TYPE_WRITE=3, - NSE_TYPE_TIMER=4 }; /* At some point I was considering a - NSE_TYPE_START and NSE_TYPE_CUSTOM */ +enum nse_type { + NSE_TYPE_CONNECT=0, + NSE_TYPE_CONNECT_SSL=1, + NSE_TYPE_READ=2, + NSE_TYPE_WRITE=3, + NSE_TYPE_TIMER=4, + NSE_TYPE_PCAP_READ=5, + NSE_TYPE_MAX=6, +}; /* At some point I was considering a NSE_TYPE_START and NSE_TYPE_CUSTOM */ /* Find the type of an event that spawned a callback */ enum nse_type nse_type(nsock_event nse); @@ -462,6 +475,54 @@ int nsock_event_cancel(nsock_pool ms_poo before returning */ const struct timeval *nsock_gettimeofday(); + +#ifdef HAVE_PCAP +/* + * Open pcap device and connect it to nsp. 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 handler + * promisc : whether to open device in promiscous mode + * bpf_fmt : berkeley filter + * No return value. The filter will be okay, or program will abort + * with error. + * */ +void nsock_pcap_open(nsock_pool nsp, nsock_iod nsiod, + const char *pcap_device, int snaplen, int promisc, + const char *bpf_fmt, ...); + +/* + * Requests exacly one packet to be captured.from pcap. + * See nsock_read() for parameters description. + * */ +nsock_event_id nsock_pcap_read_packet(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, int timeout_msecs, + void *userdata); + +/* + * Gets packet data. This should be called after succesfull receiving of packet + * to get packet. If you're not interested in some values, just pass NULL + * instead of valid pointer. + * l3_data is just after l2_data in buffer. Feel free to treat l2_data as one + * buffer with size of (l2_len + l3_len). + * Ts time is fixed for systems that don't support proper timing, like Windows. + * So TS is pointing to time when packet was received or to the time _after_. + * As a result you'll get longer times than you should, but it's safer to + * think that host is a bit further. + * */ +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); + +/* Well. Just pcap-style datalink. Like DLT_EN10MB or DLT_SLIP. Check in pcap(3) manpage. */ +int nsi_pcap_linktype(nsock_iod nsiod); + +/* Is this nsiod a pcap descriptor? */ +int nsi_is_pcap(nsock_iod nsiod); + +#endif /* HAVE_PCAP */ + #ifdef __cplusplus } /* End of 'extern "C"' */ #endif diff -Nraupbw nmap-diman-4516/nsock/nsock.vcproj nmap-diman-nse-pcap/nsock/nsock.vcproj --- nmap-diman-4516/nsock/nsock.vcproj 2007-02-26 15:46:09.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/nsock.vcproj 2007-02-26 16:10:48.301217250 +0100 @@ -41,7 +41,7 @@ + + @@ -239,6 +243,10 @@ > + + diff -Nraupbw nmap-diman-4516/nsock/src/configure.ac nmap-diman-nse-pcap/nsock/src/configure.ac --- nmap-diman-4516/nsock/src/configure.ac 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/configure.ac 2007-02-26 16:05:09.820063500 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/error.c nmap-diman-nse-pcap/nsock/src/error.c --- nmap-diman-4516/nsock/src/error.c 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/error.c 2007-02-26 16:05:09.820063500 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/Makefile.in nmap-diman-nse-pcap/nsock/src/Makefile.in --- nmap-diman-4516/nsock/src/Makefile.in 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/Makefile.in 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_config.h.in nmap-diman-nse-pcap/nsock/src/nsock_config.h.in --- nmap-diman-4516/nsock/src/nsock_config.h.in 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_config.h.in 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_core.c nmap-diman-nse-pcap/nsock/src/nsock_core.c --- nmap-diman-4516/nsock/src/nsock_core.c 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_core.c 2007-02-26 16:05:09.824063750 +0100 @@ -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,14 +772,27 @@ 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) { - 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 -Nraupbw nmap-diman-4516/nsock/src/nsock_event.c nmap-diman-nse-pcap/nsock/src/nsock_event.c --- nmap-diman-4516/nsock/src/nsock_event.c 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_event.c 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_internal.h nmap-diman-nse-pcap/nsock/src/nsock_internal.h --- nmap-diman-4516/nsock/src/nsock_internal.h 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_internal.h 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_iod.c nmap-diman-nse-pcap/nsock/src/nsock_iod.c --- nmap-diman-4516/nsock/src/nsock_iod.c 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_iod.c 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_pcap.c nmap-diman-nse-pcap/nsock/src/nsock_pcap.c --- nmap-diman-4516/nsock/src/nsock_pcap.c 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_pcap.c 2007-02-26 16:05:09.824063750 +0100 @@ -0,0 +1,352 @@ +#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); +static void 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 + * */ + +void 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; + + assert(mp==NULL); + 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)) + fatal("nsock_pcap_open called with too-large bpf filter arg\n"); + 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) + fatal( + "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); + + 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); + + nsock_pcap_set_filter(mp->pt, pcap_device, bpf); + + + #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) + fatal("Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); + + /* When we use bsd hack we also need to set non-blocking */ + #ifdef PCAP_BSD_SELECT_HACK + fatal("Failed to set pcap descriptor on device %s to nonblocking state: %s", pcap_device, err0r); + #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; +} + +static void 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]; + + // 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) + fatal("Failed to lookup subnet/netmask for device (%s): %s", device, err0r); + + // log_write(LOG_STDOUT, "Packet capture filter (device %s): %s\n", device, buf); + + if (pcap_compile(pt, &fcode, (char*)bpf, 1, netmask) < 0) + fatal("Error compiling our pcap filter: %s\n", pcap_geterr(pt)); + + if (pcap_setfilter(pt, &fcode) < 0 ) + fatal("Failed to set the pcap filter: %s\n", pcap_geterr(pt)); + + pcap_freecode(&fcode); +} + +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 -Nraupbw nmap-diman-4516/nsock/src/nsock_pcap.h nmap-diman-nse-pcap/nsock/src/nsock_pcap.h --- nmap-diman-4516/nsock/src/nsock_pcap.h 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_pcap.h 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/nsock/src/nsock_pool.c nmap-diman-nse-pcap/nsock/src/nsock_pool.c --- nmap-diman-4516/nsock/src/nsock_pool.c 2007-02-26 15:46:08.000000000 +0100 +++ nmap-diman-nse-pcap/nsock/src/nsock_pool.c 2007-02-26 16:05:09.824063750 +0100 @@ -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 -Nraupbw nmap-diman-4516/scripts/p0fa.fp nmap-diman-nse-pcap/scripts/p0fa.fp --- nmap-diman-4516/scripts/p0fa.fp 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/scripts/p0fa.fp 2007-02-26 16:05:09.828064000 +0100 @@ -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 -Nraupbw nmap-diman-4516/scripts/p0f.nse nmap-diman-nse-pcap/scripts/p0f.nse --- nmap-diman-4516/scripts/p0f.nse 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/scripts/p0f.nse 2007-02-26 16:15:57.612548000 +0100 @@ -0,0 +1,606 @@ +id = "p0f signature" +description = "Guesses target os for every opened port" +author = "Marek Majkowski " +license = "See nmaps COPYING for licence" + +--[[ + it's just an implementation of 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)) + +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].data = d + opt_ptr = opt_ptr + l + op = op + 1 + end + return options +end +function Tcp:toip(raw_ip_addr) + return string.format("%i.%i.%i.%i", string.byte(raw_ip_addr,1,4)) +end + +function Tcp:parse_ip() + self.ip_offset = 0 + if string.len(self.buf) < 20 then -- too short + return false + end + self.ip_v = bit.rshift(bit.band(self:u8(self.ip_offset + 0), 0xF0), 4) + self.ip_hl = bit.band(self:u8(self.ip_offset + 0), 0x0F) -- header_length or data_offset + if self.ip_v ~= 4 then -- not ip + return false + end + self.ip_tos = self:u8(self.ip_offset + 1) + self.ip_len = self:u16(self.ip_offset + 2) + self.ip_id = self:u16(self.ip_offset + 4) + self.ip_off = self:u16(self.ip_offset + 6) + self.ip_rf = bit.band(self.ip_off, 0x8000)~=0 -- true/false + self.ip_df = bit.band(self.ip_off, 0x4000)~=0 + self.ip_mf = bit.band(self.ip_off, 0x2000)~=0 + self.ip_off = bit.band(self.ip_off, 0x1FFF) -- fragment offset + self.ip_ttl = self:u8(self.ip_offset + 8) + self.ip_p = self:u8(self.ip_offset + 9) + self.ip_sum = self:u16(self.ip_offset + 10) + self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string + self.ip_bin_dst = self:raw(self.ip_offset + 16,4) + self.ip_src = self:toip(self.ip_bin_src) -- formatted string + self.ip_dst = self:toip(self.ip_bin_dst) + self.ip_opt_offset = self.ip_offset + 20 + self.ip_options = self:parse_options(self.ip_opt_offset, ((self.ip_hl*4)-20)) + self.ip_data_offset = self.ip_offset + self.ip_hl*4 + return true +end +function Tcp:tostring() + return string.format( + "%s:%i -> %s:%i", + self.ip_src, self.tcp_sport, + self.ip_dst, self.tcp_dport + ) +end +function Tcp:to_p0f() + return string.format( + "%s:%i:%i:%i:%s:%s:?:?|link: %s, %s%s%s", + self:to_p0f_window_size(), + self.ip_ttl, + (self.ip_df and "1" or "0"), + self:to_p0f_packet_size(), + self:to_p0f_tcp_options(), + self:to_p0f_quirks(), + self:lookup_link(), + self:to_p0f_uptime(), + self:to_fill(), + self:to_ipid() + ) +end +function tohex(str) + local b = "" + for c in string.gmatch(str, ".") do + b = string.format('%s%02x',b, string.byte(c)) + end + return b +end +function Tcp:to_fill() -- ethernet fill, if packet is smaller than 46 bytes + local l = self.tcp_data_offset + self.tcp_data_length + local s = self.packet_len + if l < s then + return string.format(", fill:%s", tohex( string.sub(self.buf, l+1) )) + end + return "" +end +function Tcp:to_ipid() -- ipid number + if self.ip_id > 0 then + return string.format(", ipid:%i", self.ip_id) + end + return "" +end + +function Tcp:to_p0f_uptime() + if self.tcp_opt_t1 == nil then + return "up: disabled" + end + return string.format("up: %i hrs", self.tcp_opt_t1/360000) +end +function Tcp:to_p0f_window_size() + local win = self.tcp_win + if self.tcp_opt_mss ~= nil and + win % self.tcp_opt_mss == 0 then + return string.format("S%i", win/self.tcp_opt_mss) -- not floating -> no reminder + end + if self.tcp_opt_mtu ~= nil and + win % self.tcp_opt_mtu == 0 then + return string.format("T%i", win/self.tcp_opt_mtu) -- not floating -> no reminder + end + return string.format("%i", win) +end +function Tcp:to_p0f_packet_size() + if self.ip_len < 100 then + return string.format("%i", self.ip_len) + end + -- bigger than 99 + return "*" +end +function Tcp:to_p0f_tcp_options() + local opt_chr = { + [0] = "E", + [1] = "N", + [2] = "M", + [3] = "W", + [4] = "S", + [8] = "T" + } + local str = "" + for k,opt in ipairs(self.tcp_options) do + if opt_chr[opt.type] ~= nil then + str = str .. opt_chr[opt.type] + else + str = str .. string.format("?%i", opt.type) + end + + if opt.type == 2 then + str = str .. string.format("%i", u16(opt.data, 0)) + elseif opt.type == 3 then + str = str .. string.format("%i", u8(opt.data, 0)) + elseif opt.type == 8 then + local t = u32(opt.data, 0) + if t == 0 then + str = str .. "0" + end + end + str = str .. "," + end + if string.len(str) == 0 then + return "." + end + return string.sub(str, 0, string.len(str)-1) +end +function Tcp:tcp_parse_options() + local eoo = false + for _,opt in ipairs(self.tcp_options) do + if eoo then + self.tcp_opt_after_eol = true + end + + if opt.type == 0 then -- end of options + eoo = true + elseif opt.type == 2 then -- MSS + self.tcp_opt_mss = u16(opt.data, 0) + self.tcp_opt_mtu = self.tcp_opt_mss + 40 + elseif opt.type == 3 then -- widow scaling + self.tcp_opt_ws = u8(opt.data, 0) + elseif opt.type == 8 then -- timestamp + self.tcp_opt_t1 = u32(opt.data, 0) + self.tcp_opt_t2 = u32(opt.data, 4) + end + end +end +function Tcp:to_p0f_quirks() + local str = "" + + -- P + if self.tcp_opt_after_eol then + str = str .. "P" + end + + -- Z + if self.ip_id == 0 then + str = str .. "Z" + end + + -- I + if self.ip_options[1] ~= nil then + str = str .. "I" + end + + -- U + if self.tcp_urp ~= 0 then + str = str .. "U" + end + + -- X + if self.tcp_x2 ~= 0 then + str = str .. "X" + end + + -- A + if self.tcp_ack ~= 0 then + str = str .. "A" + end + + -- T + if self.tcp_opt_t2 ~= nil and self.tcp_opt_t2 > 0 then +--[[ io.write(string.format("%s:%i->%i t1=%i t2=%i\n", + self.ip_src, + self.tcp_sport, + self.tcp_dport, + self.tcp_opt_t1, + self.tcp_opt_t2)) +]]-- + str = str .. "T" + end + + -- D + if self.tcp_data_length > 0 then + str = str .. "D" + end + + -- F + if self.tcp_th_urg or self.tcp_th_fin then -- no push? + str = str .. "F" + end + + -- not implemented option -> "!" + + if string.len(str) == 0 then + return "." + end + return str +end + +function Tcp:parse_tcp() + self.tcp_offset = self.ip_data_offset + if string.len(self.buf) < self.tcp_offset + 20 then + return false + end + self.tcp_sport = self:u16(self.tcp_offset + 0) + self.tcp_dport = self:u16(self.tcp_offset + 2) + self.tcp_seq = self:u32(self.tcp_offset + 4) + self.tcp_ack = self:u32(self.tcp_offset + 8) + self.tcp_hl = bit.rshift(bit.band(self:u8(self.tcp_offset+12), 0xF0), 4) -- header_length or data_offset + self.tcp_x2 = bit.band(self:u8(self.tcp_offset+12), 0x0F) + self.tcp_flags = self:u8(self.tcp_offset + 13) + self.tcp_th_fin = bit.band(self.tcp_flags, 0x01)~=0 -- true/false + self.tcp_th_syn = bit.band(self.tcp_flags, 0x02)~=0 + self.tcp_th_rst = bit.band(self.tcp_flags, 0x04)~=0 + self.tcp_th_push = bit.band(self.tcp_flags, 0x08)~=0 + self.tcp_th_ack = bit.band(self.tcp_flags, 0x10)~=0 + self.tcp_th_urg = bit.band(self.tcp_flags, 0x20)~=0 + self.tcp_th_ece = bit.band(self.tcp_flags, 0x40)~=0 + self.tcp_th_cwr = bit.band(self.tcp_flags, 0x80)~=0 + self.tcp_win = self:u16(self.tcp_offset + 14) + self.tcp_sum = self:u16(self.tcp_offset + 16) + self.tcp_urp = self:u16(self.tcp_offset + 18) + self.tcp_opt_offset = self.tcp_offset + 20 + self.tcp_options = self:parse_options(self.tcp_opt_offset, ((self.tcp_hl*4)-20)) + self.tcp_data_offset = self.tcp_offset + self.tcp_hl*4 + self.tcp_data_length = self.ip_len - self.tcp_offset - self.tcp_hl*4 + self:tcp_parse_options() + return true +end + +function Tcp:lookup_link() + local mtu_def = { + {["mtu"]=256, ["txt"]= "radio modem"}, + {["mtu"]=386, ["txt"]= "ethernut"}, + {["mtu"]=552, ["txt"]= "SLIP line / encap ppp"}, + {["mtu"]=576, ["txt"]= "sometimes modem"}, + {["mtu"]=1280, ["txt"]= "gif tunnel"}, + {["mtu"]=1300, ["txt"]= "PIX, SMC, sometimes wireless"}, + {["mtu"]=1362, ["txt"]= "sometimes DSL (1)"}, + {["mtu"]=1372, ["txt"]= "cable modem"}, + {["mtu"]=1400, ["txt"]= "(Google/AOL)"}, + {["mtu"]=1415, ["txt"]= "sometimes wireless"}, + {["mtu"]=1420, ["txt"]= "GPRS, T1, FreeS/WAN"}, + {["mtu"]=1423, ["txt"]= "sometimes cable"}, + {["mtu"]=1440, ["txt"]= "sometimes DSL (2)"}, + {["mtu"]=1442, ["txt"]= "IPIP tunnel"}, + {["mtu"]=1450, ["txt"]= "vtun"}, + {["mtu"]=1452, ["txt"]= "sometimes DSL (3)"}, + {["mtu"]=1454, ["txt"]= "sometimes DSL (4)"}, + {["mtu"]=1456, ["txt"]= "ISDN ppp"}, + {["mtu"]=1458, ["txt"]= "BT DSL (?)"}, + {["mtu"]=1462, ["txt"]= "sometimes DSL (5)"}, + {["mtu"]=1470, ["txt"]= "(Google 2)"}, + {["mtu"]=1476, ["txt"]= "IPSec/GRE"}, + {["mtu"]=1480, ["txt"]= "IPv6/IPIP"}, + {["mtu"]=1492, ["txt"]= "pppoe (DSL)"}, + {["mtu"]=1496, ["txt"]= "vLAN"}, + {["mtu"]=1500, ["txt"]= "ethernet/modem"}, + {["mtu"]=1656, ["txt"]= "Ericsson HIS"}, + {["mtu"]=2024, ["txt"]= "wireless/IrDA"}, + {["mtu"]=2048, ["txt"]= "Cyclom X.25 WAN"}, + {["mtu"]=2250, ["txt"]= "AiroNet wireless"}, + {["mtu"]=3924, ["txt"]= "loopback"}, + {["mtu"]=4056, ["txt"]= "token ring (1)"}, + {["mtu"]=4096, ["txt"]= "Sangoma X.25 WAN"}, + {["mtu"]=4352, ["txt"]= "FDDI"}, + {["mtu"]=4500, ["txt"]= "token ring (2)"}, + {["mtu"]=9180, ["txt"]= "FORE ATM"}, + {["mtu"]=16384, ["txt"]= "sometimes loopback (1)"}, + {["mtu"]=16436, ["txt"]= "sometimes loopback (2)"}, + {["mtu"]=18000, ["txt"]= "token ring x4"}, + } + if not self.tcp_opt_mss or self.tcp_opt_mss==0 then + return "unspecified" + end + for _,x in ipairs(mtu_def) do + local mtu = x["mtu"] + local txt = x["txt"] + if self.tcp_opt_mtu == mtu then + return txt + end + if self.tcp_opt_mtu < mtu then + return string.format("unknown-%i", self.tcp_opt_mtu) + end + end + return string.format("unknown-%i", self.tcp_opt_mtu) +end + +---------------------------------------------------------------------------------------------------------------- +function split(str, regexp) + local tab = {} + local i = 0 + for x in string.gfind(str, regexp) do + i = i+1 + tab[i] = x + end + return tab +end +function join(delim, arr, idx) + local i = idx + local o = "" + while arr[i] ~= nil do + if o ~= "" then + o = o .. delim + end + o = o .. arr[i] + i = i + 1 + end + return o +end +function sig_unpack(signature) + local s = {} + local tab = split(signature, "[^:]+") + s.wwww = tab[1] + s.ttt = tonumber(tab[2]) + s.D = tab[3] + s.ss = tab[4] + s.OOO = split(tab[5], "[^,]+") + s.QQ = tab[6] -- split(tab[6], ".") + s.OS = tab[7] + s.details = join(":" ,tab, 8) + s.full = signature + return s +end +function sig_getindex_OOO(t) + local s = "" + for k,v in ipairs(t) do + local t = string.find(v, "^[NEST?]") -- no W and M + if t ~= nil then + s = s .. v .. "," + end + end + return s +end +function sig_getindex(s) + return string.format("%s|%s|%s|%s", s.D, s.ss, sig_getindex_OOO(s.OOO), s.QQ ) +end + +function sigs_load(filename) + local sigs = {} + local f = io.open("scripts/" .. filename, "r") + if f == nil then + io.write("SCRIPT WARNING: P0f data file '" .. filename .. "' not found!\n") + end + while true do + local line = f:read("*line") + if line == nil then break end + if string.find(line, "^#") == nil and + string.find(line, ":") ~= nil then + -- io.write(line .. "!\n") + local sig = sig_unpack(line) + local idx = sig_getindex(sig) + if sigs[idx] == nil then + sigs[idx] = {} + end + table.insert(sigs[idx], sig) + end + + end + f:close() + return sigs +end +function test_opt(a, b) -- a=['Xnnn', 'X%nnn', 'X*'] b=[Xnnn] + if a == b then + return true + end + if string.len(a)<2 then + return false + end + local a1 = string.sub(a, 1, 1) + local b1 = string.sub(b, 1, 1) + local a2 = string.sub(a, 2, 2) + local b2 = string.sub(b, 2, 2) + local a2s = string.sub(a, 2) + local b2s = string.sub(b, 2) -- can't be % + local a3s = string.sub(a, 3) + local b3s = string.sub(b, 3) + if a1 ~= b1 then + return false + end + if a2s == "*" then + return true + end + if a2 == "%" then + if tonumber(b2s) % tonumber(a3s) == 0 then + return true + else + return false + end + end + return false +end + +function sig_compare(t, s) + if test_opt(t.wwww, s.wwww)~= true then + return false, string.format("wwww %s!=%s", t.wwww, s.wwww) + end + if t.ttt < s.ttt or + s.ttt < t.ttt-40 then + return false, string.format("ttl %i>=%i>=%i", t.ttt, s.ttt, t.ttt-40) + end + if t.D ~= s.D then + return false, string.format("D %s!=%s", t.D, s.D) + end + if t.ss ~= s.ss then + return false, string.format("ss %s!=%s", t.ss, s.ss) + end + if t.QQ ~= s.QQ then + return false, string.format("QQ %s!=%s", t.QQ, s.QQ) + end + + return sig_compare_OOO(t.OOO, s.OOO) +end + +function sig_compare_OOO(to, so) + for k,v in ipairs(to) do + local a = v + local b = so[k] + if test_opt(a,b) ~= true then + return false, string.format("Opt %s!=%s", a, b) + end + end + return true +end + +function sig_test(sigs, tsignature) + local ts = sig_unpack(tsignature) + local idx = sig_getindex(ts) + local t = split(tsignature, "[^|]+") + if sigs[idx] == nil then + return string.format("UNKNOWN [%s] (%s)", t[1], t[2]) + end + local out = {} + for k,sig in ipairs(sigs[idx]) do + local t, err = sig_compare(sig, ts) + if t == true then + table.insert(out, sig) + end + end + + if out[1] == nil then + return string.format("UNKNOWN [%s] (%s)", t[1], t[2]) + end + + local s = "" + local dist + for k, sig in ipairs(out) do + dist = tonumber(sig.ttt) - tonumber(ts.ttt) + s = s .. string.format("%s %s|", sig.OS, sig.details) + end + s = string.sub(s, 1, string.len(s)-1) + return string.format("%s (distance: %i, %s)", s, dist, t[2]) +end + +---------------------------------------------------------------------------------------------------------------- +portrule = function(host, port) + return true +end + +function mkidx(h,p1,p2) + return string.format("p0f_%i_%i_%s",p1,p2,h) +end + +action = function(host, port) + local pcap = nmap.new_socket() + local conn = nmap.new_socket() + local status, plen, layer2, layer3 + local sigs = nmap.registry["p0f_sigs"] + local _, o, tcp, localport + if sigs == nil then + sigs = sigs_load("p0fa.fp") + nmap.registry["p0f_sigs"] = sigs + end + + local layer3_offset = 14 + pcap:pcap_open(host.interface, 256, 0, layer3_offset + 12, 4, "tcp and (tcp[tcpflags] & (tcp-syn|tcp-ack) != 0) ") -- index is on source_ip + pcap:set_timeout(5000) + + conn:connect(host.ip, port.number) + _, _, localport, _,_ = conn:get_info() + while true do + tcp = nmap.registry[mkidx(host.ip, port.number, localport)] + if tcp ~= nil then + o = sig_test(sigs,tcp) + break + end + + status , plen, layer2, layer3 = pcap:pcap_receive(host.bin_ip) + if status then + tcp = Tcp:new(layer3, plen-layer3_offset) + if nmap.registry[mkidx(tcp.ip_src, tcp.tcp_sport, tcp.tcp_dport)] == nil then + nmap.registry[mkidx(tcp.ip_src, tcp.tcp_sport, tcp.tcp_dport)] = tcp:to_p0f() + end + tcp = nil + else -- timeouted + o = "Failed to capture SYN+ACK" + break + end + end + conn:close() + return o +end diff -Nraupbw nmap-diman-4516/scripts/promiscuous.nse nmap-diman-nse-pcap/scripts/promiscuous.nse --- nmap-diman-4516/scripts/promiscuous.nse 1970-01-01 01:00:00.000000000 +0100 +++ nmap-diman-nse-pcap/scripts/promiscuous.nse 2007-02-26 16:16:26.478352000 +0100 @@ -0,0 +1,105 @@ +id = "Promiscuous detection" +description = "Checks if hosts on local ethernet have network card in promiscuous mode." +author = "Marek Majkowski " +license = "See nmaps COPYING for licence" + +--[[ +This script tries to guess if node in local ethernet is in promisucous mode. + +The technique is described here: + http://www.securityfriday.com/promiscuous_detection_01.pdf + +]]-- + +categories = {"safe"} -- intrusive? + +-- okay, we're interested only in hosts that are on our ethernet lan +hostrule = function(host, port) + if host.directly_connected == true and + host.mac_addr ~= nil and + host.mac_addr_src ~= nil and + host.interface ~= nil and + dnet:get_interface_link(host.interface) == 'ethernet' then + return true + end + return false +end + +do_test = function(dnet, pcap, host, test) + local _ + local status + -- flush buffers :), wait quite long. + pcap:set_timeout(50) + repeat + status ,_,_,_ = pcap:pcap_receive(host.mac_addr_src .. host.mac_addr) + until status ~= true + + for i=1,3 do + pcap:set_timeout(20 * i*i) + dnet:ethernet_send(test) + status ,_,_,_ = pcap:pcap_receive(host.mac_addr_src .. host.mac_addr) + if status == true then + return(i) + end + end + return('_') +end + +action = function(host, port) + local dnet = nmap.new_dnet() + local pcap = nmap.new_socket() + local _ + local status + local results = { + ['1_____1_'] = false, -- MacOSX(Tiger.Panther)/Linux/ ?Win98/ WinXP sp2(no pcap) + ['1_______'] = false, -- Old Apple/SunOS/3Com + ['1___1_1_'] = false, -- MacOSX(Tiger) + ['11111111'] = true, -- BSD/Linux/OSX/ (or not promiscous openwrt ) + ['1_1___1_'] = false, -- WinXP sp2 + pcap|| win98 sniff || win2k sniff (see below) + ['111___1_'] = true, -- WinXP sp2 promisc +-- ['1111__1_'] = true, -- ?Win98 promisc + ??win98 no promisc *not confirmed* + } + dnet:ethernet_open(host.interface) + + pcap:pcap_open(host.interface, 64, 1, 0, 12, "arp") + + local test_static = host.mac_addr_src .. + string.char(0x08,0x06, 0x00,0x01, 0x08,0x00, 0x06,0x04, 0x00,0x01) .. + host.mac_addr_src .. + host.bin_ip_src .. + string.char(0x00,0x00, 0x00,0x00, 0x00,0x00) .. + host.bin_ip + local t = { + string.char(0xff,0xff, 0xff,0xff, 0xff,0xff), -- B32 no meaning? + string.char(0xff,0xff, 0xff,0xff, 0xff,0xfe), -- B31 + string.char(0xff,0xff, 0x00,0x00, 0x00,0x00), -- B16 + string.char(0xff,0x00, 0x00,0x00, 0x00,0x00), -- B8 + string.char(0x01,0x00, 0x00,0x00, 0x00,0x00), -- G + string.char(0x01,0x00, 0x5e,0x00, 0x00,0x00), -- M0 + string.char(0x01,0x00, 0x5e,0x00, 0x00,0x01), -- M1 no meaning? + string.char(0x01,0x00, 0x5e,0x00, 0x00,0x03), -- M3 + } + local v + local out = "" + for _, v in ipairs(t) do + out = out .. do_test(dnet, pcap, host, v .. test_static) + end + + dnet:ethernet_close() + pcap:pcap_close() + + if out == '1_1___1_' then + return 'Win98/Win2K/WinXP with pcap installed. I\'m unsure if they\'re sniffing. (tests: "' .. out .. '")' + end + if results[out] == false then + -- probably not sniffing + return + end + if results[out] == true then + -- rather sniffer. + return 'PROMISCUOUS (tests: "' .. out .. '")' + end + + -- results[out] == nil + return 'Unknown (tests: "' .. out .. '")' +end diff -Nraupbw nmap-diman-4516/Target.cc nmap-diman-nse-pcap/Target.cc --- nmap-diman-4516/Target.cc 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/Target.cc 2007-02-26 16:05:09.828064000 +0100 @@ -348,6 +348,10 @@ void Target::setDirectlyConnected(bool c directly_connected = connected? 1 : 0; } +int Target::directlyConnectedOrUnset(){ + return directly_connected; +} + bool Target::directlyConnected() { assert(directly_connected == 0 || directly_connected == 1); return directly_connected; diff -Nraupbw nmap-diman-4516/Target.h nmap-diman-nse-pcap/Target.h --- nmap-diman-4516/Target.h 2007-02-26 15:45:58.000000000 +0100 +++ nmap-diman-nse-pcap/Target.h 2007-02-26 16:05:09.828064000 +0100 @@ -170,6 +170,7 @@ class Target { been set yet. */ void setDirectlyConnected(bool connected); bool directlyConnected(); + int directlyConnectedOrUnset(); /* 1-directly connected, 0-no, -1-we don't know*/ /* If the host is NOT directly connected, you can set the next hop value here. It is OK to pass in a sockaddr_in or sockaddr_in6