diff --git a/include/Checkpointable.h b/include/Checkpointable.h index 319787f1ec..1805a84167 100644 --- a/include/Checkpointable.h +++ b/include/Checkpointable.h @@ -36,7 +36,7 @@ class Checkpointable { public: Checkpointable(); - ~Checkpointable(); + virtual ~Checkpointable(); bool checkpoint(lua_State* vm, NetworkInterface *iface, u_int8_t checkpoint_id, DetailsLevel details_level); /* This function must return a serialization of the entity information needed diff --git a/include/GenericHost.h b/include/GenericHost.h deleted file mode 100644 index 0b40cea388..0000000000 --- a/include/GenericHost.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * (C) 2013-18 - 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 _GENERIC_HOST_H_ -#define _GENERIC_HOST_H_ - -#include "ntop_includes.h" - -class NetworkInterface; -class Flow; - -class GenericHost : public GenericHashEntry, public GenericTrafficElement { - protected: - bool localHost, systemHost; - u_int32_t low_goodput_client_flows, low_goodput_server_flows; - u_int32_t total_activity_time /* sec */, last_epoch_update; /* useful to avoid multiple updates */ - - /* Throughput */ - float goodput_bytes_thpt, last_goodput_bytes_thpt, bytes_goodput_thpt_diff; - ValueTrend bytes_goodput_thpt_trend; - - public: - GenericHost(NetworkInterface *_iface); - virtual ~GenericHost() { - /* Pool counters are updated both in and outside the datapath. - So decPoolNumHosts must stay in the destructor to preserve counters - consistency (no thread outside the datapath will change the last pool id) */ - iface->decPoolNumHosts(get_host_pool(), true /* Host is deleted inline */); - }; - - inline bool isLocalHost() { return(localHost || systemHost); }; - inline bool isSystemHost() { return(systemHost); }; - inline void setSystemHost() { systemHost = true; }; - - inline nDPIStats* get_ndpi_stats() { return(ndpiStats); }; - - void incStats(u_int32_t when, u_int8_t l4_proto, u_int ndpi_proto, - u_int64_t sent_packets, u_int64_t sent_bytes, u_int64_t sent_goodput_bytes, - u_int64_t rcvd_packets, u_int64_t rcvd_bytes, u_int64_t rcvd_goodput_bytes); - - virtual char* get_string_key(char *buf, u_int buf_len) { return(NULL); }; - virtual bool match(AddressTree *ptree) { return(true); }; - - virtual void set_to_purge() { /* Saves 1 extra-step of purge idle */ - iface->decNumHosts(isLocalHost()); - GenericHashEntry::set_to_purge(); - }; - - inline bool isChildSafe() { -#ifdef NTOPNG_PRO - return(iface->getHostPools()->isChildrenSafePool(host_pool_id)); -#else - return(false); -#endif - }; - - inline bool forgeGlobalDns() { -#ifdef NTOPNG_PRO - return(iface->getHostPools()->forgeGlobalDns(host_pool_id)); -#else - return(false); -#endif - }; -}; - -#endif /* _GENERIC_HOST_H_ */ diff --git a/include/Host.h b/include/Host.h index a6411e8592..82edcdcd7f 100644 --- a/include/Host.h +++ b/include/Host.h @@ -24,42 +24,49 @@ #include "ntop_includes.h" -class Host : public GenericHost, public Checkpointable { - private: - u_int32_t asn; - AutonomousSystem *as; - Country *country; - Vlan *vlan; - char *symbolic_name, *asname, os[16], trafficCategory[12], *info; - FrequentStringItems *top_sites; - char *old_sites; - bool blacklisted_host, blacklisted_alarm_emitted, drop_all_host_traffic, dump_host_traffic, dhcpUpdated, host_label_set; - u_int32_t host_quota_mb; - int16_t local_network_id; - u_int32_t num_alerts_detected; +class Host : public Checkpointable, public GenericHashEntry, public GenericTrafficElement { + protected: IpAddress ip; - Mutex *m; Mac *mac; - u_int32_t mac_last_seen; - u_int8_t num_resolve_attempts; - time_t nextResolveAttempt, nextSitesUpdate; - AlertCounter *syn_flood_attacker_alert, *syn_flood_victim_alert; - AlertCounter *flow_flood_attacker_alert, *flow_flood_victim_alert; + char *symbolic_name; + char *asname, *info; TrafficStats tcp_sent, tcp_rcvd; TrafficStats udp_sent, udp_rcvd; TrafficStats icmp_sent, icmp_rcvd; TrafficStats other_ip_sent, other_ip_rcvd; TrafficStats ingress_drops, egress_drops; - ICMPstats *icmp; PacketStats sent_stats, recv_stats; + struct { + u_int32_t pktRetr, pktOOO, pktLost, pktKeepAlive; + } tcpPacketStats; /* Sent packets */ u_int32_t total_num_flows_as_client, total_num_flows_as_server; + u_int32_t total_activity_time /* sec */; + + virtual json_object* getJSONObject(); + + private: + u_int32_t low_goodput_client_flows, low_goodput_server_flows; + u_int32_t last_epoch_update; /* useful to avoid multiple updates */ + + /* Throughput */ + float goodput_bytes_thpt, last_goodput_bytes_thpt, bytes_goodput_thpt_diff; + ValueTrend bytes_goodput_thpt_trend; + + u_int32_t asn; + AutonomousSystem *as; + Country *country; + Vlan *vlan; + bool host_label_set; + u_int32_t host_quota_mb; + + Mutex *m; + u_int32_t mac_last_seen; + u_int8_t num_resolve_attempts; + time_t nextResolveAttempt; + u_int32_t num_active_flows_as_client, num_active_flows_as_server; - DnsStats *dns; - HTTPstats *http; - bool trigger_host_alerts, good_low_flow_detected; - u_int32_t attacker_max_num_flows_per_sec, victim_max_num_flows_per_sec; - u_int32_t attacker_max_num_syn_per_sec, victim_max_num_syn_per_sec; - NetworkStats *networkStats; + bool good_low_flow_detected; + char *ssdpLocation, *ssdpLocation_shadow; #ifdef NTOPNG_PRO bool has_blocking_quota, has_blocking_shaper; @@ -70,26 +77,47 @@ class Host : public GenericHost, public Checkpointable { bool checkpoint_set; bool hidden_from_top; - struct { - u_int32_t pktRetr, pktOOO, pktLost, pktKeepAlive; - } tcpPacketStats; /* Sent packets */ - void initialize(Mac *_mac, u_int16_t _vlan_id, bool init_all); - void refreshHTTPBL(); - json_object* getJSONObject(); - bool readDHCPCache(); - void updateLocal(); + virtual void refreshHTTPBL() {}; + virtual bool readDHCPCache() { return false; }; #ifdef NTOPNG_PRO TrafficShaper *get_shaper(ndpi_protocol ndpiProtocol, bool isIngress); void get_quota(u_int16_t protocol, u_int64_t *bytes_quota, u_int32_t *secs_quota, u_int32_t *schedule_bitmap, bool *is_category); #endif + char* printMask(char *str, u_int str_len) { return ip.printMask(str, str_len, isLocalHost()); }; public: - Host(NetworkInterface *_iface); - Host(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId); Host(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId); Host(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId, IpAddress *_ip); - ~Host(); + + virtual ~Host(); + + virtual bool isLocalHost() = 0; + virtual bool isSystemHost() = 0; + inline void setSystemHost() { /* TODO: remove */ }; + + inline nDPIStats* get_ndpi_stats() { return(ndpiStats); }; + + virtual void set_to_purge() { /* Saves 1 extra-step of purge idle */ + iface->decNumHosts(isLocalHost()); + GenericHashEntry::set_to_purge(); + }; + + inline bool isChildSafe() { +#ifdef NTOPNG_PRO + return(iface->getHostPools()->isChildrenSafePool(host_pool_id)); +#else + return(false); +#endif + }; + + inline bool forgeGlobalDns() { +#ifdef NTOPNG_PRO + return(iface->getHostPools()->forgeGlobalDns(host_pool_id)); +#else + return(false); +#endif + }; virtual void updateStats(struct timeval *tv); void incLowGoodputFlows(bool asClient); @@ -99,29 +127,26 @@ class Host : public GenericHost, public Checkpointable { inline void incOOOPkts(u_int32_t num) { tcpPacketStats.pktOOO += num; }; inline void incLostPkts(u_int32_t num) { tcpPacketStats.pktLost += num; }; inline void incKeepAlivePkts(u_int32_t num) { tcpPacketStats.pktKeepAlive += num; }; - inline int16_t get_local_network_id() { return(local_network_id); }; + virtual int16_t get_local_network_id() = 0; inline PacketStats* get_sent_stats() { return(&sent_stats); }; inline PacketStats* get_recv_stats() { return(&recv_stats); }; - inline HTTPstats* getHTTPstats() { return(http); }; - inline HTTPstats* getHTTP() { return(http); }; + virtual HTTPstats* getHTTPstats() { return(NULL); }; inline void set_ipv4(u_int32_t _ipv4) { ip.set(_ipv4); }; inline void set_ipv6(struct ndpi_in6_addr *_ipv6) { ip.set(_ipv6); }; inline u_int32_t key() { return(ip.key()); }; char* getJSON(); - void setOS(char *_os); + virtual void setOS(char *_os) {}; inline IpAddress* get_ip() { return(&ip); } void set_mac(Mac *m); void set_mac(char *m); void set_mac(u_int8_t *m); - inline bool isBlacklisted() { return(blacklisted_host); } - inline bool isBlacklistedAlarmEmitted() { return(blacklisted_alarm_emitted); } - inline void setBlacklistedAlarmEmitted() { blacklisted_alarm_emitted = true; } - bool hasAnomalies(); + virtual bool isBlacklisted() { return(false); } inline u_int8_t* get_mac() { return(mac ? mac->get_mac() : NULL); } inline Mac* getMac() { return(mac); } - inline char* get_os() { return(os); } + virtual char* get_traffic_category() { return((char*)""); } + virtual char* get_os() { return((char*)""); } inline char* get_name() { return(symbolic_name); } - inline char* get_httpbl() { refreshHTTPBL(); return(trafficCategory); } + inline char* get_httpbl() { refreshHTTPBL(); return(get_traffic_category()); } #ifdef NTOPNG_PRO inline TrafficShaper *get_ingress_shaper(ndpi_protocol ndpiProtocol) { return(get_shaper(ndpiProtocol, true)); } inline TrafficShaper *get_egress_shaper(ndpi_protocol ndpiProtocol) { return(get_shaper(ndpiProtocol, false)); } @@ -148,10 +173,9 @@ class Host : public GenericHost, public Checkpointable { inline char* get_string_key(char *buf, u_int buf_len) { return(ip.print(buf, buf_len)); }; char* get_hostkey(char *buf, u_int buf_len, bool force_vlan=false); bool idle(); - void incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer); - void lua(lua_State* vm, AddressTree * ptree, bool host_details, + virtual void incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer) {}; + virtual void lua(lua_State* vm, AddressTree * ptree, bool host_details, bool verbose, bool returnHost, bool asListElement); - void luaAnomalies(lua_State* vm); void resolveHostName(); void setName(char *name); void set_host_label(char *label_name, bool ignoreIfPresent); @@ -162,50 +186,50 @@ class Host : public GenericHost, public Checkpointable { u_int64_t sent_packets, u_int64_t sent_bytes, u_int64_t sent_goodput_bytes, u_int64_t rcvd_packets, u_int64_t rcvd_bytes, u_int64_t rcvd_goodput_bytes); void incHitter(Host *peer, u_int64_t sent_bytes, u_int64_t rcvd_bytes); - void updateHostTrafficPolicy(char *key); + virtual void updateHostTrafficPolicy(char *key) {}; char* serialize(); - void serialize2redis(); - bool deserialize(char *json_str, char *key); + virtual void serialize2redis() {}; 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); + virtual void updateSynFlags(time_t when, u_int8_t flags, Flow *f, bool syn_sent) {}; inline void updateRoundTripTime(u_int32_t rtt_msecs) { if(as) as->updateRoundTripTime(rtt_msecs); } - void incNumFlows(bool as_client); + virtual void incNumFlows(bool as_client); void decNumFlows(bool as_client); inline void incFlagStats(bool as_client, u_int8_t flags) { if (as_client) sent_stats.incFlagStats(flags); else recv_stats.incFlagStats(flags); }; - inline void incIngressDrops(u_int num_bytes) { ingress_drops.incStats(num_bytes); }; - inline void incEgressDrops(u_int num_bytes) { egress_drops.incStats(num_bytes); }; - inline void incNumDNSQueriesSent(u_int16_t query_type) { if(dns) dns->incNumDNSQueriesSent(query_type); }; - inline void incNumDNSQueriesRcvd(u_int16_t query_type) { if(dns) dns->incNumDNSQueriesRcvd(query_type); }; - inline void incNumDNSResponsesSent(u_int32_t ret_code) { if(dns) dns->incNumDNSResponsesSent(ret_code); }; - inline void incNumDNSResponsesRcvd(u_int32_t ret_code) { if(dns) dns->incNumDNSResponsesRcvd(ret_code); }; - inline bool triggerAlerts() { return(trigger_host_alerts); }; + inline void incIngressDrops(u_int num_bytes) { ingress_drops.incStats(num_bytes); }; + inline void incEgressDrops(u_int num_bytes) { egress_drops.incStats(num_bytes); }; + virtual void incNumDNSQueriesSent(u_int16_t query_type) { }; + virtual void incNumDNSQueriesRcvd(u_int16_t query_type) { }; + virtual void incNumDNSResponsesSent(u_int32_t ret_code) { }; + virtual void incNumDNSResponsesRcvd(u_int32_t ret_code) { }; + virtual bool triggerAlerts() { return(false); }; - u_int32_t getNumAlerts(bool from_alertsmanager = false); - inline void setNumAlerts(u_int32_t num) { num_alerts_detected = num; }; - void postHashAdd(); - void loadAlertsCounter(); + virtual u_int32_t getNumAlerts(bool from_alertsmanager = false) { return(0); }; + virtual void setNumAlerts(u_int32_t num) {}; + virtual void postHashAdd(); + virtual void loadAlertsCounter() {}; - inline NetworkStats* getNetworkStats(int16_t networkId){ return(iface->getNetworkStats(networkId)); }; - inline Country* getCountryStats() { return country; }; + virtual NetworkStats* getNetworkStats(int16_t networkId) { return(NULL); }; + inline Country* getCountryStats() { return country; }; - void refreshHostAlertPrefs(); - void updateHTTPHostRequest(char *virtual_host_name, u_int32_t num_req, u_int32_t bytes_sent, u_int32_t bytes_rcvd); + virtual void refreshHostAlertPrefs() {}; + virtual void updateHTTPHostRequest(char *virtual_host_name, u_int32_t num_req, u_int32_t bytes_sent, u_int32_t bytes_rcvd) {}; bool match(AddressTree *tree) { return(get_ip() ? get_ip()->match(tree) : false); }; void updateHostPool(bool isInlineCall, bool firstUpdate=false); - inline bool dropAllTraffic() { return(drop_all_host_traffic); }; - inline bool dumpHostTraffic() { return(dump_host_traffic); }; - void setDumpTrafficPolicy(bool new_policy); + virtual bool dropAllTraffic() { return(false); }; + virtual bool dumpHostTraffic() { return(false); }; + virtual void setDumpTrafficPolicy(bool new_policy) {}; bool serializeCheckpoint(json_object *my_object, DetailsLevel details_level); void checkPointHostTalker(lua_State *vm, bool saveCheckpoint); inline void setInfo(char *s) { if(info) free(info); info = strdup(s); } inline char* getInfo(char *buf, uint buf_len) { return get_visual_name(buf, buf_len, true); } - void incrVisitedWebSite(char *hostname); + void incrVisitedWebSite(char *hostname) {}; + virtual u_int32_t getActiveHTTPHosts() { return(0); }; inline u_int32_t getNumOutgoingFlows() { return(num_active_flows_as_client); } inline u_int32_t getNumIncomingFlows() { return(num_active_flows_as_server); } inline u_int32_t getNumActiveFlows() { return(getNumOutgoingFlows()+getNumIncomingFlows()); } @@ -220,8 +244,8 @@ class Host : public GenericHost, public Checkpointable { inline void setSSDPLocation(char *url) { if(url) { - if(ssdpLocation_shadow) free(ssdpLocation_shadow); - ssdpLocation_shadow = ssdpLocation; + if(ssdpLocation_shadow) free(ssdpLocation_shadow); + ssdpLocation_shadow = ssdpLocation; ssdpLocation = strdup(url); } } diff --git a/include/LocalHost.h b/include/LocalHost.h new file mode 100644 index 0000000000..d71fbc7daa --- /dev/null +++ b/include/LocalHost.h @@ -0,0 +1,98 @@ +/* + * + * (C) 2013-18 - 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 _LOCAL_HOST_H_ +#define _LOCAL_HOST_H_ + +#include "ntop_includes.h" + +class LocalHost : public Host { + private: + int16_t local_network_id; + NetworkStats *networkStats; + DnsStats *dns; + HTTPstats *http; + ICMPstats *icmp; + FrequentStringItems *top_sites; + char *old_sites; + char os[16]; + time_t nextSitesUpdate; + bool systemHost; + bool dhcpUpdated; + bool trigger_host_alerts; + bool drop_all_host_traffic, dump_host_traffic; + u_int32_t num_alerts_detected; + u_int32_t attacker_max_num_flows_per_sec, victim_max_num_flows_per_sec; + u_int32_t attacker_max_num_syn_per_sec, victim_max_num_syn_per_sec; + AlertCounter *syn_flood_attacker_alert, *syn_flood_victim_alert; + AlertCounter *flow_flood_attacker_alert, *flow_flood_victim_alert; + + void initialize(); + virtual bool readDHCPCache(); + public: + LocalHost(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId, IpAddress *_ip); + LocalHost(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId); + virtual ~LocalHost(); + + virtual int16_t get_local_network_id() { return(local_network_id); }; + virtual bool isLocalHost() { return(true); }; + virtual bool isSystemHost() { return(systemHost); }; + + virtual void serialize2redis(); + bool deserialize(char *json_str, char *key); + + virtual json_object* getJSONObject(); + virtual NetworkStats* getNetworkStats(int16_t networkId){ return(iface->getNetworkStats(networkId)); }; + virtual u_int32_t getActiveHTTPHosts() { return(http ? http->get_num_virtual_hosts() : 0); }; + virtual HTTPstats* getHTTPstats() { return(http); }; + virtual char* get_os() { return(os); }; + + virtual bool dropAllTraffic() { return(drop_all_host_traffic); }; + virtual bool dumpHostTraffic() { return(dump_host_traffic); }; + + bool hasAnomalies(); + void luaAnomalies(lua_State* vm); + virtual void loadAlertsCounter(); + + virtual void incNumFlows(bool as_client); + virtual void refreshHostAlertPrefs(); + void incrVisitedWebSite(char *hostname); + virtual bool triggerAlerts() { return(trigger_host_alerts); }; + virtual u_int32_t getNumAlerts(bool from_alertsmanager = false); + virtual void setNumAlerts(u_int32_t num) { num_alerts_detected = num; }; + virtual void setDumpTrafficPolicy(bool new_policy); + virtual void setOS(char *_os); + virtual void updateSynFlags(time_t when, u_int8_t flags, Flow *f, bool syn_sent); + virtual void updateStats(struct timeval *tv); + virtual void updateHostTrafficPolicy(char *key); + virtual void updateHTTPHostRequest(char *virtual_host_name, u_int32_t num_req, u_int32_t bytes_sent, u_int32_t bytes_rcvd); + + virtual void incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer); + virtual void incNumDNSQueriesSent(u_int16_t query_type) { if(dns) dns->incNumDNSQueriesSent(query_type); }; + virtual void incNumDNSQueriesRcvd(u_int16_t query_type) { if(dns) dns->incNumDNSQueriesRcvd(query_type); }; + virtual void incNumDNSResponsesSent(u_int32_t ret_code) { if(dns) dns->incNumDNSResponsesSent(ret_code); }; + virtual void incNumDNSResponsesRcvd(u_int32_t ret_code) { if(dns) dns->incNumDNSResponsesRcvd(ret_code); }; + + virtual void lua(lua_State* vm, AddressTree * ptree, bool host_details, + bool verbose, bool returnHost, bool asListElement); +}; + +#endif /* _LOCAL_HOST_H_ */ diff --git a/include/RemoteHost.h b/include/RemoteHost.h new file mode 100644 index 0000000000..e578d4f68e --- /dev/null +++ b/include/RemoteHost.h @@ -0,0 +1,48 @@ +/* + * + * (C) 2013-18 - 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 _REMOTE_HOST_H_ +#define _REMOTE_HOST_H_ + +#include "ntop_includes.h" + +class RemoteHost : public Host { + private: + bool blacklisted_host; + char trafficCategory[12]; + + void initialize(); + + public: + RemoteHost(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId, IpAddress *_ip); + RemoteHost(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId); + virtual ~RemoteHost(); + + virtual char* get_traffic_category() { return(trafficCategory); }; + virtual int16_t get_local_network_id() { return(-1); }; + virtual bool isBlacklisted() { return(blacklisted_host); }; + virtual bool isLocalHost() { return(false); }; + virtual bool isSystemHost() { return(false); }; + + virtual void refreshHTTPBL(); +}; + +#endif /* _REMOTE_HOST_H_ */ diff --git a/include/ntop_includes.h b/include/ntop_includes.h index e2c104b0ae..aba8621c3a 100644 --- a/include/ntop_includes.h +++ b/include/ntop_includes.h @@ -237,7 +237,6 @@ using namespace std; #include "PF_RINGInterface.h" #endif #include "AlertCounter.h" -#include "GenericHost.h" #include "GenericHash.h" #include "VirtualHost.h" #include "VirtualHostHash.h" @@ -287,12 +286,13 @@ using namespace std; #endif #include "Geolocation.h" -#include "GenericHost.h" #include "Vlan.h" #include "AutonomousSystem.h" #include "Country.h" #include "Mac.h" #include "Host.h" +#include "LocalHost.h" +#include "RemoteHost.h" #include "Flow.h" #include "FlowHash.h" #include "MacHash.h" diff --git a/src/GenericHost.cpp b/src/GenericHost.cpp deleted file mode 100644 index fb46a68bc7..0000000000 --- a/src/GenericHost.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * (C) 2013-18 - 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" - -/* *************************************** */ - -GenericHost::GenericHost(NetworkInterface *_iface) : GenericHashEntry(_iface) { - if(_iface == NULL) - ntop->getTrace()->traceEvent(TRACE_WARNING, "NULL interface"); - - ndpiStats = new nDPIStats(); - - systemHost = false, localHost = false; - last_bytes = 0, last_bytes_thpt = bytes_thpt = 0, bytes_thpt_trend = trend_unknown; - bytes_thpt_diff = 0, last_epoch_update = 0; - total_activity_time = 0; - last_packets = 0, last_pkts_thpt = pkts_thpt = 0, pkts_thpt_trend = trend_unknown; - last_update_time.tv_sec = 0, last_update_time.tv_usec = 0, vlan_id = 0; - low_goodput_client_flows = low_goodput_server_flows = 0; - // readStats(); - Commented as if put here it's too early and the key is not yet set - goodput_bytes_thpt = last_goodput_bytes_thpt = bytes_goodput_thpt_diff = 0; - bytes_goodput_thpt_trend = trend_unknown; - -} - -/* *************************************** */ - -void GenericHost::incStats(u_int32_t when, u_int8_t l4_proto, u_int ndpi_proto, - u_int64_t sent_packets, u_int64_t sent_bytes, u_int64_t sent_goodput_bytes, - u_int64_t rcvd_packets, u_int64_t rcvd_bytes, u_int64_t rcvd_goodput_bytes) { - if(sent_packets || rcvd_packets) { - sent.incStats(sent_packets, sent_bytes), rcvd.incStats(rcvd_packets, rcvd_bytes); - - if(ndpiStats) { - ndpiStats->incStats(when, ndpi_proto, sent_packets, sent_bytes, rcvd_packets, rcvd_bytes), - ndpiStats->incCategoryStats(when, - getInterface()->get_ndpi_proto_category(ndpi_proto), - sent_bytes, rcvd_bytes); - - } - - if(when && when - last_epoch_update >= ntop->getPrefs()->get_housekeeping_frequency()) - total_activity_time += ntop->getPrefs()->get_housekeeping_frequency(), last_epoch_update = when; - - updateSeen(); - } -} diff --git a/src/Host.cpp b/src/Host.cpp index 0e2ae071c4..84fd7fa936 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -23,13 +23,7 @@ /* *************************************** */ -Host::Host(NetworkInterface *_iface) : GenericHost(_iface) { - initialize(NULL, 0, false); -} - -/* *************************************** */ - -Host::Host(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId) : GenericHost(_iface) { +Host::Host(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId) : GenericHashEntry(_iface) { ip.set(ipAddress); initialize(NULL, _vlanId, true); } @@ -37,7 +31,7 @@ Host::Host(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId) : Gener /* *************************************** */ Host::Host(NetworkInterface *_iface, Mac *_mac, - u_int16_t _vlanId, IpAddress *_ip) : GenericHost(_iface) { + u_int16_t _vlanId, IpAddress *_ip) : GenericHashEntry(_iface) { ip.set(_ip); #ifdef BROADCAST_DEBUG @@ -50,20 +44,12 @@ Host::Host(NetworkInterface *_iface, Mac *_mac, /* *************************************** */ -Host::Host(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId) : GenericHost(_iface) { - initialize(_mac, _vlanId, true); -} - -/* *************************************** */ - Host::~Host() { if(num_uses > 0) ntop->getTrace()->traceEvent(TRACE_WARNING, "Internal error: num_uses=%u", num_uses); // ntop->getTrace()->traceEvent(TRACE_NORMAL, "Deleting %s (%s)", k, localHost ? "local": "remote"); - serialize2redis(); /* possibly dumps counters and data to redis */ - if(mac) mac->decUses(); if(as) as->decUses(); if(country) country->decUses(); @@ -82,20 +68,17 @@ Host::~Host() { } #endif - if(icmp) delete icmp; - if(dns) delete dns; - if(http) delete http; + if(symbolic_name) free(symbolic_name); if(ssdpLocation_shadow) free(ssdpLocation_shadow); if(ssdpLocation) free(ssdpLocation); - if(syn_flood_attacker_alert) delete syn_flood_attacker_alert; - if(syn_flood_victim_alert) delete syn_flood_victim_alert; - if(flow_flood_attacker_alert) delete flow_flood_attacker_alert; - if(flow_flood_victim_alert) delete flow_flood_victim_alert; if(m) delete m; - if(top_sites) delete top_sites; - if(old_sites) free(old_sites); if(info) free(info); + + /* Pool counters are updated both in and outside the datapath. + So decPoolNumHosts must stay in the destructor to preserve counters + consistency (no thread outside the datapath will change the last pool id) */ + iface->decPoolNumHosts(get_host_pool(), true /* Host is deleted inline */); } /* *************************************** */ @@ -105,7 +88,7 @@ void Host::set_host_label(char *label_name, bool ignoreIfPresent) { char buf[64], buf1[64], *host = ip.print(buf, sizeof(buf)); host_label_set = true; - + if(ignoreIfPresent && (!ntop->getRedis()->hashGet((char*)HOST_LABEL_NAMES, host, buf1, (u_int)sizeof(buf1)) /* Found into redis */ && (buf1[0] != '\0') /* Not empty */ )) @@ -118,8 +101,17 @@ void Host::set_host_label(char *label_name, bool ignoreIfPresent) { /* *************************************** */ void Host::initialize(Mac *_mac, u_int16_t _vlanId, bool init_all) { - char key[64], redis_key[128], *k; - char buf[64], host[96]; + ndpiStats = new nDPIStats(); + + last_bytes = 0, last_bytes_thpt = bytes_thpt = 0, bytes_thpt_trend = trend_unknown; + bytes_thpt_diff = 0, last_epoch_update = 0; + total_activity_time = 0; + last_packets = 0, last_pkts_thpt = pkts_thpt = 0, pkts_thpt_trend = trend_unknown; + last_update_time.tv_sec = 0, last_update_time.tv_usec = 0, vlan_id = 0; + low_goodput_client_flows = low_goodput_server_flows = 0; + // readStats(); - Commented as if put here it's too early and the key is not yet set + goodput_bytes_thpt = last_goodput_bytes_thpt = bytes_goodput_thpt_diff = 0; + bytes_goodput_thpt_trend = trend_unknown; #ifdef NTOPNG_PRO has_blocking_quota = has_blocking_shaper = false; @@ -133,27 +125,15 @@ void Host::initialize(Mac *_mac, u_int16_t _vlanId, bool init_all) { if((vlan = iface->getVlan(_vlanId, true)) != NULL) vlan->incUses(); - num_alerts_detected = 0; - drop_all_host_traffic = false, dump_host_traffic = false, dhcpUpdated = false, - num_resolve_attempts = 0, ssdpLocation = NULL, ssdpLocation_shadow = NULL; - attacker_max_num_syn_per_sec = ntop->getPrefs()->get_attacker_max_num_syn_per_sec(); - victim_max_num_syn_per_sec = ntop->getPrefs()->get_victim_max_num_syn_per_sec(); - attacker_max_num_flows_per_sec = ntop->getPrefs()->get_attacker_max_num_flows_per_sec(); - victim_max_num_flows_per_sec = ntop->getPrefs()->get_victim_max_num_flows_per_sec(); + num_resolve_attempts = 0, ssdpLocation = NULL, ssdpLocation_shadow = NULL; + good_low_flow_detected = false; - networkStats = NULL, local_network_id = -1, nextResolveAttempt = 0, info = NULL; - syn_flood_attacker_alert = new AlertCounter(attacker_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); - syn_flood_victim_alert = new AlertCounter(victim_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); - flow_flood_attacker_alert = new AlertCounter(attacker_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); - flow_flood_victim_alert = new AlertCounter(victim_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + nextResolveAttempt = 0, info = NULL; host_label_set = false; - os[0] = '\0', trafficCategory[0] = '\0', blacklisted_host = false, blacklisted_alarm_emitted = false; num_uses = 0, symbolic_name = NULL, vlan_id = _vlanId % MAX_NUM_VLAN, total_num_flows_as_client = total_num_flows_as_server = 0, num_active_flows_as_client = num_active_flows_as_server = 0; - trigger_host_alerts = false; first_seen = last_seen = iface->getTimeLastPktRcvd(); - nextSitesUpdate = 0; checkpoint_set = false; checkpoint_sent_bytes = checkpoint_rcvd_bytes = 0; if((m = new(std::nothrow) Mutex()) == NULL) @@ -162,77 +142,8 @@ void Host::initialize(Mac *_mac, u_int16_t _vlanId, bool init_all) { memset(&tcpPacketStats, 0, sizeof(tcpPacketStats)); asn = 0, asname = NULL; as = NULL, country = NULL; - k = ip.print(key, sizeof(key)); - snprintf(redis_key, sizeof(redis_key), HOST_SERIALIZED_KEY, iface->get_id(), k, vlan_id); - dns = NULL, http = NULL, top_sites = NULL, old_sites = NULL, - icmp = NULL; if(init_all) { - char *strIP = ip.print(buf, sizeof(buf)); - - snprintf(host, sizeof(host), "%s@%u", strIP, vlan_id); - - updateLocal(); - updateHostTrafficPolicy(host); - - if(isLocalHost()) { - /* initialize this in any case to support runtime 'are_top_talkers_enabled' changes */ - top_sites = new FrequentStringItems(HOST_SITES_TOP_NUMBER); - old_sites = strdup("{}"); - - readDHCPCache(); - } - - // ntop->getTrace()->traceEvent(TRACE_NORMAL, "Loading %s (%s)", k, localHost ? "local": "remote"); - - if(isLocalHost()) { - dns = new DnsStats(); - http = new HTTPstats(iface->get_hosts_hash()); - } - - if((localHost || systemHost) - && ntop->getPrefs()->is_idle_local_host_cache_enabled()) { - char *json = NULL; - - if((json = (char*)malloc(HOST_MAX_SERIALIZED_LEN * sizeof(char))) == NULL) - ntop->getTrace()->traceEvent(TRACE_ERROR, - "Unable to allocate memory to deserialize %s", redis_key); - else if(!ntop->getRedis()->get(redis_key, json, HOST_MAX_SERIALIZED_LEN)){ - bool shadow_localHost = localHost, shadow_systemHost = systemHost; /* Just in case */ - /* Found saved copy of the host so let's start from the previous state */ - // ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s => %s", redis_key, json); - ntop->getTrace()->traceEvent(TRACE_INFO, "Deserializing %s", redis_key); - - deserialize(json, redis_key); - localHost = shadow_localHost, systemHost = shadow_systemHost; - } - - if(json) free(json); - } - - if(localHost || systemHost - || ntop->getPrefs()->is_dns_resolution_enabled_for_all_hosts()) { - char rsp[256]; - - if(ntop->getRedis()->getAddress(host, rsp, sizeof(rsp), true) == 0) - setName(rsp); - // else ntop->getRedis()->pushHostToResolve(host, false, localHost); - } - - if(!(localHost || systemHost)) { - blacklisted_host = ntop->isBlacklistedIP(&ip); - - if((!blacklisted_host) && ntop->getPrefs()->is_httpbl_enabled() && ip.isIPv4()) { - // http:bl only works for IPv4 addresses - if(ntop->getRedis()->getAddressTrafficFiltering(host, iface, trafficCategory, - sizeof(trafficCategory), true) == 0) { - if(strcmp(trafficCategory, NULL_BL)) { - blacklisted_host = true; - } - } - } - } - if((as = iface->getAS(&ip, true)) != NULL) { as->incUses(); asn = as->get_asn(); @@ -246,41 +157,12 @@ void Host::initialize(Mac *_mac, u_int16_t _vlanId, bool init_all) { country->incUses(); } - iface->incNumHosts(isLocalHost()); - - refreshHostAlertPrefs(); - updateHostPool(true /* inline with packet processing */, true /* first inc */); reloadHideFromTop(); } /* *************************************** */ -bool Host::readDHCPCache() { - Mac *m = mac; /* Cache it as it can be replaced with secondary_mac */ - - if(localHost && m && (!dhcpUpdated)) { - /* Check DHCP cache */ - char client_mac[24], buf[64], key[64]; - - dhcpUpdated = true; - - if(!m->isNull()) { - Utils::formatMac(m->get_mac(), client_mac, sizeof(client_mac)); - - snprintf(key, sizeof(key), DHCP_CACHE, iface->get_id()); - if(ntop->getRedis()->hashGet(key, client_mac, buf, sizeof(buf)) == 0) { - setName(buf); - return true; - } - } - } - - return false; -} - -/* *************************************** */ - char* Host::get_hostkey(char *buf, u_int buf_len, bool force_vlan) { char ipbuf[64]; char *key = ip.print(ipbuf, sizeof(ipbuf)); @@ -296,35 +178,6 @@ char* Host::get_hostkey(char *buf, u_int buf_len, bool force_vlan) { /* *************************************** */ -void Host::updateHostTrafficPolicy(char *key) { - if(localHost || systemHost) { - char buf[64], *host; - - if(key) - host = key; - else - host = get_hostkey(buf, sizeof(buf)); - - if(iface->isPacketInterface()) { - if((ntop->getRedis()->hashGet((char*)DROP_HOST_TRAFFIC, host, buf, sizeof(buf)) == -1) - || (strcmp(buf, "true") != 0)) - drop_all_host_traffic = false; - else - drop_all_host_traffic = true; - - } - - if((ntop->getRedis()->hashGet((char*)DUMP_HOST_TRAFFIC, - host, buf, sizeof(buf)) == -1) - || (strcmp(buf, "true") != 0)) - dump_host_traffic = false; - else - dump_host_traffic = true; - } -} - -/* *************************************** */ - void Host::updateHostPool(bool isInlineCall, bool firstUpdate) { if(!iface) return; @@ -403,26 +256,6 @@ void Host::updateHostPool(bool isInlineCall, bool firstUpdate) { /* *************************************** */ -void Host::updateLocal() { - localHost = ip.isLocalHost(&local_network_id); - - if(local_network_id >= 0) - networkStats = getNetworkStats(local_network_id); - - systemHost = localHost ? ip.isLocalInterfaceAddress() : false; - - if(0) { - char buf[64]; - - ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s is %s %s [%p]", - ip.print(buf, sizeof(buf)), - localHost ? "local" : "remote", - systemHost ? "systemHost" : "", this); - } -} - -/* *************************************** */ - void Host::set_mac(Mac *_mac) { if((mac != _mac) && (_mac != NULL)) { if(mac) mac->decUses(); @@ -462,34 +295,35 @@ void Host::set_mac(char *m) { void Host::lua(lua_State* vm, AddressTree *ptree, bool host_details, bool verbose, bool returnHost, bool asListElement) { - char buf[64], buf_id[64], ip_buf[64], *ipaddr = NULL, *local_net, *host_id = buf_id; - bool mask_host = Utils::maskHost(localHost); + char buf[64], buf_id[64], *host_id = buf_id; + char ip_buf[64], *ipaddr = NULL; + bool mask_host = Utils::maskHost(isLocalHost()); Mac *m = mac; /* Cache macs as they can be swapped/updated */ - + if((ptree && (!match(ptree))) || mask_host) return; #if 0 if(1) { char buf[64]; - + ntop->getTrace()->traceEvent(TRACE_NORMAL, "********* %s is %s %s [%p]", ip.print(buf, sizeof(buf)), - localHost ? "local" : "remote", - systemHost ? "systemHost" : "", this); + isLocalHost() ? "local" : "remote", + isSystemHost() ? "systemHost" : "", this); } #endif - + lua_newtable(vm); - lua_push_str_table_entry(vm, "ip", (ipaddr = ip.printMask(ip_buf, sizeof(ip_buf), localHost))); + + lua_push_str_table_entry(vm, "ip", (ipaddr = printMask(ip_buf, sizeof(ip_buf)))); lua_push_int_table_entry(vm, "ipkey", ip.key()); + lua_push_bool_table_entry(vm, "localhost", isLocalHost()); lua_push_str_table_entry(vm, "mac", Utils::formatMac(m ? m->get_mac() : NULL, buf, sizeof(buf))); - lua_push_int_table_entry(vm, "devtype", (localHost && m) ? m->getDeviceType() : device_unknown); + lua_push_int_table_entry(vm, "devtype", m ? m->getDeviceType() : device_unknown); lua_push_int_table_entry(vm, "operatingSystem", m ? m->getOperatingSystem() : os_unknown); - lua_push_bool_table_entry(vm, "localhost", localHost); - lua_push_int_table_entry(vm, "bytes.sent", sent.getNumBytes()); lua_push_int_table_entry(vm, "bytes.rcvd", rcvd.getNumBytes()); @@ -499,34 +333,30 @@ void Host::lua(lua_State* vm, AddressTree *ptree, lua_push_int_table_entry(vm, "num_alerts", triggerAlerts() ? getNumAlerts() : 0); lua_push_str_table_entry(vm, "name", get_visual_name(buf, sizeof(buf))); - lua_push_int32_table_entry(vm, "local_network_id", local_network_id); - local_net = ntop->getLocalNetworkName(local_network_id); - if(local_net == NULL) - lua_push_nil_table_entry(vm, "local_network_name"); - else - lua_push_str_table_entry(vm, "local_network_name", local_net); - - lua_push_bool_table_entry(vm, "systemhost", systemHost); - lua_push_bool_table_entry(vm, "is_blacklisted", blacklisted_host); + lua_push_bool_table_entry(vm, "systemhost", isSystemHost()); + lua_push_bool_table_entry(vm, "is_blacklisted", isBlacklisted()); lua_push_bool_table_entry(vm, "is_broadcast", ip.isBroadcastAddress()); lua_push_bool_table_entry(vm, "is_multicast", ip.isMulticastAddress()); lua_push_bool_table_entry(vm, "childSafe", isChildSafe()); lua_push_int_table_entry(vm, "asn", asn); lua_push_int_table_entry(vm, "host_pool_id", host_pool_id); lua_push_str_table_entry(vm, "asname", asname ? asname : (char*)""); - lua_push_str_table_entry(vm, "os", os); + lua_push_str_table_entry(vm, "os", get_os()); if(mac && mac->isDhcpHost()) lua_push_bool_table_entry(vm, "dhcpHost", true); lua_push_int_table_entry(vm, "active_flows.as_client", num_active_flows_as_client); lua_push_int_table_entry(vm, "active_flows.as_server", num_active_flows_as_server); - lua_push_int_table_entry(vm, "active_http_hosts", http ? http->get_num_virtual_hosts() : 0); #ifdef NTOPNG_PRO lua_push_bool_table_entry(vm, "has_blocking_quota", has_blocking_quota); lua_push_bool_table_entry(vm, "has_blocking_shaper", has_blocking_shaper); #endif + lua_push_bool_table_entry(vm, "drop_all_host_traffic", dropAllTraffic()); + lua_push_bool_table_entry(vm, "dump_host_traffic", dumpHostTraffic()); + lua_push_int_table_entry(vm, "active_http_hosts", getActiveHTTPHosts()); + if(host_details) { /* This has been disabled as in case of an attack, most hosts do not have a name and we will waste @@ -538,9 +368,6 @@ void Host::lua(lua_State* vm, AddressTree *ptree, ntop->getRedis()->pushHostToResolve(ipaddr, false, true /* Fake to resolve it ASAP */); } - if(icmp) - icmp->lua(ip.isIPv4(), vm); - if(ssdpLocation) lua_push_str_table_entry(vm, "ssdp", ssdpLocation); } @@ -578,9 +405,9 @@ void Host::lua(lua_State* vm, AddressTree *ptree, if(host_details) { char *continent = NULL, *country_name = NULL, *city = NULL; float latitude = 0, longitude = 0; - + ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city, &latitude, &longitude); - + if(info) lua_push_str_table_entry(vm, "info", getInfo(buf, sizeof(buf))); lua_push_str_table_entry(vm, "continent", continent ? continent : (char*)""); @@ -608,8 +435,6 @@ void Host::lua(lua_State* vm, AddressTree *ptree, lua_push_int_table_entry(vm, "other_ip.packets.rcvd", other_ip_rcvd.getNumPkts()); lua_push_int_table_entry(vm, "other_ip.bytes.rcvd", other_ip_rcvd.getNumBytes()); - lua_push_bool_table_entry(vm, "drop_all_host_traffic", drop_all_host_traffic); - /* Host ingress/egress drops */ lua_push_int_table_entry(vm, "bridge.ingress_drops.bytes", ingress_drops.getNumBytes()); lua_push_int_table_entry(vm, "bridge.ingress_drops.packets", ingress_drops.getNumPkts()); @@ -619,31 +444,9 @@ void Host::lua(lua_State* vm, AddressTree *ptree, lua_push_int_table_entry(vm, "low_goodput_flows.as_client", low_goodput_client_flows); lua_push_int_table_entry(vm, "low_goodput_flows.as_server", low_goodput_server_flows); - if((!mask_host) && top_sites && ntop->getPrefs()->are_top_talkers_enabled()) { - char *cur_sites = top_sites->json(); - lua_push_str_table_entry(vm, "sites", cur_sites ? cur_sites : (char*)"{}"); - lua_push_str_table_entry(vm, "sites.old", old_sites ? old_sites : (char*)"{}"); - if(cur_sites) free(cur_sites); - } - if(city) free(city); } - if(localHost) { - /* Criteria */ - lua_newtable(vm); - - lua_push_int_table_entry(vm, "upload", getNumBytesSent()); - lua_push_int_table_entry(vm, "download", getNumBytesRcvd()); - lua_push_int_table_entry(vm, "unknown", get_ndpi_stats()->getProtoBytes(NDPI_PROTOCOL_UNKNOWN)); - lua_push_int_table_entry(vm, "incomingflows", getNumIncomingFlows()); - lua_push_int_table_entry(vm, "outgoingflows", getNumOutgoingFlows()); - - lua_pushstring(vm, "criteria"); - lua_insert(vm, -2); - lua_settable(vm, -3); - } - lua_push_int_table_entry(vm, "seen.first", first_seen); lua_push_int_table_entry(vm, "seen.last", last_seen); lua_push_int_table_entry(vm, "duration", get_duration()); @@ -653,7 +456,7 @@ void Host::lua(lua_State* vm, AddressTree *ptree, if(ntop->getPrefs()->is_httpbl_enabled()) lua_push_str_table_entry(vm, "httpbl", get_httpbl()); - lua_push_bool_table_entry(vm, "dump_host_traffic", dump_host_traffic); + if(verbose) { char *rsp = serialize(); @@ -665,9 +468,7 @@ void Host::lua(lua_State* vm, AddressTree *ptree, sent_stats.lua(vm, "pktStats.sent"); recv_stats.lua(vm, "pktStats.recv"); - if(dns) dns->lua(vm); - if(http) http->lua(vm); - if(hasAnomalies()) luaAnomalies(vm); + } if(!returnHost) @@ -698,56 +499,6 @@ void Host::setName(char *name) { if(m) m->unlock(__FILE__, __LINE__); } -/* *************************************** */ - -bool Host::hasAnomalies() { - time_t now = time(0); - - return syn_flood_victim_alert->isAboveThreshold(now) - || syn_flood_attacker_alert->isAboveThreshold(now) - || flow_flood_victim_alert->isAboveThreshold(now) - || flow_flood_attacker_alert->isAboveThreshold(now); -} - -/* *************************************** */ - -void Host::luaAnomalies(lua_State* vm) { - if(!vm) - return; - - if(hasAnomalies()) { - time_t now = time(0); - lua_newtable(vm); - - if(syn_flood_victim_alert->isAboveThreshold(now)) - syn_flood_victim_alert->lua(vm, "syn_flood_victim"); - if(syn_flood_attacker_alert->isAboveThreshold(now)) - syn_flood_attacker_alert->lua(vm, "syn_flood_attacker"); - if(flow_flood_victim_alert->isAboveThreshold(now)) - flow_flood_victim_alert->lua(vm, "flows_flood_victim"); - if(flow_flood_attacker_alert->isAboveThreshold(now)) - flow_flood_attacker_alert->lua(vm, "flows_flood_attacker"); - - lua_pushstring(vm, "anomalies"); - lua_insert(vm, -2); - lua_settable(vm, -3); - } -} - -/* ***************************************** */ - -void Host::refreshHTTPBL() { - if(ip.isIPv4() - && (!localHost) - && (trafficCategory[0] == '\0') - && ntop->get_httpbl()) { - char buf[128] = { 0 }; - char* ip_addr = ip.print(buf, sizeof(buf)); - - ntop->get_httpbl()->findCategory(ip_addr, trafficCategory, sizeof(trafficCategory), false); - } -} - /* ***************************************** */ char* Host::get_name(char *buf, u_int buf_len, bool force_resolution_if_not_found) { @@ -791,11 +542,11 @@ bool Host::idle() { break; case location_local_only: - if(localHost || systemHost) return(false); + if(isLocalHost() || isSystemHost()) return(false); break; case location_remote_only: - if(!(localHost||systemHost)) return(false); + if(!(isLocalHost() || isSystemHost())) return(false); break; case location_all: @@ -803,7 +554,7 @@ bool Host::idle() { break; } - return(isIdle(ntop->getPrefs()->get_host_max_idle(localHost))); + return(isIdle(ntop->getPrefs()->get_host_max_idle(isLocalHost()))); }; /* *************************************** */ @@ -813,9 +564,20 @@ void Host::incStats(u_int32_t when, u_int8_t l4_proto, u_int ndpi_proto, u_int64_t rcvd_packets, u_int64_t rcvd_bytes, u_int64_t rcvd_goodput_bytes) { if(sent_packets || rcvd_packets) { - ((GenericHost*)this)->incStats(when, l4_proto, ndpi_proto, - sent_packets, sent_bytes, sent_goodput_bytes, - rcvd_packets, rcvd_bytes, rcvd_goodput_bytes); + sent.incStats(sent_packets, sent_bytes), rcvd.incStats(rcvd_packets, rcvd_bytes); + + if(ndpiStats) { + ndpiStats->incStats(when, ndpi_proto, sent_packets, sent_bytes, rcvd_packets, rcvd_bytes), + ndpiStats->incCategoryStats(when, + getInterface()->get_ndpi_proto_category(ndpi_proto), + sent_bytes, rcvd_bytes); + + } + + if(when && when - last_epoch_update >= ntop->getPrefs()->get_housekeeping_frequency()) + total_activity_time += ntop->getPrefs()->get_housekeeping_frequency(), last_epoch_update = when; + + updateSeen(); /* Paket stats sent_stats and rcvd_stats are incremented in Flow::incStats */ @@ -858,26 +620,6 @@ char* Host::serialize() { return(rsp); } - -/* *************************************** */ - -void Host::serialize2redis() { - if((localHost || systemHost) - && (ntop->getPrefs()->is_idle_local_host_cache_enabled() - || ntop->getPrefs()->is_active_local_host_cache_enabled()) - && (!ip.isEmpty())) { - char *json = serialize(); - char host_key[128], key[128]; - char *k = ip.print(host_key, sizeof(host_key)); - - snprintf(key, sizeof(key), HOST_SERIALIZED_KEY, iface->get_id(), k, vlan_id); - ntop->getRedis()->set(key, json, ntop->getPrefs()->get_local_host_cache_duration()); - ntop->getTrace()->traceEvent(TRACE_INFO, "Dumping serialization %s", k); - //ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s => %s", k, json); - free(json); - } -} - /* *************************************** */ json_object* Host::getJSONObject() { @@ -886,7 +628,7 @@ json_object* Host::getJSONObject() { Mac *m = mac; char *continent, *country_name, *city = NULL; float latitude, longitude; - + if((my_object = json_object_new_object()) == NULL) return(NULL); json_object_object_add(my_object, "mac_address", json_object_new_string(Utils::formatMac(m ? m->get_mac() : NULL, buf, sizeof(buf)))); @@ -896,15 +638,16 @@ json_object* Host::getJSONObject() { json_object_object_add(my_object, "asn", json_object_new_int(asn)); if(symbolic_name) json_object_object_add(my_object, "symbolic_name", json_object_new_string(symbolic_name)); if(asname) json_object_object_add(my_object, "asname", json_object_new_string(asname ? asname : (char*)"")); - if(strlen(os)) json_object_object_add(my_object, "os", json_object_new_string(os)); - if(trafficCategory[0] != '\0') json_object_object_add(my_object, "trafficCategory", json_object_new_string(trafficCategory)); + if(strlen(get_os())) json_object_object_add(my_object, "os", json_object_new_string(get_os())); + if(get_traffic_category()[0] != '\0') + json_object_object_add(my_object, "trafficCategory", json_object_new_string(get_traffic_category())); if(vlan_id != 0) json_object_object_add(my_object, "vlan_id", json_object_new_int(vlan_id)); json_object_object_add(my_object, "ip", ip.getJSONObject()); ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city, &latitude, &longitude); - json_object_object_add(my_object, "localHost", json_object_new_boolean(localHost)); - json_object_object_add(my_object, "systemHost", json_object_new_boolean(systemHost)); - json_object_object_add(my_object, "is_blacklisted", json_object_new_boolean(blacklisted_host)); + json_object_object_add(my_object, "localHost", json_object_new_boolean(isLocalHost())); + json_object_object_add(my_object, "systemHost", json_object_new_boolean(isSystemHost())); + json_object_object_add(my_object, "is_blacklisted", json_object_new_boolean(isBlacklisted())); json_object_object_add(my_object, "tcp_sent", tcp_sent.getJSONObject()); json_object_object_add(my_object, "tcp_rcvd", tcp_rcvd.getJSONObject()); json_object_object_add(my_object, "udp_sent", udp_sent.getJSONObject()); @@ -952,17 +695,15 @@ json_object* Host::getJSONObject() { /* The value below is handled by reading dumps on disk as otherwise the string will be too long */ //json_object_object_add(my_object, "activityStats", activityStats.getJSONObject()); - if(dns) json_object_object_add(my_object, "dns", dns->getJSONObject()); - if(http) json_object_object_add(my_object, "http", http->getJSONObject()); if(city) free(city); - + return(my_object); } /* *************************************** */ char* Host::get_visual_name(char *buf, u_int buf_len, bool from_info) { - bool mask_host = Utils::maskHost(localHost); + bool mask_host = Utils::maskHost(isLocalHost()); char buf2[64]; char ipbuf[64]; char *sym_name; @@ -972,9 +713,9 @@ char* Host::get_visual_name(char *buf, u_int buf_len, bool from_info) { if(sym_name && sym_name[0]) { if(ip.isIPv6() && strcmp(ip.print(ipbuf, sizeof(ipbuf)), sym_name)) { - snprintf(buf, buf_len, "%s [IPv6]", sym_name); + snprintf(buf, buf_len, "%s [IPv6]", sym_name); } else - strncpy(buf, sym_name, buf_len); + strncpy(buf, sym_name, buf_len); } else buf[0] = '\0'; } else @@ -1020,127 +761,11 @@ bool Host::addIfMatching(lua_State* vm, u_int8_t *_mac) { /* *************************************** */ -bool Host::deserialize(char *json_str, char *key) { - json_object *o, *obj; - enum json_tokener_error jerr = json_tokener_success; - - if((o = json_tokener_parse_verbose(json_str, &jerr)) == NULL) { - ntop->getTrace()->traceEvent(TRACE_WARNING, "JSON Parse error [%s] key: %s: %s", - json_tokener_error_desc(jerr), - key, - json_str); - return(false); - } - - if(! mac) { - u_int8_t mac_buf[6]; - memset(mac_buf, 0, sizeof(mac_buf)); - - if(json_object_object_get_ex(o, "mac_address", &obj)) Utils::parseMac(mac_buf, json_object_get_string(obj)); - - // sticky hosts enabled, we must bring up the mac address - if((mac = iface->getMac(mac_buf, true /* create if not exists*/)) != NULL) - mac->incUses(); - else - ntop->getTrace()->traceEvent(TRACE_WARNING, "Internal error: NULL mac. Are you running out of memory?"); - } - - if(json_object_object_get_ex(o, "seen.first", &obj)) first_seen = json_object_get_int64(obj); - if(json_object_object_get_ex(o, "seen.last", &obj)) last_seen = json_object_get_int64(obj); - - if(json_object_object_get_ex(o, "symbolic_name", &obj)) { if(symbolic_name) free(symbolic_name); symbolic_name = strdup(json_object_get_string(obj)); } - if(json_object_object_get_ex(o, "os", &obj)) { snprintf(os, sizeof(os), "%s", json_object_get_string(obj)); } - if(json_object_object_get_ex(o, "trafficCategory", &obj)){ snprintf(trafficCategory, sizeof(trafficCategory), "%s", json_object_get_string(obj)); } - if(json_object_object_get_ex(o, "localHost", &obj)) localHost = (json_object_get_boolean(obj) ? true : false); - if(json_object_object_get_ex(o, "systemHost", &obj)) systemHost = (json_object_get_boolean(obj) ? true : false); - if(json_object_object_get_ex(o, "tcp_sent", &obj)) tcp_sent.deserialize(obj); - if(json_object_object_get_ex(o, "tcp_rcvd", &obj)) tcp_rcvd.deserialize(obj); - if(json_object_object_get_ex(o, "udp_sent", &obj)) udp_sent.deserialize(obj); - if(json_object_object_get_ex(o, "udp_rcvd", &obj)) udp_rcvd.deserialize(obj); - if(json_object_object_get_ex(o, "icmp_sent", &obj)) icmp_sent.deserialize(obj); - if(json_object_object_get_ex(o, "icmp_rcvd", &obj)) icmp_rcvd.deserialize(obj); - if(json_object_object_get_ex(o, "other_ip_sent", &obj)) other_ip_sent.deserialize(obj); - if(json_object_object_get_ex(o, "other_ip_rcvd", &obj)) other_ip_rcvd.deserialize(obj); - - /* packet stats */ - if(json_object_object_get_ex(o, "pktStats.sent", &obj)) sent_stats.deserialize(obj); - if(json_object_object_get_ex(o, "pktStats.recv", &obj)) recv_stats.deserialize(obj); - - /* TCP packet stats */ - if(json_object_object_get_ex(o, "tcpPacketStats.pktRetr", &obj)) tcpPacketStats.pktRetr = json_object_get_int(obj); - if(json_object_object_get_ex(o, "tcpPacketStats.pktOOO", &obj)) tcpPacketStats.pktOOO = json_object_get_int(obj); - if(json_object_object_get_ex(o, "tcpPacketStats.pktLost", &obj)) tcpPacketStats.pktLost = json_object_get_int(obj); - if(json_object_object_get_ex(o, "tcpPacketStats.pktKeepAlive", &obj)) tcpPacketStats.pktKeepAlive = json_object_get_int(obj); - - if(json_object_object_get_ex(o, "flows.as_client", &obj)) total_num_flows_as_client = json_object_get_int(obj); - if(json_object_object_get_ex(o, "flows.as_server", &obj)) total_num_flows_as_server = json_object_get_int(obj); - if(json_object_object_get_ex(o, "flows.dropped", &obj)) total_num_dropped_flows = json_object_get_int(obj); - - if(json_object_object_get_ex(o, "is_blacklisted", &obj)) blacklisted_host = json_object_get_boolean(obj); - - if(json_object_object_get_ex(o, "sent", &obj)) sent.deserialize(obj); - if(json_object_object_get_ex(o, "rcvd", &obj)) rcvd.deserialize(obj); - last_bytes = sent.getNumBytes() + rcvd.getNumBytes(); - last_packets = sent.getNumPkts() + rcvd.getNumPkts(); - - if(json_object_object_get_ex(o, "total_activity_time", &obj)) total_activity_time = json_object_get_int(obj); - - if(json_object_object_get_ex(o, "dns", &obj)) { - if(dns) dns->deserialize(obj); - } - - if(json_object_object_get_ex(o, "http", &obj)) { - if(http) http->deserialize(obj); - } - - if(ndpiStats) { - delete ndpiStats; - ndpiStats = NULL; - } - - if(json_object_object_get_ex(o, "ndpiStats", &obj)) { - ndpiStats = new nDPIStats(); - ndpiStats->deserialize(iface, obj); - } - - /* We commented the line below to avoid strings too long */ -#if 0 - activityStats.reset(); - if(json_object_object_get_ex(o, "activityStats", &obj)) activityStats.deserialize(obj); -#endif - - if(json_object_object_get_ex(o, "pktStats.sent", &obj)) sent_stats.deserialize(obj); - if(json_object_object_get_ex(o, "pktStats.recv", &obj)) recv_stats.deserialize(obj); - - json_object_put(o); - - return(true); -} - -/* *************************************** */ - -void Host::updateSynFlags(time_t when, u_int8_t flags, Flow *f, bool syn_sent) { - AlertCounter *counter = syn_sent ? syn_flood_attacker_alert : syn_flood_victim_alert; - - if(localHost && triggerAlerts()) - counter->incHits(when); -} - -/* *************************************** */ - void Host::incNumFlows(bool as_client) { - AlertCounter *counter; - - if(as_client) { + if(as_client) total_num_flows_as_client++, num_active_flows_as_client++; - counter = flow_flood_attacker_alert; - } else { + else total_num_flows_as_server++, num_active_flows_as_server++; - counter = flow_flood_victim_alert; - } - - if(localHost && triggerAlerts()) - counter->incHits(time(0)); } /* *************************************** */ @@ -1220,7 +845,7 @@ TrafficShaper* Host::get_shaper(ndpi_protocol ndpiProtocol, bool isIngress) { // Avoid dropping critical protocols if(Utils::isCriticalNetworkProtocol(ndpiProtocol.master_protocol) || - Utils::isCriticalNetworkProtocol(ndpiProtocol.app_protocol)) + Utils::isCriticalNetworkProtocol(ndpiProtocol.app_protocol)) return policer->getShaper(PASS_ALL_SHAPER_ID); #endif @@ -1299,15 +924,15 @@ void Host::get_quota(u_int16_t protocol, u_int64_t *bytes_quota, u_int32_t *secs if(sd) { /* A protocol quota has priority over the category quota */ if(sd->protocol_shapers.enabled) { - bytes = sd->protocol_shapers.bytes_quota; - secs = sd->protocol_shapers.secs_quota; - schedule = sd->protocol_shapers.schedule_bitmap; - category = false; + bytes = sd->protocol_shapers.bytes_quota; + secs = sd->protocol_shapers.secs_quota; + schedule = sd->protocol_shapers.schedule_bitmap; + category = false; } else if(sd->category_shapers.enabled) { - bytes = sd->category_shapers.bytes_quota; - secs = sd->category_shapers.secs_quota; - schedule = sd->category_shapers.schedule_bitmap; - category = true; + bytes = sd->category_shapers.bytes_quota; + secs = sd->category_shapers.secs_quota; + schedule = sd->category_shapers.schedule_bitmap; + category = true; } } } @@ -1438,34 +1063,6 @@ void Host::luaUsedQuotas(lua_State* vm) { void Host::updateStats(struct timeval *tv) { GenericTrafficElement::updateStats(tv); - if(http) http->updateStats(tv); - - if(!localHost) return; - - if(top_sites && ntop->getPrefs()->are_top_talkers_enabled() && (tv->tv_sec >= nextSitesUpdate)) { - if(nextSitesUpdate > 0) { - if(old_sites) - free(old_sites); - old_sites = top_sites->json(); - } - - nextSitesUpdate = tv->tv_sec + HOST_SITES_REFRESH; - } -} - -/* *************************************** */ - -u_int32_t Host::getNumAlerts(bool from_alertsmanager) { - if(!from_alertsmanager) - return(num_alerts_detected); - - num_alerts_detected = iface->getAlertsManager()->getNumHostAlerts(this, true); - - ntop->getTrace()->traceEvent(TRACE_DEBUG, - "Refreshing alerts from alertsmanager [num: %i]", - num_alerts_detected); - - return(num_alerts_detected); } /* *************************************** */ @@ -1476,54 +1073,6 @@ void Host::postHashAdd() { /* *************************************** */ -void Host::loadAlertsCounter() { - char buf[64], counters_key[64]; - char rsp[16]; - char *key = get_hostkey(buf, sizeof(buf), true /* force vlan */); - - if(ntop->getPrefs()->are_alerts_disabled() || !isLocalHost()) { - num_alerts_detected = 0; - return; - } - - snprintf(counters_key, sizeof(counters_key), CONST_HOSTS_ALERT_COUNTERS, iface->get_id()); - - if (ntop->getRedis()->hashGet(counters_key, key, rsp, sizeof(rsp)) == 0) - num_alerts_detected = atoi(rsp); - else - num_alerts_detected = 0; - -#if 0 - printf("%s: num_alerts_detected = %d\n", key, num_alerts_detected); -#endif -} - -/* *************************************** */ - -void Host::updateHTTPHostRequest(char *virtual_host_name, u_int32_t num_req, - u_int32_t bytes_sent, u_int32_t bytes_rcvd) { - if(http) - http->updateHTTPHostRequest(virtual_host_name, num_req, bytes_sent, bytes_rcvd); -} - -/* *************************************** */ - -void Host::setDumpTrafficPolicy(bool new_policy) { - char buf[64], *host; - - if(dump_host_traffic == new_policy) - return; /* Nothing to do */ - else - dump_host_traffic = new_policy; - - host = get_hostkey(buf, sizeof(buf), true); - - ntop->getRedis()->hashSet((char*)DUMP_HOST_TRAFFIC, host, - (char*)(dump_host_traffic ? "true" : "false")); -}; - -/* *************************************** */ - bool Host::serializeCheckpoint(json_object *my_object, DetailsLevel details_level) { json_object_object_add(my_object, "sent", sent.getJSONObject()); json_object_object_add(my_object, "rcvd", rcvd.getJSONObject()); @@ -1573,107 +1122,6 @@ void Host::checkPointHostTalker(lua_State *vm, bool saveCheckpoint) { /* *************************************** */ -void Host::refreshHostAlertPrefs() { - bool alerts_read = false; - - if(!ntop->getPrefs()->are_alerts_disabled() - && (localHost || systemHost) - && (!ip.isEmpty())) { - char *key, ip_buf[48], rsp[64], rkey[128]; - - /* This value always contains vlan information */ - key = get_hostkey(ip_buf, sizeof(ip_buf), true); - - if(key) { - snprintf(rkey, sizeof(rkey), CONST_SUPPRESSED_ALERT_PREFS, getInterface()->get_id()); - if(ntop->getRedis()->hashGet(rkey, key, rsp, sizeof(rsp)) == 0) - trigger_host_alerts = ((strcmp(rsp, "false") == 0) ? 0 : 1); - else - trigger_host_alerts = true; - - alerts_read = true; - - if(trigger_host_alerts) { - /* Defaults */ - int flow_attacker_pref = ntop->getPrefs()->get_attacker_max_num_flows_per_sec(); - int flow_victim_pref = ntop->getPrefs()->get_victim_max_num_flows_per_sec(); - int syn_attacker_pref = ntop->getPrefs()->get_attacker_max_num_syn_per_sec(); - int syn_victim_pref = ntop->getPrefs()->get_victim_max_num_syn_per_sec(); - - key = ip.print(ip_buf, sizeof(ip_buf)); - snprintf(rkey, sizeof(rkey), CONST_HOST_ANOMALIES_THRESHOLD, key, vlan_id); - - /* per-host values */ - if((ntop->getRedis()->get(rkey, rsp, sizeof(rsp)) == 0) && (rsp[0] != '\0')) { - /* Note: the order of the fields must match that of anomalies_config into alerts_utils.lua - e.g., %i|%i|%i|%i*/ - char *a, *_t; - - a = strtok_r(rsp, "|", &_t); - if(a && strncmp(a, "global", strlen("global"))) - flow_attacker_pref = atoi(a); - - a = strtok_r(NULL, "|", &_t); - if(a && strncmp(a, "global", strlen("global"))) - flow_victim_pref = atoi(a); - - a = strtok_r(NULL, "|", &_t); - if(a && strncmp(a, "global", strlen("global"))) - syn_attacker_pref = atoi(a); - - a = strtok_r(NULL, "|", &_t); - if(a && strncmp(a, "global", strlen("global"))) - syn_victim_pref = atoi(a); - -#if 0 - printf("%s: %s\n", rkey, rsp); -#endif - } - - /* Counter reload logic */ - if((u_int32_t)flow_attacker_pref != attacker_max_num_flows_per_sec) { - attacker_max_num_flows_per_sec = flow_attacker_pref; - flow_flood_attacker_alert->resetThresholds(attacker_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); -#if 0 - printf("%s: attacker_max_num_flows_per_sec = %d\n", key, attacker_max_num_flows_per_sec); -#endif - } - - if((u_int32_t)flow_victim_pref != victim_max_num_flows_per_sec) { - victim_max_num_flows_per_sec = flow_victim_pref; - flow_flood_victim_alert->resetThresholds(victim_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); -#if 0 - printf("%s: victim_max_num_flows_per_sec = %d\n", key, victim_max_num_flows_per_sec); -#endif - } - - if((u_int32_t)syn_attacker_pref != attacker_max_num_syn_per_sec) { - attacker_max_num_syn_per_sec = syn_attacker_pref; - syn_flood_attacker_alert->resetThresholds(attacker_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); - -#if 0 - printf("%s: attacker_max_num_syn_per_sec = %d\n", key, attacker_max_num_syn_per_sec); -#endif - } - - if((u_int32_t)syn_victim_pref != victim_max_num_syn_per_sec) { - victim_max_num_syn_per_sec = syn_victim_pref; - syn_flood_victim_alert->resetThresholds(victim_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); - -#if 0 - printf("%s: victim_max_num_syn_per_sec = %d\n", key, victim_max_num_syn_per_sec); -#endif - } - } - } - } - - if(!alerts_read) - trigger_host_alerts = false; -} - -/* *************************************** */ - void Host::incLowGoodputFlows(bool asClient) { bool alert = false; @@ -1719,31 +1167,6 @@ void Host::decLowGoodputFlows(bool asClient) { /* *************************************** */ -void Host::incrVisitedWebSite(char *hostname) { - u_int ip4_0 = 0, ip4_1 = 0, ip4_2 = 0, ip4_3 = 0; - char *firstdot = NULL, *nextdot = NULL; - - if(top_sites - && ntop->getPrefs()->are_top_talkers_enabled() - && (strstr(hostname, "in-addr.arpa") == NULL) - && (sscanf(hostname, "%u.%u.%u.%u", &ip4_0, &ip4_1, &ip4_2, &ip4_3) != 4) - ) { - if(ntop->isATrackerHost(hostname)) { - ntop->getTrace()->traceEvent(TRACE_INFO, "[TRACKER] %s", hostname); - return; /* Ignore trackers */ - } - - firstdot = strchr(hostname, '.'); - - if(firstdot) - nextdot = strchr(&firstdot[1], '.'); - - top_sites->add(nextdot ? &firstdot[1] : hostname, 1); - } -} - -/* *************************************** */ - /* Splits a string in the format hostip@vlanid: *buf=hostip, *vlan_id=vlanid */ void Host::splitHostVlan(const char *at_sign_str, char*buf, int bufsize, u_int16_t *vlan_id) { int size; @@ -1773,7 +1196,7 @@ void Host::setMDSNInfo(char *str) { "._afpovertcp._tcp.local", NULL }; - + if(strstr(str, ".ip6.arpa")) return; /* Ignored for the time being */ for(int i=0; tokens[i] != NULL; i++) { @@ -1789,15 +1212,6 @@ void Host::setMDSNInfo(char *str) { set_host_label(info, true); return; } - } -} - -/* *************************************** */ - -void Host::incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer) { - if(localHost) { - if(!icmp) icmp = new ICMPstats(); - if(icmp) icmp->incStats(icmp_type, icmp_code, sent, peer); } } @@ -1806,11 +1220,11 @@ void Host::incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer char* Host::get_country(char *buf, u_int buf_len) { char *continent, *country_name, *city = NULL; float latitude, longitude; - + ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city, &latitude, &longitude); snprintf(buf, buf_len, "%s", country_name); if(city) free(city); - + return(buf); } @@ -1819,7 +1233,7 @@ char* Host::get_country(char *buf, u_int buf_len) { char* Host::get_city(char *buf, u_int buf_len) { char *continent, *country_name, *city = NULL; float latitude, longitude; - + ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city, &latitude, &longitude); if(city) { @@ -1827,7 +1241,7 @@ char* Host::get_city(char *buf, u_int buf_len) { free(city); } else buf[0] = '\0'; - + return(buf); } @@ -1840,30 +1254,3 @@ void Host::get_geocoordinates(float *latitude, float *longitude) { ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city, latitude, longitude); if(city) free(city); } - -/* *************************************** */ - -void Host::setOS(char *_os) { - if((!localHost) - || (mac == NULL) - /* - When this happens then this is a (NAT+)router and - the OS would be misleading - */ - || (mac->getDeviceType() == device_networking) - ) return; - - if(os[0] == '\0') - snprintf(os, sizeof(os), "%s", _os); - - if(strcasestr(os, "iPhone") - || strcasestr(os, "Android") - || strcasestr(os, "mobile")) - mac->setDeviceType(device_phone); - else if(strcasestr(os, "Mac OS") - || strcasestr(os, "Windows") - || strcasestr(os, "Linux")) - mac->setDeviceType(device_workstation); - else if(strcasestr(os, "iPad") || strcasestr(os, "tablet")) - mac->setDeviceType(device_tablet); -} diff --git a/src/LocalHost.cpp b/src/LocalHost.cpp new file mode 100644 index 0000000000..8ecb18f79e --- /dev/null +++ b/src/LocalHost.cpp @@ -0,0 +1,675 @@ +/* + * + * (C) 2013-18 - 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" + +/* *************************************** */ + +LocalHost::LocalHost(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId, IpAddress *_ip) : Host(_iface, _mac, _vlanId, _ip) { +#ifdef LOCALHOST_DEBUG + char buf[48]; + ntop->getTrace()->traceEvent(TRACE_NORMAL, "Instantiating local host %s", _ip ? _ip->print(buf, sizeof(buf)) : ""); +#endif + initialize(); +} + +/* *************************************** */ + +LocalHost::LocalHost(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId) : Host(_iface, ipAddress, _vlanId) { + initialize(); +} + +/* *************************************** */ + +LocalHost::~LocalHost() { + serialize2redis(); /* possibly dumps counters and data to redis */ + + if(top_sites) delete top_sites; + if(old_sites) free(old_sites); + if(dns) delete dns; + if(http) delete http; + if(icmp) delete icmp; + + if(syn_flood_attacker_alert) delete syn_flood_attacker_alert; + if(syn_flood_victim_alert) delete syn_flood_victim_alert; + if(flow_flood_attacker_alert) delete flow_flood_attacker_alert; + if(flow_flood_victim_alert) delete flow_flood_victim_alert; +} + +/* *************************************** */ + +void LocalHost::initialize() { + char key[64], redis_key[128], *k; + char buf[64]; + + local_network_id = -1; + nextSitesUpdate = 0; + top_sites = new FrequentStringItems(HOST_SITES_TOP_NUMBER); + old_sites = strdup("{}"); + dhcpUpdated = false; + icmp = NULL; + num_alerts_detected = 0; + drop_all_host_traffic = false, dump_host_traffic = false; + trigger_host_alerts = false; + + os[0] = '\0'; + + ip.isLocalHost(&local_network_id); + networkStats = getNetworkStats(local_network_id); + + systemHost = ip.isLocalInterfaceAddress(); + + readDHCPCache(); + + dns = new DnsStats(); + http = new HTTPstats(iface->get_hosts_hash()); + + if(ntop->getPrefs()->is_idle_local_host_cache_enabled()) { + char *json = NULL; + + k = ip.print(key, sizeof(key)); + snprintf(redis_key, sizeof(redis_key), HOST_SERIALIZED_KEY, iface->get_id(), k, vlan_id); + + if((json = (char*)malloc(HOST_MAX_SERIALIZED_LEN * sizeof(char))) == NULL) + ntop->getTrace()->traceEvent(TRACE_ERROR, + "Unable to allocate memory to deserialize %s", redis_key); + else if(!ntop->getRedis()->get(redis_key, json, HOST_MAX_SERIALIZED_LEN)){ + /* Found saved copy of the host so let's start from the previous state */ + // ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s => %s", redis_key, json); + ntop->getTrace()->traceEvent(TRACE_INFO, "Deserializing %s", redis_key); + + deserialize(json, redis_key); + } + + if(json) free(json); + } + + attacker_max_num_syn_per_sec = ntop->getPrefs()->get_attacker_max_num_syn_per_sec(); + victim_max_num_syn_per_sec = ntop->getPrefs()->get_victim_max_num_syn_per_sec(); + attacker_max_num_flows_per_sec = ntop->getPrefs()->get_attacker_max_num_flows_per_sec(); + victim_max_num_flows_per_sec = ntop->getPrefs()->get_victim_max_num_flows_per_sec(); + + syn_flood_attacker_alert = new AlertCounter(attacker_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + syn_flood_victim_alert = new AlertCounter(victim_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + flow_flood_attacker_alert = new AlertCounter(attacker_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + flow_flood_victim_alert = new AlertCounter(victim_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + + char host[96]; + char *strIP = ip.print(buf, sizeof(buf)); + snprintf(host, sizeof(host), "%s@%u", strIP, vlan_id); + char rsp[256]; + + if(ntop->getRedis()->getAddress(host, rsp, sizeof(rsp), true) == 0) + setName(rsp); + + updateHostTrafficPolicy(host); + + iface->incNumHosts(true /* Local Host */); + + refreshHostAlertPrefs(); + +#ifdef LOCALHOST_DEBUG + ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s is %s [%p]", + ip.print(buf, sizeof(buf)), + isSystemHost() ? "systemHost" : "", this); +#endif +} + +/* *************************************** */ + +void LocalHost::loadAlertsCounter() { + char buf[64], counters_key[64]; + char rsp[16]; + char *key = get_hostkey(buf, sizeof(buf), true /* force vlan */); + + if(ntop->getPrefs()->are_alerts_disabled()) { + num_alerts_detected = 0; + return; + } + + snprintf(counters_key, sizeof(counters_key), CONST_HOSTS_ALERT_COUNTERS, iface->get_id()); + + if (ntop->getRedis()->hashGet(counters_key, key, rsp, sizeof(rsp)) == 0) + num_alerts_detected = atoi(rsp); + else + num_alerts_detected = 0; + +#if 0 + printf("%s: num_alerts_detected = %d\n", key, num_alerts_detected); +#endif +} + +/* *************************************** */ + +void LocalHost::incICMP(u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer) { + if(!icmp) icmp = new ICMPstats(); + if(icmp) icmp->incStats(icmp_type, icmp_code, sent, peer); +} + +/* *************************************** */ + +void LocalHost::incNumFlows(bool as_client) { + AlertCounter *counter; + + Host::incNumFlows(as_client); + + if(as_client) + counter = flow_flood_attacker_alert; + else + counter = flow_flood_victim_alert; + + if(triggerAlerts()) + counter->incHits(time(0)); +} + +/* *************************************** */ + +void LocalHost::incrVisitedWebSite(char *hostname) { + u_int ip4_0 = 0, ip4_1 = 0, ip4_2 = 0, ip4_3 = 0; + char *firstdot = NULL, *nextdot = NULL; + + if(top_sites + && ntop->getPrefs()->are_top_talkers_enabled() + && (strstr(hostname, "in-addr.arpa") == NULL) + && (sscanf(hostname, "%u.%u.%u.%u", &ip4_0, &ip4_1, &ip4_2, &ip4_3) != 4) + ) { + if(ntop->isATrackerHost(hostname)) { + ntop->getTrace()->traceEvent(TRACE_INFO, "[TRACKER] %s", hostname); + return; /* Ignore trackers */ + } + + firstdot = strchr(hostname, '.'); + + if(firstdot) + nextdot = strchr(&firstdot[1], '.'); + + top_sites->add(nextdot ? &firstdot[1] : hostname, 1); + } +} + +/* *************************************** */ + +bool LocalHost::readDHCPCache() { + Mac *m = mac; /* Cache it as it can be replaced with secondary_mac */ + + if(m && (!dhcpUpdated)) { + /* Check DHCP cache */ + char client_mac[24], buf[64], key[64]; + + dhcpUpdated = true; + + if(!m->isNull()) { + Utils::formatMac(m->get_mac(), client_mac, sizeof(client_mac)); + + snprintf(key, sizeof(key), DHCP_CACHE, iface->get_id()); + if(ntop->getRedis()->hashGet(key, client_mac, buf, sizeof(buf)) == 0) { + setName(buf); + return true; + } + } + } + + return false; +} + +/* *************************************** */ + +json_object* LocalHost::getJSONObject() { + json_object *my_object = Host::getJSONObject(); + + if(dns) json_object_object_add(my_object, "dns", dns->getJSONObject()); + if(http) json_object_object_add(my_object, "http", http->getJSONObject()); + + return(my_object); +} + +/* *************************************** */ + +void LocalHost::serialize2redis() { + if((ntop->getPrefs()->is_idle_local_host_cache_enabled() + || ntop->getPrefs()->is_active_local_host_cache_enabled()) + && (!ip.isEmpty())) { + char *json = serialize(); + char host_key[128], key[128]; + char *k = ip.print(host_key, sizeof(host_key)); + + snprintf(key, sizeof(key), HOST_SERIALIZED_KEY, iface->get_id(), k, vlan_id); + ntop->getRedis()->set(key, json, ntop->getPrefs()->get_local_host_cache_duration()); + ntop->getTrace()->traceEvent(TRACE_INFO, "Dumping serialization %s", k); + //ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s => %s", k, json); + free(json); + } +} + +/* *************************************** */ + +bool LocalHost::deserialize(char *json_str, char *key) { + json_object *o, *obj; + enum json_tokener_error jerr = json_tokener_success; + + if((o = json_tokener_parse_verbose(json_str, &jerr)) == NULL) { + ntop->getTrace()->traceEvent(TRACE_WARNING, "JSON Parse error [%s] key: %s: %s", + json_tokener_error_desc(jerr), + key, + json_str); + return(false); + } + + if(! mac) { + u_int8_t mac_buf[6]; + memset(mac_buf, 0, sizeof(mac_buf)); + + if(json_object_object_get_ex(o, "mac_address", &obj)) Utils::parseMac(mac_buf, json_object_get_string(obj)); + + // sticky hosts enabled, we must bring up the mac address + if((mac = iface->getMac(mac_buf, true /* create if not exists*/)) != NULL) + mac->incUses(); + else + ntop->getTrace()->traceEvent(TRACE_WARNING, "Internal error: NULL mac. Are you running out of memory?"); + } + + if(json_object_object_get_ex(o, "seen.first", &obj)) first_seen = json_object_get_int64(obj); + if(json_object_object_get_ex(o, "seen.last", &obj)) last_seen = json_object_get_int64(obj); + + if(json_object_object_get_ex(o, "symbolic_name", &obj)) { if(symbolic_name) free(symbolic_name); symbolic_name = strdup(json_object_get_string(obj)); } + if(json_object_object_get_ex(o, "os", &obj)) { snprintf(os, sizeof(os), "%s", json_object_get_string(obj)); } + if(json_object_object_get_ex(o, "tcp_sent", &obj)) tcp_sent.deserialize(obj); + if(json_object_object_get_ex(o, "tcp_rcvd", &obj)) tcp_rcvd.deserialize(obj); + if(json_object_object_get_ex(o, "udp_sent", &obj)) udp_sent.deserialize(obj); + if(json_object_object_get_ex(o, "udp_rcvd", &obj)) udp_rcvd.deserialize(obj); + if(json_object_object_get_ex(o, "icmp_sent", &obj)) icmp_sent.deserialize(obj); + if(json_object_object_get_ex(o, "icmp_rcvd", &obj)) icmp_rcvd.deserialize(obj); + if(json_object_object_get_ex(o, "other_ip_sent", &obj)) other_ip_sent.deserialize(obj); + if(json_object_object_get_ex(o, "other_ip_rcvd", &obj)) other_ip_rcvd.deserialize(obj); + + /* packet stats */ + if(json_object_object_get_ex(o, "pktStats.sent", &obj)) sent_stats.deserialize(obj); + if(json_object_object_get_ex(o, "pktStats.recv", &obj)) recv_stats.deserialize(obj); + + /* TCP packet stats */ + if(json_object_object_get_ex(o, "tcpPacketStats.pktRetr", &obj)) tcpPacketStats.pktRetr = json_object_get_int(obj); + if(json_object_object_get_ex(o, "tcpPacketStats.pktOOO", &obj)) tcpPacketStats.pktOOO = json_object_get_int(obj); + if(json_object_object_get_ex(o, "tcpPacketStats.pktLost", &obj)) tcpPacketStats.pktLost = json_object_get_int(obj); + if(json_object_object_get_ex(o, "tcpPacketStats.pktKeepAlive", &obj)) tcpPacketStats.pktKeepAlive = json_object_get_int(obj); + + if(json_object_object_get_ex(o, "flows.as_client", &obj)) total_num_flows_as_client = json_object_get_int(obj); + if(json_object_object_get_ex(o, "flows.as_server", &obj)) total_num_flows_as_server = json_object_get_int(obj); + if(json_object_object_get_ex(o, "flows.dropped", &obj)) total_num_dropped_flows = json_object_get_int(obj); + + if(json_object_object_get_ex(o, "sent", &obj)) sent.deserialize(obj); + if(json_object_object_get_ex(o, "rcvd", &obj)) rcvd.deserialize(obj); + last_bytes = sent.getNumBytes() + rcvd.getNumBytes(); + last_packets = sent.getNumPkts() + rcvd.getNumPkts(); + + if(json_object_object_get_ex(o, "total_activity_time", &obj)) total_activity_time = json_object_get_int(obj); + + if(json_object_object_get_ex(o, "dns", &obj)) { + if(dns) dns->deserialize(obj); + } + + if(json_object_object_get_ex(o, "http", &obj)) { + if(http) http->deserialize(obj); + } + + if(ndpiStats) { + delete ndpiStats; + ndpiStats = NULL; + } + + if(json_object_object_get_ex(o, "ndpiStats", &obj)) { + ndpiStats = new nDPIStats(); + ndpiStats->deserialize(iface, obj); + } + + /* We commented the line below to avoid strings too long */ +#if 0 + activityStats.reset(); + if(json_object_object_get_ex(o, "activityStats", &obj)) activityStats.deserialize(obj); +#endif + + if(json_object_object_get_ex(o, "pktStats.sent", &obj)) sent_stats.deserialize(obj); + if(json_object_object_get_ex(o, "pktStats.recv", &obj)) recv_stats.deserialize(obj); + + json_object_put(o); + + return(true); +} + +/* *************************************** */ + +void LocalHost::updateSynFlags(time_t when, u_int8_t flags, Flow *f, bool syn_sent) { + AlertCounter *counter = syn_sent ? syn_flood_attacker_alert : syn_flood_victim_alert; + + if(triggerAlerts()) + counter->incHits(when); +} + +/* *************************************** */ + +void LocalHost::updateHostTrafficPolicy(char *key) { + char buf[64], *host; + + if(key) + host = key; + else + host = get_hostkey(buf, sizeof(buf)); + + if(iface->isPacketInterface()) { + if((ntop->getRedis()->hashGet((char*)DROP_HOST_TRAFFIC, host, buf, sizeof(buf)) == -1) + || (strcmp(buf, "true") != 0)) + drop_all_host_traffic = false; + else + drop_all_host_traffic = true; + + } + + if((ntop->getRedis()->hashGet((char*)DUMP_HOST_TRAFFIC, + host, buf, sizeof(buf)) == -1) + || (strcmp(buf, "true") != 0)) + dump_host_traffic = false; + else + dump_host_traffic = true; +} + +/* *************************************** */ + +void LocalHost::setDumpTrafficPolicy(bool new_policy) { + char buf[64], *host; + + if(dump_host_traffic == new_policy) + return; /* Nothing to do */ + else + dump_host_traffic = new_policy; + + host = get_hostkey(buf, sizeof(buf), true); + + ntop->getRedis()->hashSet((char*)DUMP_HOST_TRAFFIC, host, + (char*)(dump_host_traffic ? "true" : "false")); +}; + +/* *************************************** */ + +bool LocalHost::hasAnomalies() { + time_t now = time(0); + + return syn_flood_victim_alert->isAboveThreshold(now) + || syn_flood_attacker_alert->isAboveThreshold(now) + || flow_flood_victim_alert->isAboveThreshold(now) + || flow_flood_attacker_alert->isAboveThreshold(now); +} + +/* *************************************** */ + +void LocalHost::luaAnomalies(lua_State* vm) { + if(!vm) + return; + + if(hasAnomalies()) { + time_t now = time(0); + lua_newtable(vm); + + if(syn_flood_victim_alert->isAboveThreshold(now)) + syn_flood_victim_alert->lua(vm, "syn_flood_victim"); + if(syn_flood_attacker_alert->isAboveThreshold(now)) + syn_flood_attacker_alert->lua(vm, "syn_flood_attacker"); + if(flow_flood_victim_alert->isAboveThreshold(now)) + flow_flood_victim_alert->lua(vm, "flows_flood_victim"); + if(flow_flood_attacker_alert->isAboveThreshold(now)) + flow_flood_attacker_alert->lua(vm, "flows_flood_attacker"); + + lua_pushstring(vm, "anomalies"); + lua_insert(vm, -2); + lua_settable(vm, -3); + } +} + +/* *************************************** */ + +void LocalHost::lua(lua_State* vm, AddressTree *ptree, + bool host_details, bool verbose, + bool returnHost, bool asListElement) { + char buf_id[64], *host_id = buf_id; + char *local_net; + bool mask_host = Utils::maskHost(isLocalHost()); + + if((ptree && (!match(ptree))) || mask_host) + return; + + Host::lua(vm, + NULL /* ptree already checked */, + host_details, verbose, returnHost, + false /* asListElement possibly handled later */); + + if((!mask_host) && top_sites && ntop->getPrefs()->are_top_talkers_enabled()) { + char *cur_sites = top_sites->json(); + lua_push_str_table_entry(vm, "sites", cur_sites ? cur_sites : (char*)"{}"); + lua_push_str_table_entry(vm, "sites.old", old_sites ? old_sites : (char*)"{}"); + if(cur_sites) free(cur_sites); + } + + lua_push_int32_table_entry(vm, "local_network_id", local_network_id); + + local_net = ntop->getLocalNetworkName(local_network_id); + if(local_net == NULL) + lua_push_nil_table_entry(vm, "local_network_name"); + else + lua_push_str_table_entry(vm, "local_network_name", local_net); + + /* Criteria */ + lua_newtable(vm); + + lua_push_int_table_entry(vm, "upload", getNumBytesSent()); + lua_push_int_table_entry(vm, "download", getNumBytesRcvd()); + lua_push_int_table_entry(vm, "unknown", get_ndpi_stats()->getProtoBytes(NDPI_PROTOCOL_UNKNOWN)); + lua_push_int_table_entry(vm, "incomingflows", getNumIncomingFlows()); + lua_push_int_table_entry(vm, "outgoingflows", getNumOutgoingFlows()); + + lua_pushstring(vm, "criteria"); + lua_insert(vm, -2); + lua_settable(vm, -3); + + if(host_details) { + if(icmp) + icmp->lua(ip.isIPv4(), vm); + } + + if(verbose) { + if(dns) dns->lua(vm); + if(http) http->lua(vm); + + if(hasAnomalies()) luaAnomalies(vm); + } + + if(asListElement) { + host_id = get_hostkey(buf_id, sizeof(buf_id)); + + lua_pushstring(vm, host_id); + lua_insert(vm, -2); + lua_settable(vm, -3); + } +} + +/* *************************************** */ + +void LocalHost::refreshHostAlertPrefs() { + bool alerts_read = false; + + if(!ntop->getPrefs()->are_alerts_disabled() + && (!ip.isEmpty())) { + char *key, ip_buf[48], rsp[64], rkey[128]; + + /* This value always contains vlan information */ + key = get_hostkey(ip_buf, sizeof(ip_buf), true); + + if(key) { + snprintf(rkey, sizeof(rkey), CONST_SUPPRESSED_ALERT_PREFS, getInterface()->get_id()); + if(ntop->getRedis()->hashGet(rkey, key, rsp, sizeof(rsp)) == 0) + trigger_host_alerts = ((strcmp(rsp, "false") == 0) ? 0 : 1); + else + trigger_host_alerts = true; + + alerts_read = true; + + if(trigger_host_alerts) { + /* Defaults */ + int flow_attacker_pref = ntop->getPrefs()->get_attacker_max_num_flows_per_sec(); + int flow_victim_pref = ntop->getPrefs()->get_victim_max_num_flows_per_sec(); + int syn_attacker_pref = ntop->getPrefs()->get_attacker_max_num_syn_per_sec(); + int syn_victim_pref = ntop->getPrefs()->get_victim_max_num_syn_per_sec(); + + key = ip.print(ip_buf, sizeof(ip_buf)); + snprintf(rkey, sizeof(rkey), CONST_HOST_ANOMALIES_THRESHOLD, key, vlan_id); + + /* per-host values */ + if((ntop->getRedis()->get(rkey, rsp, sizeof(rsp)) == 0) && (rsp[0] != '\0')) { + /* Note: the order of the fields must match that of anomalies_config into alerts_utils.lua + e.g., %i|%i|%i|%i*/ + char *a, *_t; + + a = strtok_r(rsp, "|", &_t); + if(a && strncmp(a, "global", strlen("global"))) + flow_attacker_pref = atoi(a); + + a = strtok_r(NULL, "|", &_t); + if(a && strncmp(a, "global", strlen("global"))) + flow_victim_pref = atoi(a); + + a = strtok_r(NULL, "|", &_t); + if(a && strncmp(a, "global", strlen("global"))) + syn_attacker_pref = atoi(a); + + a = strtok_r(NULL, "|", &_t); + if(a && strncmp(a, "global", strlen("global"))) + syn_victim_pref = atoi(a); + +#if 0 + printf("%s: %s\n", rkey, rsp); +#endif + } + + /* Counter reload logic */ + if((u_int32_t)flow_attacker_pref != attacker_max_num_flows_per_sec) { + attacker_max_num_flows_per_sec = flow_attacker_pref; + flow_flood_attacker_alert->resetThresholds(attacker_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); +#if 0 + printf("%s: attacker_max_num_flows_per_sec = %d\n", key, attacker_max_num_flows_per_sec); +#endif + } + + if((u_int32_t)flow_victim_pref != victim_max_num_flows_per_sec) { + victim_max_num_flows_per_sec = flow_victim_pref; + flow_flood_victim_alert->resetThresholds(victim_max_num_flows_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); +#if 0 + printf("%s: victim_max_num_flows_per_sec = %d\n", key, victim_max_num_flows_per_sec); +#endif + } + + if((u_int32_t)syn_attacker_pref != attacker_max_num_syn_per_sec) { + attacker_max_num_syn_per_sec = syn_attacker_pref; + syn_flood_attacker_alert->resetThresholds(attacker_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + +#if 0 + printf("%s: attacker_max_num_syn_per_sec = %d\n", key, attacker_max_num_syn_per_sec); +#endif + } + + if((u_int32_t)syn_victim_pref != victim_max_num_syn_per_sec) { + victim_max_num_syn_per_sec = syn_victim_pref; + syn_flood_victim_alert->resetThresholds(victim_max_num_syn_per_sec, CONST_MAX_THRESHOLD_CROSS_DURATION); + +#if 0 + printf("%s: victim_max_num_syn_per_sec = %d\n", key, victim_max_num_syn_per_sec); +#endif + } + } + } + } + + if(!alerts_read) + trigger_host_alerts = false; +} + +/* *************************************** */ + +void LocalHost::updateHTTPHostRequest(char *virtual_host_name, u_int32_t num_req, + u_int32_t bytes_sent, u_int32_t bytes_rcvd) { + if(http) + http->updateHTTPHostRequest(virtual_host_name, num_req, bytes_sent, bytes_rcvd); +} + +/* *************************************** */ + +void LocalHost::updateStats(struct timeval *tv) { + Host::updateStats(tv); + + if(http) http->updateStats(tv); + + if(top_sites && ntop->getPrefs()->are_top_talkers_enabled() && (tv->tv_sec >= nextSitesUpdate)) { + if(nextSitesUpdate > 0) { + if(old_sites) + free(old_sites); + old_sites = top_sites->json(); + } + + nextSitesUpdate = tv->tv_sec + HOST_SITES_REFRESH; + } +} + +/* *************************************** */ + +u_int32_t LocalHost::getNumAlerts(bool from_alertsmanager) { + if(!from_alertsmanager) + return(num_alerts_detected); + + num_alerts_detected = iface->getAlertsManager()->getNumHostAlerts(this, true); + + ntop->getTrace()->traceEvent(TRACE_DEBUG, + "Refreshing alerts from alertsmanager [num: %i]", + num_alerts_detected); + + return(num_alerts_detected); +} + +/* *************************************** */ + +void LocalHost::setOS(char *_os) { + if((mac == NULL) + /* + When this happens then this is a (NAT+)router and + the OS would be misleading + */ + || (mac->getDeviceType() == device_networking) + ) return; + + if(os[0] == '\0') + snprintf(os, sizeof(os), "%s", _os); + + if(strcasestr(os, "iPhone") + || strcasestr(os, "Android") + || strcasestr(os, "mobile")) + mac->setDeviceType(device_phone); + else if(strcasestr(os, "Mac OS") + || strcasestr(os, "Windows") + || strcasestr(os, "Linux")) + mac->setDeviceType(device_workstation); + else if(strcasestr(os, "iPad") || strcasestr(os, "tablet")) + mac->setDeviceType(device_tablet); +} diff --git a/src/NetworkInterface.cpp b/src/NetworkInterface.cpp index 5a14e4cc0c..eeb38ddcfe 100644 --- a/src/NetworkInterface.cpp +++ b/src/NetworkInterface.cpp @@ -2535,6 +2535,7 @@ void NetworkInterface::cleanup() { void NetworkInterface::findFlowHosts(u_int16_t vlanId, Mac *src_mac, IpAddress *_src_ip, Host **src, Mac *dst_mac, IpAddress *_dst_ip, Host **dst) { + int16_t local_network_id; /* Do not look on sub interfaces, Flows are always created in the same interface of its hosts */ (*src) = hosts_hash->get(vlanId, _src_ip); @@ -2546,7 +2547,11 @@ void NetworkInterface::findFlowHosts(u_int16_t vlanId, return; } - (*src) = new Host(this, src_mac, vlanId, _src_ip); + if(_src_ip && (_src_ip->isLocalHost(&local_network_id) || _src_ip->isLocalInterfaceAddress())) + (*src) = new LocalHost(this, src_mac, vlanId, _src_ip); + else + (*src) = new RemoteHost(this, src_mac, vlanId, _src_ip); + if(!hosts_hash->add(*src)) { //ntop->getTrace()->traceEvent(TRACE_WARNING, "Too many hosts in interface %s", ifname); delete *src; @@ -2571,7 +2576,11 @@ void NetworkInterface::findFlowHosts(u_int16_t vlanId, return; } - (*dst) = new Host(this, dst_mac, vlanId, _dst_ip); + if(_dst_ip && (_dst_ip->isLocalHost(&local_network_id) || _dst_ip->isLocalInterfaceAddress())) + (*dst) = new LocalHost(this, dst_mac, vlanId, _dst_ip); + else + (*dst) = new RemoteHost(this, dst_mac, vlanId, _dst_ip); + if(!hosts_hash->add(*dst)) { // ntop->getTrace()->traceEvent(TRACE_WARNING, "Too many hosts in interface %s", ifname); delete *dst; @@ -3095,7 +3104,16 @@ static bool find_vlan_by_vlan_id(GenericHashEntry *he, void *user_data, bool *ma /* **************************************************** */ bool NetworkInterface::restoreHost(char *host_ip, u_int16_t vlan_id) { - Host *h = new Host(this, host_ip, vlan_id); + Host *h; + int16_t local_network_id; + IpAddress ipa; + + ipa.set(host_ip); + + if(ipa.isLocalHost(&local_network_id)) + h = new LocalHost(this, host_ip, vlan_id); + else + h = new RemoteHost(this, host_ip, vlan_id); if(!h) return(false); diff --git a/src/Prefs.cpp b/src/Prefs.cpp index 994ba435a8..19901af682 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -435,7 +435,7 @@ void Prefs::getDefaultStringPrefsValue(const char *pref_key, char **buffer, cons bool Prefs::getDefaultBoolPrefsValue(const char *pref_key, const bool default_value) { char rsp[8]; - if(ntop->getRedis()->get((char*)pref_key, rsp, sizeof(rsp)) == 0) + if(ntop->getRedis()->get((char*)pref_key, rsp, sizeof(rsp)) == 0 && rsp[0] != '\0') return((rsp[0] == '1') ? true : false); else return(default_value); diff --git a/src/RemoteHost.cpp b/src/RemoteHost.cpp new file mode 100644 index 0000000000..4922b531aa --- /dev/null +++ b/src/RemoteHost.cpp @@ -0,0 +1,87 @@ +/* + * + * (C) 2013-18 - 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" + +/* *************************************** */ + +RemoteHost::RemoteHost(NetworkInterface *_iface, Mac *_mac, u_int16_t _vlanId, IpAddress *_ip) : Host(_iface, _mac, _vlanId, _ip) { +#ifdef REMOTEHOST_DEBUG + char buf[48]; + ntop->getTrace()->traceEvent(TRACE_NORMAL, "Instantiating REMOTE host %s", _ip ? _ip->print(buf, sizeof(buf)) : ""); +#endif + initialize(); +} + +/* *************************************** */ + +RemoteHost::RemoteHost(NetworkInterface *_iface, char *ipAddress, u_int16_t _vlanId) : Host(_iface, ipAddress, _vlanId) { + +} + +/* *************************************** */ + +RemoteHost::~RemoteHost() { +} + +/* *************************************** */ + +void RemoteHost::initialize() { + char buf[64], host[96]; + char *strIP = ip.print(buf, sizeof(buf)); + snprintf(host, sizeof(host), "%s@%u", strIP, vlan_id); + char rsp[256]; + + blacklisted_host = false, + trafficCategory[0] = '\0'; + + if(ntop->getPrefs()->is_dns_resolution_enabled_for_all_hosts()) { + if(ntop->getRedis()->getAddress(host, rsp, sizeof(rsp), true) == 0) + setName(rsp); + } + + blacklisted_host = ntop->isBlacklistedIP(&ip); + + if((!blacklisted_host) && ntop->getPrefs()->is_httpbl_enabled() && ip.isIPv4()) { + // http:bl only works for IPv4 addresses + if(ntop->getRedis()->getAddressTrafficFiltering(host, iface, trafficCategory, + sizeof(trafficCategory), true) == 0) { + if(strcmp(trafficCategory, NULL_BL)) { + blacklisted_host = true; + } + } + } + + iface->incNumHosts(false /* Remote Host */); +} + +/* ***************************************** */ + +void RemoteHost::refreshHTTPBL() { + if(ip.isIPv4() + && (trafficCategory[0] == '\0') + && ntop->get_httpbl()) { + char buf[128] = { 0 }; + char* ip_addr = ip.print(buf, sizeof(buf)); + + ntop->get_httpbl()->findCategory(ip_addr, trafficCategory, sizeof(trafficCategory), false); + } +}