diff --git a/include/AddressTree.h b/include/AddressTree.h index ce097e11dd..ad722a0b54 100644 --- a/include/AddressTree.h +++ b/include/AddressTree.h @@ -59,6 +59,7 @@ class AddressTree { int16_t findAddress(int family, void *addr, u_int8_t *network_mask_bits = NULL); int16_t findMac(u_int8_t addr[]); bool match(char *addr); + bool match(const IpAddress * const ipa, int network_bits) const; void dump(); void walk(void_fn3_t func, void * const user_data) const; }; diff --git a/include/BroadcastDomains.h b/include/BroadcastDomains.h new file mode 100644 index 0000000000..ca1d381b4e --- /dev/null +++ b/include/BroadcastDomains.h @@ -0,0 +1,45 @@ +/* + * + * (C) 2013-19 - ntop.org + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _BROADCAST_DOMAINS_H_ +#define _BROADCAST_DOMAINS_H_ + +class Host; + +#include "ntop_includes.h" + +class BroadcastDomains { + private: + AddressTree *inline_broadcast_domains; /* Accessed inline */ + AddressTree *broadcast_domains, *broadcast_domains_shadow; /* Accessed concurrently non-inline */ + time_t next_update, last_update; + + public: + BroadcastDomains(); + ~BroadcastDomains(); + + void inlineAddAddress(const IpAddress * const ipa, int network_bits); + void inlineReloadBroadcastDomains(bool force_immediate_reload = false); + bool inlineIsLocalBroadcastDomainHost(const Host * const h) const; +}; + +#endif /* _BROADCAST_DOMAINS_H_ */ + diff --git a/include/Host.h b/include/Host.h index 418fab520b..7928f9484d 100644 --- a/include/Host.h +++ b/include/Host.h @@ -146,7 +146,7 @@ class Host : public GenericHashEntry { inline void set_ipv6(struct ndpi_in6_addr *_ipv6) { ip.set(_ipv6); }; inline u_int32_t key() { return(ip.key()); }; char* getJSON(); - inline IpAddress* get_ip() { return(&ip); } + inline IpAddress* get_ip() { return(&ip); } void set_mac(Mac *m); void set_mac(char *m); void set_mac(u_int8_t *m); @@ -240,7 +240,7 @@ class Host : public GenericHashEntry { virtual NetworkStats* getNetworkStats(int16_t networkId) { return(NULL); }; inline Country* getCountryStats() { return country; }; - bool match(AddressTree *tree) { return(get_ip() ? get_ip()->match(tree) : false); }; + bool match(AddressTree * const tree) const { return ip.match(tree); }; void updateHostPool(bool isInlineCall, bool firstUpdate = false); virtual bool dropAllTraffic() { return(false); }; bool incFlowAlertHits(time_t when); diff --git a/include/IpAddress.h b/include/IpAddress.h index c9dafd1767..b814e638db 100644 --- a/include/IpAddress.h +++ b/include/IpAddress.h @@ -81,7 +81,7 @@ class IpAddress { char* serialize(); bool get_sockaddr(struct sockaddr ** const sa, ssize_t * const sa_len) const; json_object* getJSONObject(); - bool match(AddressTree *tree); + bool match(AddressTree * const tree) const; void* findAddress(AddressTree *ptree); void dump(); }; diff --git a/include/NetworkInterface.h b/include/NetworkInterface.h index 550407e5c6..45fde7b238 100644 --- a/include/NetworkInterface.h +++ b/include/NetworkInterface.h @@ -88,7 +88,7 @@ class NetworkInterface : public Checkpointable { MDNS *mdns; /* Broadcast domain */ - AddressTree *broadcast_domains; + BroadcastDomains bcast_domains; #ifdef HAVE_EBPF /* eBPF */ @@ -423,6 +423,7 @@ class NetworkInterface : public Checkpointable { void getnDPIProtocols(lua_State *vm, ndpi_protocol_category_t filter, bool skip_critical); void setnDPIProtocolCategory(u_int16_t protoId, ndpi_protocol_category_t protoCategory); void guessAllnDPIProtocols(); + void guessAllBroadcastDomainHosts(); int getActiveHostsList(lua_State* vm, u_int32_t *begin_slot, diff --git a/include/ntop_includes.h b/include/ntop_includes.h index 220e304061..6cdb0045a3 100644 --- a/include/ntop_includes.h +++ b/include/ntop_includes.h @@ -181,6 +181,7 @@ using namespace std; #include "AddressTree.h" #include "VlanAddressTree.h" #include "AddressList.h" +#include "BroadcastDomains.h" #include "IpAddress.h" #include "ntop_typedefs.h" #include "Trace.h" diff --git a/src/AddressTree.cpp b/src/AddressTree.cpp index d12b1b1bb4..2776a94422 100644 --- a/src/AddressTree.cpp +++ b/src/AddressTree.cpp @@ -239,6 +239,22 @@ bool AddressTree::match(char *addr) { /* ******************************************* */ +bool AddressTree::match(const IpAddress * const ipa, int network_bits) const { + if(!ipa) + return false; + + bool is_v4 = ipa->isIPv4(); + if(!is_v4 && !ptree_v6) + return false; + + if(is_v4) + return Utils::ptree_match(ptree_v4, AF_INET, &ipa->getIP()->ipType.ipv4, network_bits); + else + return Utils::ptree_match(ptree_v6, AF_INET6, &ipa->getIP()->ipType.ipv6, network_bits); +} + +/* ******************************************* */ + int16_t AddressTree::findAddress(int family, void *addr, u_int8_t *network_mask_bits) { patricia_tree_t *p; int bits; diff --git a/src/BroadcastDomains.cpp b/src/BroadcastDomains.cpp new file mode 100644 index 0000000000..dc55e164bd --- /dev/null +++ b/src/BroadcastDomains.cpp @@ -0,0 +1,90 @@ +/* + * + * (C) 2013-19 - ntop.org + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "ntop_includes.h" + +/* *************************************** */ + +BroadcastDomains::BroadcastDomains() { + inline_broadcast_domains = new (std::nothrow) AddressTree(false); + broadcast_domains = broadcast_domains_shadow = NULL; + next_update = last_update = 0; +} + +/* *************************************** */ + +BroadcastDomains::~BroadcastDomains() { + if(inline_broadcast_domains) { delete(inline_broadcast_domains); inline_broadcast_domains = NULL; } + if(broadcast_domains) { delete(broadcast_domains); broadcast_domains = NULL; } + if(broadcast_domains_shadow) { delete(broadcast_domains_shadow); broadcast_domains_shadow = NULL; } +} + +/* *************************************** */ + +void BroadcastDomains::inlineAddAddress(const IpAddress * const ipa, int network_bits) { + if(!inline_broadcast_domains + || inline_broadcast_domains->match(ipa, network_bits)) + return; + + inline_broadcast_domains->addAddress(ipa, network_bits, true /* Compact after add */); + + if(!next_update) + next_update = time(NULL) + 1; +} + +/* *************************************** */ + +void BroadcastDomains::inlineReloadBroadcastDomains(bool force_immediate_reload) { + time_t now = time(NULL); + + if(force_immediate_reload) + goto reload; + + if(next_update) { + if(now > next_update) { + /* do the swap */ + reload: + if(broadcast_domains_shadow) + delete broadcast_domains_shadow; + + broadcast_domains_shadow = broadcast_domains; + broadcast_domains = new (std::nothrow) AddressTree(*inline_broadcast_domains); + + last_update = now; + next_update = 0; + } + } + + if(broadcast_domains_shadow && now > last_update + 1) { + delete broadcast_domains_shadow; + broadcast_domains_shadow = NULL; + } +} + + +/* *************************************** */ + +bool BroadcastDomains::inlineIsLocalBroadcastDomainHost(const Host * const h) const { + if(inline_broadcast_domains && h) + return h->match(inline_broadcast_domains); + + return false; +} diff --git a/src/IpAddress.cpp b/src/IpAddress.cpp index 16d4d69d9a..c5178285ce 100644 --- a/src/IpAddress.cpp +++ b/src/IpAddress.cpp @@ -298,7 +298,7 @@ json_object* IpAddress::getJSONObject() { * @param ptree The hosts allowed to be accessed. * @return true if the host matches the tree, false otherwise. */ -bool IpAddress::match(AddressTree *tree) { +bool IpAddress::match(AddressTree * const tree) const { if(tree == NULL) return(false); else { diff --git a/src/NetworkInterface.cpp b/src/NetworkInterface.cpp index 1e9928f2f1..64d5f3d206 100644 --- a/src/NetworkInterface.cpp +++ b/src/NetworkInterface.cpp @@ -304,8 +304,6 @@ void NetworkInterface::init() { memset(subInterfaces, 0, sizeof(subInterfaces)); reload_custom_categories = reload_hosts_blacklist = false; - broadcast_domains = new AddressTree(false); - ip_addresses = "", networkStats = NULL, pcap_datalink_type = 0, cpu_affinity = -1; hide_from_top = hide_from_top_shadow = NULL; @@ -566,7 +564,6 @@ void NetworkInterface::deleteDataStructures() { if(vlans_hash) { delete(vlans_hash); vlans_hash = NULL; } if(macs_hash) { delete(macs_hash); macs_hash = NULL; } if(arp_hash_matrix) { delete(arp_hash_matrix); arp_hash_matrix = NULL; } - if(broadcast_domains) { delete(broadcast_domains); broadcast_domains = NULL; } #ifdef NTOPNG_PRO if(aggregated_flows_hash) { @@ -2024,6 +2021,7 @@ bool NetworkInterface::dissectPacket(u_int32_t bridge_iface_idx, pollQueuedeBPFEvents(); reloadCustomCategories(); + bcast_domains.inlineReloadBroadcastDomains(); #if 0 static u_int n = 0; @@ -2532,74 +2530,70 @@ decode_packet_eth: && !arp_spa_h->isBroadcastDomainHost()) arp_spa_h->setBroadcastDomainHost(); #endif - - if(broadcast_domains) { + #ifdef DEBUG - char buf1[32], buf2[32], buf3[32]; + char buf1[32], buf2[32], buf3[32]; #endif - u_int32_t src = ntohl(arpp->arp_spa); - u_int32_t dst = ntohl(arpp->arp_tpa); - u_int32_t net = src & dst; - u_int32_t diff; - u_int8_t cidr; - - if(src > dst) { - u_int32_t r = src; - src = dst; - dst = r; - } + u_int32_t src = ntohl(arpp->arp_spa); + u_int32_t dst = ntohl(arpp->arp_tpa); + u_int32_t net = src & dst; + u_int32_t diff; + u_int8_t cidr; - diff = dst-src; + if(src > dst) { + u_int32_t r = src; + src = dst; + dst = r; + } - if(diff <= 1024) { - u_int32_t mask; - IpAddress cur_bcast_domain; - - /* Ignore networks > /21 */ + diff = dst-src; - /* 131.114.2.22 <-> 131.114.3.2 */ - - if(diff <= 256) { - mask = 0xFFFFFF00, cidr = 24; - net &= mask, diff = 256; + if(diff <= 1024) { + u_int32_t mask; + IpAddress cur_bcast_domain; - if((src & mask) != (dst & mask)) { - mask <<= 1, cidr -= 1; - net = src & mask, diff = diff << 1; - } - } else if(diff <= 512) { - mask = 0xFFFFFE00, cidr = 23; - net &= mask, diff = 512; + /* Ignore networks > /21 */ - if((src & mask) != (dst & mask)) { - mask <<= 1, cidr -= 1; - net = src & mask, diff = diff << 1; - } - } else if(diff <= 768) { - mask = 0xFFFFFC00, cidr = 22; - net &= mask, diff = 768; + /* 131.114.2.22 <-> 131.114.3.2 */ - if((src & mask) != (dst & mask)) { - mask <<= 1, cidr -= 1; - net = src & mask, diff = diff << 1; - } - } else { - net &= 0xFFFFF800, diff = 1024, cidr = 21; + if(diff <= 256) { + mask = 0xFFFFFF00, cidr = 24; + net &= mask, diff = 256; + + if((src & mask) != (dst & mask)) { + mask <<= 1, cidr -= 1; + net = src & mask, diff = diff << 1; } + } else if(diff <= 512) { + mask = 0xFFFFFE00, cidr = 23; + net &= mask, diff = 512; + + if((src & mask) != (dst & mask)) { + mask <<= 1, cidr -= 1; + net = src & mask, diff = diff << 1; + } + } else if(diff <= 768) { + mask = 0xFFFFFC00, cidr = 22; + net &= mask, diff = 768; + + if((src & mask) != (dst & mask)) { + mask <<= 1, cidr -= 1; + net = src & mask, diff = diff << 1; + } + } else { + net &= 0xFFFFF800, diff = 1024, cidr = 21; + } #ifdef DEBUG - ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s <-> %s [%s - %u/%u]", - Utils::intoaV4(src, buf1, sizeof(buf1)), - Utils::intoaV4(dst, buf2, sizeof(buf2)), - Utils::intoaV4(net, buf3, sizeof(buf3)), - diff, cidr); + ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s <-> %s [%s - %u/%u]", + Utils::intoaV4(src, buf1, sizeof(buf1)), + Utils::intoaV4(dst, buf2, sizeof(buf2)), + Utils::intoaV4(net, buf3, sizeof(buf3)), + diff, cidr); #endif - - cur_bcast_domain.set(htonl(net)); - broadcast_domains->addAddress(&cur_bcast_domain, cidr, true); - // broadcast_domains->dump(); - } + cur_bcast_domain.set(htonl(net)); + bcast_domains.inlineAddAddress(&cur_bcast_domain, cidr); } e = getArpHashMatrixElement(srcMac->get_mac(), dstMac->get_mac(), &src2dst_element); @@ -5148,6 +5142,7 @@ u_int NetworkInterface::purgeIdleFlows() { pollQueuedeBPFEvents(); reloadCustomCategories(); + bcast_domains.inlineReloadBroadcastDomains(); if(!purge_idle_flows_hosts) return(0); @@ -5287,6 +5282,11 @@ void NetworkInterface::guessAllnDPIProtocols() { walker(&begin_slot, walk_all, walker_flows, guess_all_ndpi_protocols_walker, this); } +/* *************************************** */ + +void NetworkInterface::guessAllBroadcastDomainHosts() { + bcast_domains.inlineReloadBroadcastDomains(true); +} /* **************************************************** */ @@ -7324,13 +7324,10 @@ bool NetworkInterface::isInDhcpRange(IpAddress *ip) { /* *************************************** */ bool NetworkInterface::isLocalBroadcastDomainHost(Host *h) { - if(broadcast_domains == NULL) - return(false); - else { - IpAddress *i = h->get_ip(); + IpAddress *i = h->get_ip(); - return(i->match(broadcast_domains) || i->match(ntop->getLoadInterfaceAddresses())); - } + return(bcast_domains.inlineIsLocalBroadcastDomainHost(h) + || i->match(ntop->getLoadInterfaceAddresses())); } /* *************************************** */ diff --git a/src/PcapInterface.cpp b/src/PcapInterface.cpp index 6ebdca047c..6e9b6a9975 100644 --- a/src/PcapInterface.cpp +++ b/src/PcapInterface.cpp @@ -303,8 +303,10 @@ static void* packetPollLoop(void* ptr) { } while(pcap_list != NULL); - if(iface->read_from_pcap_dump()) + if(iface->read_from_pcap_dump()) { iface->guessAllnDPIProtocols(); + iface->guessAllBroadcastDomainHosts(); + } ntop->getTrace()->traceEvent(TRACE_NORMAL, "Terminated packet polling for %s", iface->get_name());