/src/ntopng/src/LocalHostStats.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * (C) 2013-26 - ntop.org |
4 | | * |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software Foundation, |
18 | | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include "ntop_includes.h" |
23 | | |
24 | | /* *************************************** */ |
25 | | |
26 | 10.9k | LocalHostStats::LocalHostStats(Host* _host) : HostStats(_host) { |
27 | 10.9k | if (trace_new_delete) |
28 | 0 | ntop->getTrace()->traceEvent(TRACE_NORMAL, "[new] %s", __FILE__); |
29 | | |
30 | 10.9k | top_sites = new (std::nothrow) MostVisitedList(HOST_SITES_TOP_NUMBER); |
31 | | |
32 | 10.9k | dns = new (std::nothrow) DnsStats(); |
33 | 10.9k | http = new (std::nothrow) HTTPstats(_host); |
34 | 10.9k | icmp = new (std::nothrow) ICMPstats(); |
35 | 10.9k | peers = new (std::nothrow) |
36 | 10.9k | PeerStats(MAX_DYNAMIC_STATS_VALUES /* 10 as default */); |
37 | | |
38 | 10.9k | init(); |
39 | 10.9k | } |
40 | | |
41 | | /* *************************************** */ |
42 | | |
43 | 10.9k | LocalHostStats::LocalHostStats(LocalHostStats& s) : HostStats(s) { |
44 | 10.9k | top_sites = new (std::nothrow) MostVisitedList(HOST_SITES_TOP_NUMBER); |
45 | 10.9k | peers = new (std::nothrow) |
46 | 10.9k | PeerStats(MAX_DYNAMIC_STATS_VALUES /* 10 as default */); |
47 | 10.9k | dns = s.getDNSstats() ? new (std::nothrow) DnsStats(*s.getDNSstats()) : NULL; |
48 | 10.9k | http = NULL; |
49 | 10.9k | icmp = NULL; |
50 | | |
51 | 10.9k | init(); |
52 | 10.9k | } |
53 | | |
54 | | /* *************************************** */ |
55 | | |
56 | 21.8k | LocalHostStats::~LocalHostStats() { |
57 | 21.8k | if (top_sites) delete top_sites; |
58 | 21.8k | if (dns) delete dns; |
59 | 21.8k | if (http) delete http; |
60 | 21.8k | if (icmp) delete icmp; |
61 | 21.8k | if (peers) delete (peers); |
62 | 21.8k | } |
63 | | |
64 | | /* *************************************** */ |
65 | | |
66 | 21.8k | void LocalHostStats::init() { |
67 | 21.8k | nextPeriodicUpdate = 0; |
68 | 21.8k | num_contacts_as_cli = num_contacts_as_srv = num_reset_flow = 0; |
69 | | |
70 | 21.8k | num_contacted_hosts_as_client.init(8); /* 128 bytes */ |
71 | 21.8k | num_host_contacts_as_server.init(8); /* 128 bytes */ |
72 | 21.8k | num_contacted_services_as_client.init(8); /* 128 bytes */ |
73 | 21.8k | num_contacted_hosts.init(4); /* 16 bytes */ |
74 | 21.8k | num_contacted_countries.init(4); /* 16 bytes */ |
75 | 21.8k | contacts_as_cli.init(4); /* 16 bytes */ |
76 | 21.8k | contacts_as_srv.init(4); /* 16 bytes */ |
77 | | |
78 | 21.8k | num_dns_servers.init(5); |
79 | 21.8k | num_smtp_servers.init(5); |
80 | 21.8k | num_ntp_servers.init(5); |
81 | 21.8k | num_imap_servers.init(5); |
82 | 21.8k | num_pop_servers.init(5); |
83 | 21.8k | num_contacted_domain_names.init(4); |
84 | 21.8k | } |
85 | | |
86 | | /* *************************************** */ |
87 | | |
88 | 868 | void LocalHostStats::incrVisitedWebSite(char* hostname) { |
89 | 868 | u_int ip4_0 = 0, ip4_1 = 0, ip4_2 = 0, ip4_3 = 0; |
90 | 868 | char *firstdot = NULL, *nextdot = NULL; |
91 | | |
92 | 868 | if ((strstr(hostname, "in-addr.arpa") == NULL) && |
93 | 849 | (sscanf(hostname, "%u.%u.%u.%u", &ip4_0, &ip4_1, &ip4_2, &ip4_3) != 4)) { |
94 | 848 | incContactedHosts(hostname); |
95 | | |
96 | | /* Top Sites update, done only if the preference is enabled */ |
97 | 848 | if (top_sites && ntop->getPrefs()->are_top_talkers_enabled()) { |
98 | 0 | if (ntop->isATrackerHost(hostname)) { |
99 | 0 | ntop->getTrace()->traceEvent(TRACE_INFO, "[TRACKER] %s", hostname); |
100 | 0 | return; /* Ignore trackers */ |
101 | 0 | } |
102 | | |
103 | 0 | firstdot = strchr(hostname, '.'); |
104 | |
|
105 | 0 | if (firstdot) nextdot = strchr(&firstdot[1], '.'); |
106 | |
|
107 | 0 | top_sites->incrVisitedData(nextdot ? &firstdot[1] : hostname, 1); |
108 | 0 | host->getInterface()->incrVisitedWebSite(nextdot ? &firstdot[1] |
109 | 0 | : hostname); |
110 | 0 | } |
111 | 848 | } |
112 | 868 | } |
113 | | |
114 | | /* *************************************** */ |
115 | | |
116 | 13.5k | void LocalHostStats::updateStats(const struct timeval* tv) { |
117 | 13.5k | HostStats::updateStats(tv); |
118 | | |
119 | 13.5k | if (dns) dns->updateStats(tv); |
120 | 13.5k | if (icmp) icmp->updateStats(tv); |
121 | 13.5k | if (http) http->updateStats(tv); |
122 | | |
123 | | /* 5 Min Update */ |
124 | 13.5k | if (tv->tv_sec >= nextPeriodicUpdate) { |
125 | | /* visited sites update */ |
126 | 6.65k | contacted_hosts.addObservation(getContactedHostsCardinality()); |
127 | 6.65k | resetContactedHosts(); |
128 | | |
129 | | /* countries contacts update */ |
130 | 6.65k | resetCountriesContacts(); |
131 | | |
132 | | /* Contacted peers update */ |
133 | 6.65k | updateHostContacts(); |
134 | | |
135 | 6.65k | if (ntop->getPrefs()->are_top_talkers_enabled()) { |
136 | 0 | if (top_sites && host) { |
137 | 0 | char additional_key_info[128], buf[100]; |
138 | 0 | if (!host->get_mac() && !host->get_ip()) return; |
139 | | |
140 | | /* String like `_1.1.1.1@2` */ |
141 | 0 | snprintf(additional_key_info, sizeof(additional_key_info), "_%s", |
142 | 0 | host->get_tskey(buf, sizeof(buf))); |
143 | |
|
144 | 0 | top_sites->saveOldData( |
145 | 0 | host->getInterface()->get_id(), additional_key_info, |
146 | 0 | (char*)HASHKEY_LOCAL_HOSTS_TOP_SITES_HOUR_KEYS_PUSHED); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | 6.65k | nextPeriodicUpdate = tv->tv_sec + HOST_SITES_REFRESH; |
151 | 6.65k | } |
152 | 13.5k | } |
153 | | |
154 | | /* *************************************** */ |
155 | | |
156 | 6.65k | void LocalHostStats::updateHostContacts() { |
157 | 6.65k | num_contacts_as_cli = contacts_as_cli.getEstimate(), |
158 | 6.65k | num_contacts_as_srv = contacts_as_srv.getEstimate(); |
159 | 6.65k | if (peers) { |
160 | 6.65k | peers->addElement(num_contacts_as_cli, true); |
161 | 6.65k | peers->addElement(num_contacts_as_srv, false); |
162 | 6.65k | } |
163 | 6.65k | contacts_as_cli.reset(), contacts_as_srv.reset(); |
164 | 6.65k | } |
165 | | |
166 | | /* *************************************** */ |
167 | | |
168 | | void LocalHostStats::getJSONObject(json_object* my_object, |
169 | 0 | DetailsLevel details_level) { |
170 | 0 | HostStats::getJSONObject(my_object, details_level); |
171 | |
|
172 | 0 | if (dns) json_object_object_add(my_object, "dns", dns->getJSONObject()); |
173 | 0 | if (http) json_object_object_add(my_object, "http", http->getJSONObject()); |
174 | | |
175 | | /* UDP stats */ |
176 | 0 | if (udp_sent_unicast) |
177 | 0 | json_object_object_add(my_object, "udpBytesSent.unicast", |
178 | 0 | json_object_new_int64(udp_sent_unicast)); |
179 | 0 | if (udp_sent_non_unicast) |
180 | 0 | json_object_object_add(my_object, "udpBytesSent.non_unicast", |
181 | 0 | json_object_new_int64(udp_sent_non_unicast)); |
182 | |
|
183 | 0 | addRedisSitesKey(); |
184 | 0 | } |
185 | | |
186 | | /* *************************************** */ |
187 | | |
188 | 0 | void LocalHostStats::luaHostBehaviour(lua_State* vm) { |
189 | 0 | HostStats::luaHostBehaviour(vm); |
190 | |
|
191 | 0 | lua_newtable(vm); |
192 | |
|
193 | 0 | lua_push_uint32_table_entry(vm, "value", getContactedHostsCardinality()); |
194 | 0 | lua_push_bool_table_entry(vm, "anomaly", contacted_hosts.anomalyFound()); |
195 | 0 | lua_push_uint64_table_entry(vm, "lower_bound", |
196 | 0 | contacted_hosts.getLastLowerBound()); |
197 | 0 | lua_push_uint64_table_entry(vm, "upper_bound", |
198 | 0 | contacted_hosts.getLastUpperBound()); |
199 | |
|
200 | 0 | lua_pushstring(vm, "contacted_hosts_behaviour"); |
201 | 0 | lua_insert(vm, -2); |
202 | 0 | lua_settable(vm, -3); |
203 | 0 | } |
204 | | |
205 | | /* *************************************** */ |
206 | | |
207 | | void LocalHostStats::lua(lua_State* vm, bool mask_host, |
208 | 0 | DetailsLevel details_level) { |
209 | 0 | HostStats::lua(vm, mask_host, details_level); |
210 | |
|
211 | 0 | if ((!mask_host) && top_sites && |
212 | 0 | ntop->getPrefs()->are_top_talkers_enabled()) { |
213 | 0 | top_sites->lua(vm, (char*)"sites", (char*)"sites.old"); |
214 | 0 | } |
215 | |
|
216 | 0 | luaHostBehaviour(vm); |
217 | |
|
218 | 0 | if (details_level >= details_high) { |
219 | 0 | luaICMP(vm, host->get_ip()->isIPv4(), true); |
220 | 0 | luaDNS(vm, true); |
221 | 0 | luaHTTP(vm); |
222 | | |
223 | | /* Contacts */ |
224 | 0 | lua_newtable(vm); |
225 | |
|
226 | 0 | lua_push_int32_table_entry(vm, "num_contacted_hosts_as_client", |
227 | 0 | num_contacted_hosts_as_client.getEstimate()); |
228 | 0 | lua_push_int32_table_entry(vm, "num_host_contacts_as_server", |
229 | 0 | num_host_contacts_as_server.getEstimate()); |
230 | 0 | lua_push_int32_table_entry(vm, "num_contacted_services_as_client", |
231 | 0 | num_contacted_services_as_client.getEstimate()); |
232 | |
|
233 | 0 | lua_pushstring(vm, "cardinality"); |
234 | 0 | lua_insert(vm, -2); |
235 | 0 | lua_settable(vm, -3); |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | /* *************************************** */ |
240 | | |
241 | 0 | void LocalHostStats::luaPeers(lua_State* vm) { |
242 | 0 | if (peers) { |
243 | 0 | if (peers->getSlidingWinStatus()) { |
244 | 0 | lua_newtable(vm); |
245 | |
|
246 | 0 | lua_push_int32_table_entry(vm, "contacted_peers_in_last_5mins_as_cli", |
247 | 0 | num_contacts_as_cli); |
248 | 0 | lua_push_int32_table_entry(vm, "contacted_peers_in_last_5mins_as_srv", |
249 | 0 | num_contacts_as_srv); |
250 | 0 | lua_push_int32_table_entry(vm, "sliding_avg_peers_as_client", |
251 | 0 | peers->getCliSlidingEstimate()); |
252 | 0 | lua_push_int32_table_entry(vm, "sliding_avg_peers_as_server", |
253 | 0 | peers->getSrvSlidingEstimate()); |
254 | 0 | lua_push_int32_table_entry(vm, "tot_avg_peers_as_client", |
255 | 0 | peers->getCliTotEstimate()); |
256 | 0 | lua_push_int32_table_entry(vm, "tot_avg_peers_as_server", |
257 | 0 | peers->getSrvTotEstimate()); |
258 | |
|
259 | 0 | lua_pushstring(vm, "peers"); |
260 | 0 | lua_insert(vm, -2); |
261 | 0 | lua_settable(vm, -3); |
262 | |
|
263 | 0 | return; |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | 0 | lua_pushnil(vm); |
268 | 0 | } |
269 | | |
270 | | /* *************************************** */ |
271 | | |
272 | 0 | void LocalHostStats::lua_get_timeseries(lua_State* vm) { |
273 | 0 | luaStats(vm, host->getInterface(), true /* host details */, |
274 | 0 | true /* verbose */, true /* tsLua */); |
275 | |
|
276 | 0 | tcp_packet_stats_sent.lua(vm, "tcpPacketStats.sent"); |
277 | 0 | tcp_packet_stats_rcvd.lua(vm, "tcpPacketStats.rcvd"); |
278 | |
|
279 | 0 | if (dns) dns->lua(vm, false /* NOT verbose */); |
280 | |
|
281 | 0 | if (icmp) { |
282 | 0 | struct ts_icmp_stats icmp_s; |
283 | 0 | icmp->getTsStats(&icmp_s); |
284 | |
|
285 | 0 | lua_push_uint64_table_entry(vm, "icmp.echo_pkts_sent", |
286 | 0 | icmp_s.echo_packets_sent); |
287 | 0 | lua_push_uint64_table_entry(vm, "icmp.echo_pkts_rcvd", |
288 | 0 | icmp_s.echo_packets_rcvd); |
289 | 0 | lua_push_uint64_table_entry(vm, "icmp.echo_reply_pkts_sent", |
290 | 0 | icmp_s.echo_reply_packets_sent); |
291 | 0 | lua_push_uint64_table_entry(vm, "icmp.echo_reply_pkts_rcvd", |
292 | 0 | icmp_s.echo_reply_packets_rcvd); |
293 | 0 | } |
294 | |
|
295 | 0 | luaHostBehaviour(vm); |
296 | 0 | } |
297 | | |
298 | | /* *************************************** */ |
299 | | |
300 | | void LocalHostStats::incStats(time_t when, u_int8_t l4_proto, u_int ndpi_proto, |
301 | | ndpi_protocol_category_t ndpi_category, |
302 | | custom_app_t custom_app, u_int64_t sent_packets, |
303 | | u_int64_t sent_bytes, |
304 | | u_int64_t sent_goodput_bytes, |
305 | | u_int64_t rcvd_packets, u_int64_t rcvd_bytes, |
306 | | u_int64_t rcvd_goodput_bytes, |
307 | 18.4k | bool peer_is_unicast) { |
308 | 18.4k | HostStats::incStats(when, l4_proto, ndpi_proto, ndpi_category, custom_app, |
309 | 18.4k | sent_packets, sent_bytes, sent_goodput_bytes, |
310 | 18.4k | rcvd_packets, rcvd_bytes, rcvd_goodput_bytes, |
311 | 18.4k | peer_is_unicast); |
312 | | |
313 | 18.4k | if (l4_proto == IPPROTO_UDP) { |
314 | 4.36k | if (peer_is_unicast) |
315 | 2.77k | udp_sent_unicast += sent_bytes; |
316 | 1.59k | else |
317 | 1.59k | udp_sent_non_unicast += sent_bytes; |
318 | 4.36k | } |
319 | 18.4k | } |
320 | | |
321 | | /* *************************************** */ |
322 | | |
323 | 0 | void LocalHostStats::removeRedisSitesKey() { |
324 | 0 | char additional_key_info[128]; |
325 | |
|
326 | 0 | if (!host->get_mac() && !host->get_ip()) return; |
327 | | |
328 | | /* String like `_1.1.1.1@2` */ |
329 | 0 | snprintf(additional_key_info, sizeof(additional_key_info), "%s_", |
330 | 0 | host->get_tskey(additional_key_info, sizeof(additional_key_info))); |
331 | | /* Deserializing the info */ |
332 | 0 | top_sites->serializeDeserialize( |
333 | 0 | host->getInterface()->get_id(), false, additional_key_info, |
334 | 0 | (char*)HASHKEY_TOP_SITES_SERIALIZATION_KEY, |
335 | 0 | (char*)HASHKEY_LOCAL_HOSTS_TOP_SITES_HOUR_KEYS_PUSHED, |
336 | 0 | (char*)HASHKEY_LOCAL_HOSTS_TOP_SITES_DAY_KEYS_PUSHED); |
337 | 0 | } |
338 | | |
339 | | /* *************************************** */ |
340 | | |
341 | 0 | void LocalHostStats::addRedisSitesKey() { |
342 | 0 | char additional_key_info[128]; |
343 | |
|
344 | 0 | if (!host->get_mac() && !host->get_ip()) return; |
345 | | |
346 | | /* String like `_1.1.1.1@2` */ |
347 | 0 | snprintf(additional_key_info, sizeof(additional_key_info), "%s_", |
348 | 0 | host->get_tskey(additional_key_info, sizeof(additional_key_info))); |
349 | | /* Serializing the info */ |
350 | 0 | top_sites->serializeDeserialize( |
351 | 0 | host->getInterface()->get_id(), true, additional_key_info, |
352 | 0 | (char*)HASHKEY_TOP_SITES_SERIALIZATION_KEY, |
353 | 0 | (char*)HASHKEY_LOCAL_HOSTS_TOP_SITES_HOUR_KEYS_PUSHED, |
354 | 0 | (char*)HASHKEY_LOCAL_HOSTS_TOP_SITES_DAY_KEYS_PUSHED); |
355 | 0 | } |