From df41e839255cef01abcceade8a97fcba55988282 Mon Sep 17 00:00:00 2001 From: Luca Deri Date: Fri, 11 Aug 2017 14:24:05 +0200 Subject: [PATCH] Added detection of ghost hosts in discovery --- include/Host.h | 1 + include/NetworkInterface.h | 1 + scripts/lua/discover.lua | 33 +++++++++++++++++++++++++++++++++ src/Host.cpp | 19 +++++++++++++++++-- src/Lua.cpp | 33 +++++++++++++++++++++++++++------ src/NetworkInterface.cpp | 34 ++++++++++++++++++++++++++++++++++ src/Utils.cpp | 7 ++++--- 7 files changed, 117 insertions(+), 11 deletions(-) diff --git a/include/Host.h b/include/Host.h index 28b3defba9..8b6a944983 100644 --- a/include/Host.h +++ b/include/Host.h @@ -174,6 +174,7 @@ class Host : public GenericHost { void serialize2redis(); bool deserialize(char *json_str, char *key); bool addIfMatching(lua_State* vm, AddressTree * ptree, char *key); + bool addIfMatching(lua_State* vm, u_int8_t *mac); void updateSynFlags(time_t when, u_int8_t flags, Flow *f, bool syn_sent); void incNumFlows(bool as_client); diff --git a/include/NetworkInterface.h b/include/NetworkInterface.h index c7f7117fe3..7a19d7e76e 100644 --- a/include/NetworkInterface.h +++ b/include/NetworkInterface.h @@ -305,6 +305,7 @@ class NetworkInterface { Mac *dst_mac, IpAddress *_dst_ip, Host **dst); Flow* findFlowByKey(u_int32_t key, AddressTree *allowed_hosts); bool findHostsByName(lua_State* vm, AddressTree *allowed_hosts, char *key); + bool findHostsByMac(lua_State* vm, u_int8_t *mac); bool dissectPacket(u_int8_t bridge_iface_idx, u_int8_t *sender_mac, /* Non NULL only for NFQUEUE interfaces */ const struct pcap_pkthdr *h, const u_char *packet, diff --git a/scripts/lua/discover.lua b/scripts/lua/discover.lua index 78ed3f1752..ff43211981 100644 --- a/scripts/lua/discover.lua +++ b/scripts/lua/discover.lua @@ -144,6 +144,8 @@ local asset_icons = { ['wifi'] = '', } +local ghost_icon = '' + local function getbaseURL(url) local name = url:match( "([^/]+)$" ) @@ -394,6 +396,8 @@ end interface.select(ifname) + + io.write("Starting ARP discovery...\n") local arp_mdns = interface.arpScanHosts() @@ -404,6 +408,27 @@ if(arp_mdns == nil) then return end +local ghost_macs = {} +local ghost_found = false + +-- Add the known macs to the list +local known_macs = interface.getMacsInfo(nil, 999, 0, false, 0, tonumber(vlan), true, true, nil) + +for _,hmac in pairs(known_macs.macs) do + if(hmac["bytes.sent"] > 0) then -- Skip silent hosts + if(arp_mdns[hmac.mac] == nil) then + local ips = interface.findHostByMac(hmac.mac) + -- io.write("Missing MAC "..hmac.mac.."\n") + + for k,v in pairs(ips) do + arp_mdns[hmac.mac] = k + ghost_macs[hmac.mac] = k + ghost_found = true + end + end + end +end + io.write("Starting SSDP discovery...\n") local ssdp = interface.discoverHosts(3) @@ -490,6 +515,10 @@ for mac,ip in pairsByValues(arp_mdns, asc) do print(""..ip.."") if(ssdp[ip] and ssdp[ip].icon) then print(ssdp[ip].icon .. " ") end + if(ghost_macs[mac] ~= nil) then + print(' '..ghost_icon..'') + end + print("") if((sym ~= "") and (sym ~= ip)) then print(sym) end @@ -555,4 +584,8 @@ end print("\n") +if(ghost_found) then + print('NOTE: The '..ghost_icon..' icon highlights ghost hosts (i.e. they do not belong to the interface IP address network).') +end + dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua") diff --git a/src/Host.cpp b/src/Host.cpp index 8f667cb030..d266bc90cf 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -1092,8 +1092,7 @@ bool Host::addIfMatching(lua_State* vm, AddressTree *ptree, char *key) { keybuf_ptr = get_hostkey(keybuf, sizeof(keybuf)); if(strcasestr((ipbuf_ptr = Utils::formatMac(m ? m->get_mac() : NULL, ipbuf, sizeof(ipbuf))), key) /* Match by MAC */ - || - strcasestr((ipbuf_ptr = Utils::formatMac(sm ? sm->get_mac() : NULL, ipbuf, sizeof(ipbuf))), key) /* Match by MAC */ + || strcasestr((ipbuf_ptr = Utils::formatMac(sm ? sm->get_mac() : NULL, ipbuf, sizeof(ipbuf))), key) /* Match by MAC */ || strcasestr((ipbuf_ptr = keybuf_ptr), key) /* Match by hostkey */ || strcasestr((ipbuf_ptr = get_visual_name(ipbuf, sizeof(ipbuf))), key)) { /* Match by name */ lua_push_str_table_entry(vm, keybuf_ptr, ipbuf_ptr); @@ -1105,6 +1104,22 @@ bool Host::addIfMatching(lua_State* vm, AddressTree *ptree, char *key) { /* *************************************** */ +bool Host::addIfMatching(lua_State* vm, u_int8_t *_mac) { + if((mac && mac->equal(0, _mac)) + || (secondary_mac && secondary_mac->equal(0, _mac))) { + char keybuf[64], ipbuf[32]; + + lua_push_str_table_entry(vm, + get_string_key(ipbuf, sizeof(ipbuf)), + get_hostkey(keybuf, sizeof(keybuf))); + return(true); + } + + return(false); +} + +/* *************************************** */ + bool Host::deserialize(char *json_str, char *key) { json_object *o, *obj; enum json_tokener_error jerr = json_tokener_success; diff --git a/src/Lua.cpp b/src/Lua.cpp index 3a501869b1..146d96b704 100644 --- a/src/Lua.cpp +++ b/src/Lua.cpp @@ -697,15 +697,15 @@ static int ntop_get_interface_macs_info(lua_State* vm) { u_int16_t vlan_id = 0, pool_filter = (u_int16_t)-1; bool a2zSortOrder = true, sourceMacsOnly = false, hostMacsOnly = false; - if(lua_type(vm, 1) == LUA_TSTRING) sortColumn = (char*)lua_tostring(vm, 1); - if(lua_type(vm, 2) == LUA_TNUMBER) maxHits = (u_int16_t)lua_tonumber(vm, 2); - if(lua_type(vm, 3) == LUA_TNUMBER) toSkip = (u_int16_t)lua_tonumber(vm, 3); + if(lua_type(vm, 1) == LUA_TSTRING) sortColumn = (char*)lua_tostring(vm, 1); + if(lua_type(vm, 2) == LUA_TNUMBER) maxHits = (u_int16_t)lua_tonumber(vm, 2); + if(lua_type(vm, 3) == LUA_TNUMBER) toSkip = (u_int16_t)lua_tonumber(vm, 3); if(lua_type(vm, 4) == LUA_TBOOLEAN) a2zSortOrder = lua_toboolean(vm, 4); - if(lua_type(vm, 5) == LUA_TNUMBER) vlan_id = (u_int16_t)lua_tonumber(vm, 5); + if(lua_type(vm, 5) == LUA_TNUMBER) vlan_id = (u_int16_t)lua_tonumber(vm, 5); if(lua_type(vm, 6) == LUA_TBOOLEAN) sourceMacsOnly = lua_toboolean(vm, 6); if(lua_type(vm, 7) == LUA_TBOOLEAN) hostMacsOnly = lua_toboolean(vm, 7); - if(lua_type(vm, 8) == LUA_TSTRING) manufacturer = lua_tostring(vm, 8); - if(lua_type(vm, 9) == LUA_TNUMBER) pool_filter = (u_int16_t)lua_tonumber(vm, 9); + if(lua_type(vm, 8) == LUA_TSTRING) manufacturer = lua_tostring(vm, 8); + if(lua_type(vm, 9) == LUA_TNUMBER) pool_filter = (u_int16_t)lua_tonumber(vm, 9); if(!ntop_interface || ntop_interface->getActiveMacList(vm, @@ -2475,6 +2475,26 @@ static int ntop_get_interface_find_host(lua_State* vm) { /* ****************************************** */ +static int ntop_get_interface_find_host_by_mac(lua_State* vm) { + NetworkInterface *ntop_interface = getCurrentInterface(vm); + char *mac; + u_int8_t _mac[6]; + + ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__); + + if(ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING)) return(CONST_LUA_ERROR); + mac = (char*)lua_tostring(vm, 1); + + if(!ntop_interface) return(CONST_LUA_ERROR); + Utils::parseMac(_mac, mac); + + ntop_interface->findHostsByMac(vm, _mac); + + return(CONST_LUA_OK); +} + +/* ****************************************** */ + static int ntop_update_host_traffic_policy(lua_State* vm) { NetworkInterface *ntop_interface = getCurrentInterface(vm); char *host_ip; @@ -5818,6 +5838,7 @@ static const luaL_Reg ntop_interface_reg[] = { { "findNameFlows", ntop_get_interface_find_proc_name_flows }, { "listHTTPhosts", ntop_list_http_hosts }, { "findHost", ntop_get_interface_find_host }, + { "findHostByMac", ntop_get_interface_find_host_by_mac }, { "updateHostTrafficPolicy", ntop_update_host_traffic_policy }, { "refreshHostsAlertsConfiguration", ntop_refresh_hosts_alerts_configuration }, { "setSecondTraffic", ntop_set_second_traffic }, diff --git a/src/NetworkInterface.cpp b/src/NetworkInterface.cpp index 6e59997d3c..73ef163d92 100644 --- a/src/NetworkInterface.cpp +++ b/src/NetworkInterface.cpp @@ -4622,6 +4622,39 @@ static bool hosts_search_walker(GenericHashEntry *h, void *user_data) { /* **************************************************** */ +struct search_mac_info { + lua_State *vm; + u_int8_t *mac; + u_int num_matches; +}; + +/* **************************************************** */ + +static bool macs_search_walker(GenericHashEntry *h, void *user_data) { + Host *host = (Host*)h; + struct search_mac_info *info = (struct search_mac_info*)user_data; + + if(host->addIfMatching(info->vm, info->mac)) + info->num_matches++; + + /* Stop after CONST_MAX_NUM_FIND_HITS matches */ + return((info->num_matches > CONST_MAX_NUM_FIND_HITS) ? true /* stop */ : false /* keep walking */); +} + +/* *************************************** */ + +bool NetworkInterface::findHostsByMac(lua_State* vm, u_int8_t *mac) { + struct search_mac_info info; + + info.vm = vm, info.mac = mac, info.num_matches = 0; + + lua_newtable(vm); + walker(walker_hosts, macs_search_walker, (void*)&info); + return(info.num_matches > 0); +} + +/* **************************************************** */ + bool NetworkInterface::findHostsByName(lua_State* vm, AddressTree *allowed_hosts, char *key) { @@ -5844,3 +5877,4 @@ void NetworkInterface::topMacsAdd(Mac *mac, ndpi_protocol *proto, u_int32_t byte frequentMacs->addMacProtocol(mac->get_mac(), proto->app_protocol, bytes); } } + diff --git a/src/Utils.cpp b/src/Utils.cpp index 0eedaadd85..07c542fda4 100755 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1824,12 +1824,13 @@ bool Utils::isSpecialMac(u_int8_t *mac) { /* ****************************************************** */ void Utils::parseMac(u_int8_t *mac, const char *symMac) { - int _mac[6]; + int _mac[6] = { 0 }; + sscanf(symMac, "%x:%x:%x:%x:%x:%x", &_mac[0], &_mac[1], &_mac[2], &_mac[3], &_mac[4], &_mac[5]); - - for (int i = 0; i < 6; i++) mac[i] = (u_int8_t)_mac[i]; + + for(int i = 0; i < 6; i++) mac[i] = (u_int8_t)_mac[i]; } /* *********************************************** */