Network discovery:

- Removed redundancies between C and Lua
- Discovery is now enabled at interface creation (if supported by the device).
This commit is contained in:
Luca Deri 2017-08-16 09:07:28 +02:00
parent 50f2c97fc6
commit c74abf4eb0
13 changed files with 98 additions and 106 deletions

View file

@ -71,8 +71,12 @@ class NetworkInterface {
u_int16_t numVirtualInterfaces;
FlowHashingEnum flowHashingMode;
FlowHashing *flowHashing;
/* Network Discovery */
NetworkDiscovery *discovery;
MDNS *mdns;
SNMP *snmp;
string ip_addresses;
int id;
bool bridge_interface;
@ -571,6 +575,7 @@ class NetworkInterface {
inline void luaTopMacsProtos(lua_State *vm) { frequentMacs->luaTopMacsProtocols(vm); }
inline SNMP* getSNMP() { return(snmp); }
inline MDNS* getMDNS() { return(mdns); }
inline NetworkDiscovery* getNetworkDiscovery() { return(discovery); }
};
#endif /* _NETWORK_INTERFACE_H_ */

View file

@ -88,8 +88,6 @@ class Utils {
static void xor_encdec(u_char *data, int data_len, u_char *key);
static bool isPrintableChar(u_char c);
static const char* flowStatus2str(FlowStatus s, AlertType *aType);
static const char* deviceType2str(DeviceType devtype);
static const DeviceType str2DeviceType(char *devtype);
static char* formatMac(u_int8_t *mac, char *buf, u_int buf_len);
static void parseMac(u_int8_t *mac, const char *symMac);
static u_int32_t macHash(u_int8_t *mac);

View file

@ -383,6 +383,7 @@ typedef enum {
device_networking,
device_wifi,
device_nas,
device_multimedia,
device_max_type /* Leave it at the end */
} DeviceType;

View file

@ -124,12 +124,13 @@ local function findDevice(ip, mac, manufacturer, _mdns, ssdp_str, ssdp_entries,
return 'workstation', discover.asset_icons['workstation']..' (Linux)'
end
if((ssdp["upnp-org:serviceId:AVTransport"] ~= nil) or (ssdp["urn:upnp-org:serviceId:RenderingControl"] ~= nil)) then
if(string.contains(friendlyName, "TV")) then
return 'tv', discover.asset_icons['tv']
end
if(string.contains(friendlyName, "TV")) then
return 'tv', discover.asset_icons['tv']
if((ssdp["urn:upnp-org:serviceId:AVTransport"] ~= nil)
or (ssdp["urn:upnp-org:serviceId:RenderingControl"] ~= nil)) then
return 'multimedia', discover.asset_icons['multimedia']
end
if(ssdp_entries and ssdp_entries["modelDescription"]) then
@ -234,6 +235,10 @@ local function findDevice(ip, mac, manufacturer, _mdns, ssdp_str, ssdp_entries,
end
end
if(string.contains(manufacturer, "Ubiquity")) then
return 'networking', discover.asset_icons['networking']
end
return 'unknown', ""
end
@ -522,7 +527,7 @@ for mac,ip in pairsByValues(arp_mdns, asc) do
discover.devtype2icon(mac_info.devtype)
end
print("</td><td>"..deviceLabel.."</td></tr>\n")
interface.setMacDeviceType(mac, deviceType, false) -- false means don't overwrite if already set to ~= unknown
interface.setMacDeviceType(mac, discover.devtype2id(deviceType), false) -- false means don't overwrite if already set to ~= unknown
end
end

View file

@ -135,7 +135,8 @@ end
if(mac_info.devtype ~= 0) then
-- This is a known device type
print("<tr><th>".. i18n("details.device_type") .. "</th><td>" .. discover.devtype2icon(mac_info.devtype) .. " " .. mac_info.device_type .. "</td><td></td></tr>\n")
print("<tr><th>".. i18n("details.device_type") .. "</th><td>" .. discover.devtype2icon(mac_info.devtype) .. " ")
print(discover.devtype2string(mac_info.devtype) .. "</td><td></td></tr>\n")
end
print("<tr><th>".. i18n("details.first_last_seen") .. "</th><td nowrap><span id=first_seen>" .. formatEpoch(mac_info["seen.first"]) .. " [" .. secondsToTime(os.time()-mac_info["seen.first"]) .. " " .. i18n("details.ago").."]" .. "</span></td>\n")

View file

@ -136,20 +136,22 @@ discover.asset_icons = {
['networking'] = '<i class="fa fa-arrows fa-lg" aria-hidden="true"></i>',
['wifi'] = '<i class="fa fa-wifi fa-lg" aria-hidden="true"></i>',
['nas'] = '<i class="fa fa-database fa-lg" aria-hidden="true"></i>',
['multimedia'] = '<i class="fa fa-music fa-lg" aria-hidden="true"></i>',
}
discover.id2label = {
[0] = 'unknown',
[1] = 'printer',
[2] = 'video',
[3] = 'workstation',
[4] = 'laptop',
[5] = 'tablet',
[6] = 'phone',
[7] = 'tv',
[8] = 'networking',
[9] = 'wifi',
[10] = 'nas',
[0] = { 'unknown', '' },
[1] = { 'printer', 'Printer' },
[2] = { 'video', 'Video Recording/Display Device' },
[3] = { 'workstation', 'PC' },
[4] = { 'laptop', 'Laptop' },
[5] = { 'tablet', 'Tablet' },
[6] = { 'phone', 'Phone' },
[7] = { 'tv', 'TV' },
[8] = { 'networking', 'Network Device' },
[9] = { 'wifi', 'Wireless Network Device' },
[10] = { 'nas', 'NAS' },
[11] = { 'multimedia', 'Multimedia Device' },
}
discover.ghost_icon = '<i class="fa fa-snapchat-ghost fa-lg" aria-hidden="true"></i>'
@ -157,11 +159,27 @@ discover.ghost_icon = '<i class="fa fa-snapchat-ghost fa-lg" aria-hidden="true">
function discover.devtype2icon(devtype)
local label = discover.id2label[tonumber(devtype)]
if(label == nil) then label = 0 end
if(label == nil) then label = 'unknown' else label = label[1] end
return(discover.asset_icons[label])
end
function discover.devtype2id(devtype)
for k,v in pairs(discover.id2label) do
if(v[1] == devtype) then return k end
end
return(0) -- unknown
end
function discover.devtype2string(devtype)
for k,v in pairs(discover.id2label) do
if(k == devtype) then return v[2] end
end
return("") -- unknown
end
-- ###############
return discover

View file

@ -755,23 +755,25 @@ end
-- Convert bits to human readable format
function bitsToSizeMultiplier(bits, multiplier)
precision = 2
kilobit = 1000;
megabit = kilobit * multiplier;
gigabit = megabit * multiplier;
terabit = gigabit * multiplier;
if((bits >= kilobit) and (bits < megabit)) then
return round(bits / kilobit, precision) .. ' kbit/s';
elseif((bits >= megabit) and (bits < gigabit)) then
return round(bits / megabit, precision) .. ' Mbit/s';
elseif((bits >= gigabit) and (bits < terabit)) then
return round(bits / gigabit, precision) .. ' Gbit/s';
elseif(bits >= terabit) then
return round(bits / terabit, precision) .. ' Tbit/s';
else
return round(bits, precision) .. ' bit/s';
end
if(bits == nil) then return(0) end
precision = 2
kilobit = 1000;
megabit = kilobit * multiplier;
gigabit = megabit * multiplier;
terabit = gigabit * multiplier;
if((bits >= kilobit) and (bits < megabit)) then
return round(bits / kilobit, precision) .. ' kbit/s';
elseif((bits >= megabit) and (bits < gigabit)) then
return round(bits / megabit, precision) .. ' Mbit/s';
elseif((bits >= gigabit) and (bits < terabit)) then
return round(bits / gigabit, precision) .. ' Gbit/s';
elseif(bits >= terabit) then
return round(bits / terabit, precision) .. ' Tbit/s';
else
return round(bits, precision) .. ' bit/s';
end
end
function bitsToSize(bits)

View file

@ -45,11 +45,11 @@ function mac2record(mac)
record["column_breakdown"] = "<div class='progress'><div class='progress-bar progress-bar-warning' style='width: "
.. sent2rcvd .."%;'>Sent</div><div class='progress-bar progress-bar-info' style='width: " .. (100-sent2rcvd) .. "%;'>Rcvd</div></div>"
if(throughput_type == "pps") then
record["column_thpt"] = pktsToSize(mac["throughput_pps"])
else
record["column_thpt"] = bitsToSize(8*mac["throughput_bps"])
end
-- if(throughput_type == "pps") then
-- record["column_thpt"] = pktsToSize(mac["throughput_pps"])
-- else
-- record["column_thpt"] = bitsToSize(8*mac["throughput_bps"])
-- end
record["column_traffic"] = bytesToSize(mac["bytes.sent"] + mac["bytes.rcvd"])

View file

@ -753,9 +753,10 @@ static int ntop_set_mac_device_type(lua_State* vm) {
if(ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING)) return(CONST_LUA_ERROR);
mac = (char*)lua_tostring(vm, 1);
if(ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING)) return(CONST_LUA_ERROR);
dtype = (DeviceType)Utils::str2DeviceType((char*)lua_tostring(vm, 2));
if(ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER)) return(CONST_LUA_ERROR);
dtype = (DeviceType)lua_tonumber(vm, 2);
if(dtype > device_max_type) dtype = device_unknown;
if(ntop_lua_check(vm, __FUNCTION__, 3, LUA_TBOOLEAN)) return(CONST_LUA_ERROR);
overwriteType = (bool)lua_toboolean(vm, 3);
@ -1935,16 +1936,11 @@ static int ntop_discover_iface_hosts(lua_State* vm) {
if(lua_type(vm, 1) == LUA_TNUMBER) timeout = (u_int)lua_tonumber(vm, 1);
if(ntop_interface->getMDNS()) {
/* This is a device we can use for network discovery */
if(ntop_interface->getNetworkDiscovery()) {
/* TODO: do it periodically and not inline */
try {
NetworkDiscovery *d = new NetworkDiscovery(ntop_interface);
if(d) {
d->discover(vm, timeout);
delete d;
}
ntop_interface->getNetworkDiscovery()->discover(vm, timeout);
} catch(...) {
ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to perform network discovery");
}

View file

@ -153,8 +153,6 @@ void Mac::lua(lua_State* vm, bool show_details, bool asListElement) {
lua_push_bool_table_entry(vm, "source_mac", source_mac);
lua_push_bool_table_entry(vm, "special_mac", special_mac);
lua_push_int_table_entry(vm, "devtype", device_type);
lua_push_str_table_entry(vm, "device_type", (char *)Utils::deviceType2str(device_type));
((GenericTrafficElement*)this)->lua(vm, show_details);
}
lua_push_int_table_entry(vm, "seen.first", first_seen);

View file

@ -112,10 +112,24 @@ void NetworkDiscovery::arpScan(lua_State* vm) {
if(!pd) return;
if(pcap_lookupnet(iface->get_name(), &netp, &maskp, errbuf) == -1) {
/* Np IP/mask: can't do much then */
/* No IP/mask: can't do much then */
return;
}
/* Purge existing packets */
while(true) {
FD_ZERO(&rset);
FD_SET(pd_fd, &rset);
tv.tv_sec = 1, tv.tv_usec = 0; /* Wait very little */
if(select(pd_fd + 1, &rset, NULL, NULL, &tv) > 0) {
if((reply = (struct arp_packet*)pcap_next(pd, &h)) != NULL)
;
} else
break;
}
if((mdns_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
ntop->getTrace()->traceEvent(TRACE_ERROR, "Unable to create MDNS socket");
else {

View file

@ -108,8 +108,8 @@ NetworkInterface::NetworkInterface(const char *name,
|| (!strncmp(name, "lo", 2))
|| (Utils::readIPv4((char*)name) == 0))
; /* Don't setup MDNS on ZC or RSS interfaces */
else
mdns = new MDNS(this);
else
mdns = new MDNS(this), discovery = new NetworkDiscovery(this);
if(id >= 0) {
u_int32_t num_hashes;
@ -266,7 +266,7 @@ void NetworkInterface::init() {
pkt_dumper = NULL, numL2Devices = 0, numHosts = 0, numLocalHosts = 0,
checkpointPktCount = checkpointBytesCount = checkpointPktDropCount = 0,
pollLoopCreated = false, bridge_interface = false,
mdns = NULL, snmp = NULL;
mdns = NULL, snmp = NULL, discovery = NULL;
if(ntop && ntop->getPrefs() && ntop->getPrefs()->are_taps_enabled())
pkt_dumper_tap = new PacketDumperTuntap(this);
@ -625,6 +625,7 @@ NetworkInterface::~NetworkInterface() {
if(host_pools) delete host_pools; /* note: this requires ndpi_struct */
deleteDataStructures();
if(ifDescription) free(ifDescription);
if(discovery) delete discovery;
if(mdns) delete mdns;
if(snmp) delete snmp;
if(statsManager) delete statsManager;

View file

@ -370,53 +370,6 @@ const char* Utils::flowStatus2str(FlowStatus s, AlertType *aType) {
/* **************************************************** */
/* Note: keep in sync with lua_utils icon_keys on discover.lua */
const DeviceType Utils::str2DeviceType(char *devtype) {
if(!strcasecmp(devtype, "printer")) return(device_printer);
else if(!strcasecmp(devtype, "video")) return(device_video);
else if(!strcasecmp(devtype, "workstation")) return(device_workstation);
else if(!strcasecmp(devtype, "laptop")) return(device_laptop);
else if(!strcasecmp(devtype, "tablet")) return(device_tablet);
else if(!strcasecmp(devtype, "phone")) return(device_phone);
else if(!strcasecmp(devtype, "tv")) return(device_tv);
else if(!strcasecmp(devtype, "networking")) return(device_networking);
else if(!strcasecmp(devtype, "wifi")) return(device_wifi);
else if(!strcasecmp(devtype, "nas")) return(device_nas);
else return(device_unknown);
}
/* Note: keep in sync with lua_utils icon_keys on discover.lua */
const char* Utils::deviceType2str(DeviceType devtype) {
switch (devtype) {
case device_printer:
return("Printer");
case device_video:
return("Video");
case device_workstation:
return("Computer");
case device_laptop:
return("Laptop");
case device_tablet:
return("Tablet");
case device_phone:
return("Phone");
case device_tv:
return("TV");
case device_networking:
return("Router/Switch");
case device_wifi:
return("WiFi Device");
case device_nas:
return("NAS");
case device_unknown:
default:
return("Unknown");
}
}
/* **************************************************** */
const char* Utils::trend2str(ValueTrend t) {
switch(t) {
case trend_up: