#include #include // This class keeps all our counters for specific traffic type class traffic_counter_element_t { public: uint64_t in_bytes = 0; uint64_t out_bytes = 0; uint64_t in_packets = 0; uint64_t out_packets = 0; void zeroify() { in_bytes = 0; out_bytes = 0; in_packets = 0; out_packets = 0; } // Returns zero when all counters are zero bool is_zero() const { return in_bytes == 0 && out_bytes == 0 && in_packets == 0 && out_packets == 0; } // This function compares value in object with passed value and updates our object value to it if it passed value exceeds value we have in place void update_if_larger(const traffic_counter_element_t& another_value) { if (another_value.in_bytes > this->in_bytes) { this->in_bytes = another_value.in_bytes; } if (another_value.out_bytes > this->out_bytes) { this->out_bytes = another_value.out_bytes; } if (another_value.in_packets > this->in_packets) { this->in_packets = another_value.in_packets; } if (another_value.out_packets > this->out_packets) { this->out_packets = another_value.out_packets; } } template void serialize(Archive& ar, [[maybe_unused]] const unsigned int version) { ar& BOOST_SERIALIZATION_NVP(in_bytes); ar& BOOST_SERIALIZATION_NVP(out_bytes); ar& BOOST_SERIALIZATION_NVP(in_packets); ar& BOOST_SERIALIZATION_NVP(out_packets); } // Calculates speed for all counters from input data counter void calculate_speed(const traffic_counter_element_t& traffic_counter, double speed_calc_period) { this->in_packets = uint64_t((double)traffic_counter.in_packets / speed_calc_period); this->out_packets = uint64_t((double)traffic_counter.out_packets / speed_calc_period); this->in_bytes = uint64_t((double)traffic_counter.in_bytes / speed_calc_period); this->out_bytes = uint64_t((double)traffic_counter.out_bytes / speed_calc_period); } // Calculates exponential moving average speed from instant speed void calulate_exponential_moving_average_speed(const traffic_counter_element_t& new_speed_element, double exp_value) { // Bytes counters this->in_bytes = uint64_t(new_speed_element.in_bytes + exp_value * ((double)this->in_bytes - (double)new_speed_element.in_bytes)); this->out_bytes = uint64_t(new_speed_element.out_bytes + exp_value * ((double)this->out_bytes - (double)new_speed_element.out_bytes)); // Packet counters this->in_packets = uint64_t(new_speed_element.in_packets + exp_value * ((double)this->in_packets - (double)new_speed_element.in_packets)); this->out_packets = uint64_t(new_speed_element.out_packets + exp_value * ((double)this->out_packets - (double)new_speed_element.out_packets)); } }; // Main data structure for storing traffic and speed data for all our IPs class subnet_counter_t { public: // We use inaccurate time source for it because we do not care about precise time in this case time_t last_update_time = 0; traffic_counter_element_t total; traffic_counter_element_t tcp; traffic_counter_element_t udp; traffic_counter_element_t icmp; traffic_counter_element_t fragmented; traffic_counter_element_t tcp_syn; // Total number of dropped traffic traffic_counter_element_t dropped; // Updates specific value if any of fields from another_value exceed values in our object void update_if_larger(const subnet_counter_t& another_value) { this->total.update_if_larger(another_value.total); this->tcp.update_if_larger(another_value.tcp); this->udp.update_if_larger(another_value.udp); this->icmp.update_if_larger(another_value.icmp); this->fragmented.update_if_larger(another_value.fragmented); this->tcp_syn.update_if_larger(another_value.tcp_syn); this->dropped.update_if_larger(another_value.dropped); if (in_flows < another_value.in_flows) { this->in_flows = another_value.in_flows; } if (out_flows < another_value.out_flows) { this->out_flows = another_value.out_flows; } } uint64_t in_flows = 0; uint64_t out_flows = 0; // Is total counters fields are zero? We are not handling per protocol counters here because we assume they should // be counted twice // Once: in total counter (in_bytes) and secondly in per protocol counter (for example: udp_in_bytes) bool is_zero() const { return total.in_bytes == 0 && total.out_bytes == 0 && total.in_packets == 0 && total.out_packets == 0 && in_flows == 0 && out_flows == 0; } // Fill all counters by zeros void zeroify() { total.zeroify(); dropped.zeroify(); tcp.zeroify(); udp.zeroify(); icmp.zeroify(); fragmented.zeroify(); tcp_syn.zeroify(); in_flows = 0; out_flows = 0; } template void serialize(Archive& ar, [[maybe_unused]] const unsigned int version) { ar& BOOST_SERIALIZATION_NVP(total); ar& BOOST_SERIALIZATION_NVP(dropped); ar& BOOST_SERIALIZATION_NVP(tcp); ar& BOOST_SERIALIZATION_NVP(udp); ar& BOOST_SERIALIZATION_NVP(icmp); ar& BOOST_SERIALIZATION_NVP(fragmented); ar& BOOST_SERIALIZATION_NVP(tcp_syn); ar& BOOST_SERIALIZATION_NVP(in_flows); ar& BOOST_SERIALIZATION_NVP(out_flows); } };