ntopng/src/ICMPstats.cpp

200 lines
5.6 KiB
C++

/*
*
* (C) 2013-20 - 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"
/* *************************************** */
ICMPstats::ICMPstats() {
num_destination_unreachable.reset();
}
/* *************************************** */
ICMPstats::~ICMPstats() {
std::map<u_int16_t, ICMPstats_t>::const_iterator it;
for(it = stats.begin(); it != stats.end(); ++it) {
if(it->second.last_host_sent_peer) free(it->second.last_host_sent_peer);
if(it->second.last_host_rcvd_peer) free(it->second.last_host_rcvd_peer);
}
stats.clear();
}
/* *************************************** */
void ICMPstats::incStats(u_int32_t num_pkts, u_int8_t icmp_type, u_int8_t icmp_code, bool sent, Host *peer) {
std::map<u_int16_t, ICMPstats_t>::const_iterator it;
ICMPstats_t s;
u_int16_t key = get_typecode(icmp_type, icmp_code);
char buf[64];
if(!num_pkts)
return;
m.lock(__FILE__, __LINE__);
if((it = stats.find(key)) != stats.end())
s = it->second;
else
memset(&s, 0, sizeof(s));
if(icmp_type == ICMP_DEST_UNREACH)
num_destination_unreachable.inc(num_pkts);
if(sent) {
s.pkt_sent += num_pkts;
if(peer) {
if(s.last_host_sent_peer) free(s.last_host_sent_peer);
s.last_host_sent_peer = strdup(peer->get_string_key(buf, sizeof(buf)));
}
} else {
s.pkt_rcvd += num_pkts;
if(peer) {
if(s.last_host_rcvd_peer) free(s.last_host_rcvd_peer);
s.last_host_rcvd_peer = strdup(peer->get_string_key(buf, sizeof(buf)));
}
}
stats[key] = s;
m.unlock(__FILE__, __LINE__);
};
/* *************************************** */
void ICMPstats::addToTable(const char *label, lua_State *vm, const ICMPstats_t *curr, bool verbose) {
lua_newtable(vm);
lua_push_uint64_table_entry(vm, "sent", curr->pkt_sent);
if(verbose)
lua_push_str_table_entry(vm, "last_host_sent_peer", curr->last_host_sent_peer);
lua_push_uint64_table_entry(vm, "rcvd", curr->pkt_rcvd);
if(verbose)
lua_push_str_table_entry(vm, "last_host_rcvd_peer", curr->last_host_rcvd_peer);
lua_pushstring(vm, label);
lua_insert(vm, -2);
lua_settable(vm, -3);
}
/* ******************************************* */
void ICMPstats::updateStats(const struct timeval * const tv) {
time_t when = tv->tv_sec;
num_destination_unreachable.computeAnomalyIndex(when);
#if 0
char buf[64];
ntop->getTrace()->traceEvent(TRACE_NORMAL, "num_destination_unreachable: %s",
num_destination_unreachable.print(buf, sizeof(buf)));
#endif
}
/* *************************************** */
void ICMPstats::lua(bool isV4, lua_State *vm, bool verbose) {
std::map<u_int16_t, ICMPstats_t>::const_iterator it;
m.lock(__FILE__, __LINE__);
lua_newtable(vm);
for(it = stats.begin(); it != stats.end(); ++it) {
u_int8_t icmp_type, icmp_code;
char label[32];
to_typecode(it->first, &icmp_type, &icmp_code);
snprintf(label, sizeof(label), "%u,%u", icmp_type, icmp_code);
addToTable(label, vm, &it->second, verbose);
}
m.unlock(__FILE__, __LINE__);
lua_pushstring(vm, isV4 ? "ICMPv4" : "ICMPv6");
lua_insert(vm, -2);
lua_settable(vm, -3);
}
/* *************************************** */
bool ICMPstats::hasAnomalies(time_t when) {
return num_destination_unreachable.is_misbehaving(when);
}
/* *************************************** */
void ICMPstats::luaAnomalies(lua_State *vm, time_t when) {
if(num_destination_unreachable.is_misbehaving(when))
num_destination_unreachable.lua(vm, "icmp.num_destination_unreachable");
}
/* *************************************** */
void ICMPstats::sum(ICMPstats *e) {
std::map<u_int16_t, ICMPstats_t>::const_iterator orig_it;
for(orig_it = e->stats.begin(); orig_it != e->stats.end(); ++orig_it) {
std::map<u_int16_t, ICMPstats_t>::const_iterator it;
ICMPstats_t s;
u_int16_t key = orig_it->first;
const ICMPstats_t *curr = &orig_it->second;
if((it = stats.find(key)) != stats.end())
s = it->second;
else
memset(&s, 0, sizeof(s));
s.pkt_sent = curr->pkt_sent, s.pkt_rcvd = curr->pkt_rcvd;
if(curr->last_host_sent_peer && (! s.last_host_sent_peer))
s.last_host_sent_peer = strdup(curr->last_host_sent_peer);
if(curr->last_host_rcvd_peer && (! s.last_host_rcvd_peer))
s.last_host_rcvd_peer = strdup(curr->last_host_rcvd_peer);
stats[key] = s;
}
}
/* *************************************** */
/* Get minimal stats required by the timeseries */
void ICMPstats::getTsStats(ts_icmp_stats *s) {
u_int16_t echo_key = get_typecode(8, 0);
u_int16_t echo_reply_key = get_typecode(0, 0);
std::map<u_int16_t, ICMPstats_t>::const_iterator it;
m.lock(__FILE__, __LINE__);
if((it = stats.find(echo_key)) != stats.end()) {
s->echo_packets_sent = it->second.pkt_sent;
s->echo_packets_rcvd = it->second.pkt_rcvd;
}
if((it = stats.find(echo_reply_key)) != stats.end()) {
s->echo_reply_packets_sent = it->second.pkt_sent;
s->echo_reply_packets_rcvd = it->second.pkt_rcvd;
}
m.unlock(__FILE__, __LINE__);
}