Introduced fastnetmon_logic which will keep keep all business logic functions (#869)

This commit is contained in:
Pavel Odintsov 2020-10-31 14:22:22 +00:00 committed by GitHub
parent 0f1e645693
commit 3ead151c1d
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 921 additions and 847 deletions

@ -212,9 +212,14 @@ target_link_libraries(unified_parser fastnetmon_packet_parser)
# Our ipfix database library
add_library(ipfix_rfc STATIC ipfix_rfc.cpp)
add_library(bgp_protocol bgp_flow_spec.cpp)
# Our packet parser
add_library(fastnetmon_packet_parser STATIC fastnetmon_packet_parser.c)
# Our logic library
add_library(fastnetmon_logic STATIC fastnetmon_logic.cpp)
CHECK_CXX_SOURCE_COMPILES("
#include <linux/if_packet.h>
int main() {
@ -596,6 +601,8 @@ target_link_libraries(fastnetmon fastnetmon_pcap_format)
target_link_libraries(fastnetmon ipfix_rfc)
target_link_libraries(fastnetmon_logic bgp_protocol)
# Link to our functions
target_link_libraries(fastnetmon fast_library)
@ -620,6 +627,8 @@ endif()
target_link_libraries(fastnetmon sflow_plugin netflow_plugin pcap_plugin example_plugin)
target_link_libraries(fastnetmon fastnetmon_logic)
if (ENABLE_NETMAP_SUPPORT)
target_link_libraries(fastnetmon netmap_plugin)
endif()

@ -8,3 +8,58 @@
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/PatternLayout.hh"
#include "log4cpp/Priority.hh"
// Enable custom casts from our own types
std::ostream& operator<<(std::ostream& os, bgp_flow_spec_protocol_t const& protocol) {
if (protocol == FLOW_SPEC_PROTOCOL_UDP) {
return os << "udp";
} else if (protocol == FLOW_SPEC_PROTOCOL_TCP) {
return os << "tcp";
} else if (protocol == FLOW_SPEC_PROTOCOL_ICMP) {
return os << "icmp";
} else {
return os;
}
}
void exabgp_flow_spec_rule_ban_manage(std::string action, flow_spec_rule_t flow_spec_rule) {
// "announce flow route {\\n match {\\n source 10.0.0.1/32;\\nsource-port =" + str(i) +
// ";\\n destination 1.2.3.4/32;\\n }\\n then {\\n discard;\\n }\\n }\\n\n")
}
std::ostream& operator<<(std::ostream& os, flow_spec_tcp_flags_t const& tcp_flag) {
if (tcp_flag == FLOW_TCP_FLAG_SYN) {
return os << "syn";
} else if (tcp_flag == FLOW_TCP_FLAG_ACK) {
return os << "ack";
} else if (tcp_flag == FLOW_TCP_FLAG_FIN) {
return os << "fin";
} else if (tcp_flag == FLOW_TCP_FLAG_URG) {
return os << "urgent";
} else if (tcp_flag == FLOW_TCP_FLAG_PSH) {
return os << "push";
} else if (tcp_flag == FLOW_TCP_FLAG_RST) {
return os << "rst";
} else {
return os;
}
}
std::ostream& operator<<(std::ostream& os, flow_spec_fragmentation_types_t const& fragment_flag) {
// Nice docs here: https://github.com/Exa-Networks/exabgp/blob/71157d560096ec20084cf96cfe0f60203721e93b/lib/exabgp/protocol/ip/fragment.py
if (fragment_flag == FLOW_SPEC_DONT_FRAGMENT) {
return os << "dont-fragment";
} else if (fragment_flag == FLOW_SPEC_IS_A_FRAGMENT) {
return os << "is-fragment";
} else if (fragment_flag == FLOW_SPEC_FIRST_FRAGMENT) {
return os << "first-fragment";
} else if (fragment_flag == FLOW_SPEC_LAST_FRAGMENT) {
return os << "last-fragment";
} else if (fragment_flag == FLOW_NOT_A_FRAGMENT) {
return os << "not-a-fragment";
} else {
return os;
}
}

@ -65,53 +65,11 @@ enum bgp_flow_spec_protocol_t {
};
// Enable custom casts from our own types
std::ostream& operator<<(std::ostream& os, bgp_flow_spec_protocol_t const& protocol) {
if (protocol == FLOW_SPEC_PROTOCOL_UDP) {
return os << "udp";
} else if (protocol == FLOW_SPEC_PROTOCOL_TCP) {
return os << "tcp";
} else if (protocol == FLOW_SPEC_PROTOCOL_ICMP) {
return os << "icmp";
} else {
return os;
}
}
std::ostream& operator<<(std::ostream& os, bgp_flow_spec_protocol_t const& protocol);
std::ostream& operator<<(std::ostream& os, flow_spec_fragmentation_types_t const& fragment_flag) {
// Nice docs here: https://github.com/Exa-Networks/exabgp/blob/71157d560096ec20084cf96cfe0f60203721e93b/lib/exabgp/protocol/ip/fragment.py
std::ostream& operator<<(std::ostream& os, flow_spec_fragmentation_types_t const& fragment_flag);
if (fragment_flag == FLOW_SPEC_DONT_FRAGMENT) {
return os << "dont-fragment";
} else if (fragment_flag == FLOW_SPEC_IS_A_FRAGMENT) {
return os << "is-fragment";
} else if (fragment_flag == FLOW_SPEC_FIRST_FRAGMENT) {
return os << "first-fragment";
} else if (fragment_flag == FLOW_SPEC_LAST_FRAGMENT) {
return os << "last-fragment";
} else if (fragment_flag == FLOW_NOT_A_FRAGMENT) {
return os << "not-a-fragment";
} else {
return os;
}
}
std::ostream& operator<<(std::ostream& os, flow_spec_tcp_flags_t const& tcp_flag) {
if (tcp_flag == FLOW_TCP_FLAG_SYN) {
return os << "syn";
} else if (tcp_flag == FLOW_TCP_FLAG_ACK) {
return os << "ack";
} else if (tcp_flag == FLOW_TCP_FLAG_FIN) {
return os << "fin";
} else if (tcp_flag == FLOW_TCP_FLAG_URG) {
return os << "urgent";
} else if (tcp_flag == FLOW_TCP_FLAG_PSH) {
return os << "push";
} else if (tcp_flag == FLOW_TCP_FLAG_RST) {
return os << "rst";
} else {
return os;
}
}
std::ostream& operator<<(std::ostream& os, flow_spec_tcp_flags_t const& tcp_flag);
class bgp_flow_spec_action_t {
public:
@ -564,10 +522,6 @@ class exabgp_flow_spec_rule_t : public flow_spec_rule_t {
std::string sentence_separator;
};
void exabgp_flow_spec_rule_ban_manage(std::string action, flow_spec_rule_t flow_spec_rule) {
// "announce flow route {\\n match {\\n source 10.0.0.1/32;\\nsource-port =" + str(i) +
// ";\\n destination 1.2.3.4/32;\\n }\\n then {\\n discard;\\n }\\n }\\n\n")
}
void exabgp_flow_spec_rule_ban_manage(std::string action, flow_spec_rule_t flow_spec_rule);
#endif

@ -1,27 +1,27 @@
#ifndef FAST_PLATFORM_H
#define FAST_PLATFORM_H
#pragma once
// This file automatically generated for your platform (Linux, FreeBSD and others) with cmake
/* Platform specific paths */
class FastnetmonPlatformConfigurtion {
public:
std::string fastnetmon_version = "${FASTNETMON_APPLICATION_VERSION}";
/* Platform specific paths */
std::string fastnetmon_version = "${FASTNETMON_APPLICATION_VERSION}";
std::string pid_path = "/var/run/fastnetmon.pid";
std::string global_config_path = "/etc/fastnetmon.conf";
std::string pid_path = "/var/run/fastnetmon.pid";
std::string global_config_path = "/etc/fastnetmon.conf";
std::string log_file_path = "/var/log/fastnetmon.log";
std::string attack_details_folder = "/var/log/fastnetmon_attacks";
std::string log_file_path = "/var/log/fastnetmon.log";
std::string attack_details_folder = "/var/log/fastnetmon_attacks";
// Default path to notify script
std::string notify_script_path = "/usr/local/bin/notify_about_attack.sh";
// Default path to notify script
std::string notify_script_path = "/usr/local/bin/notify_about_attack.sh";
// Default path to file with networks for whitelising
std::string white_list_path = "/etc/networks_whitelist";
// Default path to file with networks for whitelising
std::string white_list_path = "/etc/networks_whitelist";
// Default path to file with all networks listing
std::string networks_list_path = "/etc/networks_list";
// Default path to file with all networks listing
std::string networks_list_path = "/etc/networks_list";
/* Platform specific paths end */
#endif
/* Platform specific paths end */
};

@ -33,6 +33,8 @@
// Here we store variables which differs for different paltforms
#include "fast_platform.h"
#include "fastnetmon_logic.hpp"
#ifdef ENABLE_DPI
#include "fast_dpi.h"
#endif
@ -145,6 +147,8 @@ bool process_internal_traffic_as_external = false;
unsigned int recalculate_speed_timeout = 1;
FastnetmonPlatformConfigurtion fastnetmon_platform_configuration;
// Send or not any details about attack for ban script call over stdin
bool notify_script_pass_details = true;
@ -166,7 +170,6 @@ logging_configuration_t logging_configuration;
std::string screen_data_stats = "";
// Global map with parsed config file
typedef std::map<std::string, std::string> configuration_map_t;
configuration_map_t configuration_map;
// Every X seconds we will run ban list cleaner thread
@ -430,13 +433,6 @@ bool process_outgoing_traffic = true;
void init_current_instance_of_ndpi();
#endif
inline void build_average_speed_counters_from_speed_counters(map_element* current_average_speed_element,
map_element& new_speed_element,
double exp_value,
double exp_power);
inline void build_speed_counters_from_packet_counters(map_element& new_speed_element,
map_element* vector_itr,
double speed_calc_period);
void execute_ip_ban(uint32_t client_ip, map_element average_speed_element, std::string flow_attack_details, subnet_t customer_subnet);
std::string get_attack_description_in_json(uint32_t client_ip, attack_details& current_attack);
logging_configuration_t read_logging_settings(configuration_map_t configuration_map);
@ -587,50 +583,6 @@ void RunApiServer() {
}
#endif
/* Class for custom comparison fields by different fields */
template <typename T> class TrafficComparatorClass {
private:
sort_type sort_field;
direction_t sort_direction;
public:
TrafficComparatorClass(direction_t sort_direction, sort_type sort_field) {
this->sort_field = sort_field;
this->sort_direction = sort_direction;
}
bool operator()(T a, T b) {
if (sort_field == FLOWS) {
if (sort_direction == INCOMING) {
return a.second.in_flows > b.second.in_flows;
} else if (sort_direction == OUTGOING) {
return a.second.out_flows > b.second.out_flows;
} else {
return false;
}
} else if (sort_field == PACKETS) {
if (sort_direction == INCOMING) {
return a.second.in_packets > b.second.in_packets;
} else if (sort_direction == OUTGOING) {
return a.second.out_packets > b.second.out_packets;
} else {
return false;
}
} else if (sort_field == BYTES) {
if (sort_direction == INCOMING) {
return a.second.in_bytes > b.second.in_bytes;
} else if (sort_direction == OUTGOING) {
return a.second.out_bytes > b.second.out_bytes;
} else {
return false;
}
} else {
return false;
}
}
};
void sigpipe_handler_for_popen(int signo) {
logger
<< log4cpp::Priority::ERROR << "Sorry but we experienced error with popen. "
@ -1050,7 +1002,7 @@ void parse_hostgroups(std::string name, std::string value) {
// Load configuration
bool load_configuration_file() {
std::ifstream config_file(global_config_path.c_str());
std::ifstream config_file(fastnetmon_platform_configuration.global_config_path.c_str());
std::string line;
if (!config_file.is_open()) {
@ -1108,7 +1060,7 @@ bool load_configuration_file() {
}
if (configuration_map.count("pid_path") != 0) {
pid_path = configuration_map["pid_path"];
fastnetmon_platform_configuration.pid_path = configuration_map["pid_path"];
}
if (configuration_map.count("cli_stats_file_path") != 0) {
@ -1352,11 +1304,11 @@ bool load_configuration_file() {
}
if (configuration_map.count("white_list_path") != 0) {
white_list_path = configuration_map["white_list_path"];
fastnetmon_platform_configuration.white_list_path = configuration_map["white_list_path"];
}
if (configuration_map.count("networks_list_path") != 0) {
networks_list_path = configuration_map["networks_list_path"];
fastnetmon_platform_configuration.networks_list_path = configuration_map["networks_list_path"];
}
#ifdef REDIS
@ -1421,17 +1373,17 @@ bool load_configuration_file() {
}
if (configuration_map.count("notify_script_path") != 0) {
notify_script_path = configuration_map["notify_script_path"];
fastnetmon_platform_configuration.notify_script_path = configuration_map["notify_script_path"];
}
if (configuration_map.count("notify_script_pass_details") != 0) {
notify_script_pass_details = configuration_map["notify_script_pass_details"] == "on" ? true : false;
}
if (file_exists(notify_script_path)) {
if (file_exists(fastnetmon_platform_configuration.notify_script_path)) {
notify_script_enabled = true;
} else {
logger << log4cpp::Priority::ERROR << "We can't find notify script " << notify_script_path;
logger << log4cpp::Priority::ERROR << "We can't find notify script " << fastnetmon_platform_configuration.notify_script_path;
notify_script_enabled = false;
}
@ -1538,9 +1490,9 @@ void zeroify_all_flow_counters() {
}
bool load_our_networks_list() {
if (file_exists(white_list_path)) {
if (file_exists(fastnetmon_platform_configuration.white_list_path)) {
unsigned int network_entries = 0;
std::vector<std::string> network_list_from_config = read_file_to_vector(white_list_path);
std::vector<std::string> network_list_from_config = read_file_to_vector(fastnetmon_platform_configuration.white_list_path);
for (std::vector<std::string>::iterator ii = network_list_from_config.begin();
ii != network_list_from_config.end(); ++ii) {
@ -1622,8 +1574,8 @@ bool load_our_networks_list() {
}
}
if (file_exists(networks_list_path)) {
std::vector<std::string> network_list_from_config = read_file_to_vector(networks_list_path);
if (file_exists(fastnetmon_platform_configuration.networks_list_path)) {
std::vector<std::string> network_list_from_config = read_file_to_vector(fastnetmon_platform_configuration.networks_list_path);
for (std::vector<std::string>::iterator line_itr = network_list_from_config.begin();
line_itr != network_list_from_config.end(); ++line_itr) {
@ -2577,7 +2529,7 @@ void traffic_draw_program() {
sorter = PACKETS;
}
output_buffer << "FastNetMon " << fastnetmon_version << " Try Advanced edition: https://fastnetmon.com"
output_buffer << "FastNetMon " << fastnetmon_platform_configuration.fastnetmon_version << " Try Advanced edition: https://fastnetmon.com"
<< "\n"
<< "IPs ordered by: " << sort_parameter << "\n";
@ -2738,8 +2690,8 @@ void init_logging() {
// So log4cpp will never notify you if it could not write to log file due to permissions issues
// We will check it manually
if (!file_is_appendable(log_file_path)) {
std::cerr << "Can't open log file " << log_file_path
if (!file_is_appendable(fastnetmon_platform_configuration.log_file_path)) {
std::cerr << "Can't open log file " << fastnetmon_platform_configuration.log_file_path
<< " for writing! Please check file and folder permissions" << std::endl;
exit(EXIT_FAILURE);
}
@ -2747,7 +2699,7 @@ void init_logging() {
log4cpp::PatternLayout* layout = new log4cpp::PatternLayout();
layout->setConversionPattern("%d [%p] %m%n");
log4cpp::Appender* appender = new log4cpp::FileAppender("default", log_file_path);
log4cpp::Appender* appender = new log4cpp::FileAppender("default", fastnetmon_platform_configuration.log_file_path);
appender->setLayout(layout);
logger.setPriority(log4cpp::Priority::INFO);
@ -2848,7 +2800,7 @@ int main(int argc, char** argv) {
}
if (vm.count("version")) {
std::cout << "Version: " << fastnetmon_version << std::endl;
std::cout << "Version: " << fastnetmon_platform_configuration.fastnetmon_version << std::endl;
exit(EXIT_SUCCESS);
}
@ -2861,13 +2813,13 @@ int main(int argc, char** argv) {
}
if (vm.count("configuration_file")) {
global_config_path = vm["configuration_file"].as<std::string>();
std::cout << "We will use custom path to configuration file: " << global_config_path << std::endl;
fastnetmon_platform_configuration.global_config_path = vm["configuration_file"].as<std::string>();
std::cout << "We will use custom path to configuration file: " << fastnetmon_platform_configuration.global_config_path << std::endl;
}
if (vm.count("log_file")) {
log_file_path = vm["log_file"].as<std::string>();
std::cout << "We will use custom path to log file: " << log_file_path << std::endl;
fastnetmon_platform_configuration.log_file_path = vm["log_file"].as<std::string>();
std::cout << "We will use custom path to log file: " << fastnetmon_platform_configuration.log_file_path << std::endl;
}
} catch (po::error& e) {
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
@ -2917,7 +2869,7 @@ int main(int argc, char** argv) {
bool load_config_result = load_configuration_file();
if (!load_config_result) {
std::cerr << "Can't open config file " << global_config_path << " please create it!" << std::endl;
std::cerr << "Can't open config file " << fastnetmon_platform_configuration.global_config_path << " please create it!" << std::endl;
exit(1);
}
@ -2926,10 +2878,10 @@ int main(int argc, char** argv) {
exit(0);
}
if (file_exists(pid_path)) {
if (file_exists(fastnetmon_platform_configuration.pid_path)) {
pid_t pid_from_file = 0;
if (read_pid_from_file(pid_from_file, pid_path)) {
if (read_pid_from_file(pid_from_file, fastnetmon_platform_configuration.pid_path)) {
// We could read pid
if (pid_from_file > 0) {
// We use signal zero for check process existence
@ -2953,10 +2905,10 @@ int main(int argc, char** argv) {
}
// If we not failed in check steps we could run toolkit
bool print_pid_to_file_result = print_pid_to_file(getpid(), pid_path);
bool print_pid_to_file_result = print_pid_to_file(getpid(), fastnetmon_platform_configuration.pid_path);
if (!print_pid_to_file_result) {
logger << log4cpp::Priority::ERROR << "Could not create pid file, please check permissions: " << pid_path;
logger << log4cpp::Priority::ERROR << "Could not create pid file, please check permissions: " << fastnetmon_platform_configuration.pid_path;
exit(EXIT_FAILURE);
}
@ -2983,11 +2935,11 @@ int main(int argc, char** argv) {
}
/* Create folder for attack details */
if (!folder_exists(attack_details_folder)) {
int mkdir_result = mkdir(attack_details_folder.c_str(), S_IRWXU);
if (!folder_exists(fastnetmon_platform_configuration.attack_details_folder)) {
int mkdir_result = mkdir(fastnetmon_platform_configuration.attack_details_folder.c_str(), S_IRWXU);
if (mkdir_result != 0) {
logger << log4cpp::Priority::ERROR << "Can't create folder for attack details: " << attack_details_folder;
logger << log4cpp::Priority::ERROR << "Can't create folder for attack details: " << fastnetmon_platform_configuration.attack_details_folder;
exit(1);
}
}
@ -3440,7 +3392,7 @@ void call_ban_handlers(uint32_t client_ip, attack_details& current_attack, std::
}
if (notify_script_enabled) {
std::string script_call_params = notify_script_path + " " + client_ip_as_string + " " +
std::string script_call_params = fastnetmon_platform_configuration.notify_script_path + " " + client_ip_as_string + " " +
data_direction_as_string + " " + pps_as_string + " " + "ban";
logger << log4cpp::Priority::INFO << "Call script for ban client: " << client_ip_as_string;
@ -3634,7 +3586,7 @@ void call_unban_handlers(uint32_t client_ip, attack_details& current_attack) {
std::string data_direction_as_string = get_direction_name(current_attack.attack_direction);
std::string pps_as_string = convert_int_to_string(current_attack.attack_power);
std::string script_call_params = notify_script_path + " " + client_ip_as_string + " " +
std::string script_call_params = fastnetmon_platform_configuration.notify_script_path + " " + client_ip_as_string + " " +
data_direction_as_string + " " + pps_as_string + " unban";
logger << log4cpp::Priority::INFO << "Call script for unban client: " << client_ip_as_string;
@ -4046,7 +3998,7 @@ void call_attack_details_handlers(uint32_t client_ip, attack_details& current_at
// We place this variables here because we need this paths from DPI parser code
std::string ban_timestamp_as_string = print_time_t_in_fastnetmon_format(current_attack.ban_timestamp);
std::string attack_pcap_dump_path =
attack_details_folder + "/" + client_ip_as_string + "_" + ban_timestamp_as_string + ".pcap";
fastnetmon_platform_configuration.attack_details_folder + "/" + client_ip_as_string + "_" + ban_timestamp_as_string + ".pcap";
if (collect_attack_pcap_dumps) {
int pcap_fump_filedesc = open(attack_pcap_dump_path.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
@ -4089,7 +4041,7 @@ void call_attack_details_handlers(uint32_t client_ip, attack_details& current_at
logger << log4cpp::Priority::INFO
<< "Call script for notify about attack details for: " << client_ip_as_string;
std::string script_params = notify_script_path + " " + client_ip_as_string + " " +
std::string script_params = fastnetmon_platform_configuration.notify_script_path + " " + client_ip_as_string + " " +
attack_direction + " " + pps_as_string + " attack_details";
// We should execute external script in separate thread because any lag in this code
@ -4123,48 +4075,6 @@ uint64_t convert_conntrack_hash_struct_to_integer(packed_conntrack_hash* struct_
return unpacked_data;
}
void convert_integer_to_conntrack_hash_struct(packed_session* packed_connection_data,
packed_conntrack_hash* unpacked_data) {
memcpy(unpacked_data, packed_connection_data, sizeof(uint64_t));
}
std::string print_flow_tracking_for_specified_protocol(contrack_map_type& protocol_map,
std::string client_ip,
direction_t flow_direction) {
std::stringstream buffer;
// We shoud iterate over all fields
int printed_records = 0;
for (contrack_map_type::iterator itr = protocol_map.begin(); itr != protocol_map.end(); ++itr) {
// We should limit number of records in flow dump because syn flood attacks produce
// thounsands of lines
if (printed_records > ban_details_records_count) {
buffer << "Flows have cropped due to very long list.\n";
break;
}
uint64_t packed_connection_data = itr->first;
packed_conntrack_hash unpacked_key_struct;
convert_integer_to_conntrack_hash_struct(&packed_connection_data, &unpacked_key_struct);
std::string opposite_ip_as_string = convert_ip_as_uint_to_string(unpacked_key_struct.opposite_ip);
if (flow_direction == INCOMING) {
buffer << client_ip << ":" << unpacked_key_struct.dst_port << " < "
<< opposite_ip_as_string << ":" << unpacked_key_struct.src_port << " ";
} else if (flow_direction == OUTGOING) {
buffer << client_ip << ":" << unpacked_key_struct.src_port << " > "
<< opposite_ip_as_string << ":" << unpacked_key_struct.dst_port << " ";
}
buffer << itr->second.bytes << " bytes " << itr->second.packets << " packets";
buffer << "\n";
printed_records++;
}
return buffer.str();
}
/*
Attack types:
- syn flood: one local port, multiple remote hosts (and maybe multiple remote ports) and
@ -4198,654 +4108,3 @@ bool process_flow_tracking_table(conntrack_main_struct& conntrack_element, std::
return true;
}
std::string print_flow_tracking_for_ip(conntrack_main_struct& conntrack_element, std::string client_ip) {
std::stringstream buffer;
std::string in_tcp =
print_flow_tracking_for_specified_protocol(conntrack_element.in_tcp, client_ip, INCOMING);
std::string in_udp =
print_flow_tracking_for_specified_protocol(conntrack_element.in_udp, client_ip, INCOMING);
unsigned long long total_number_of_incoming_tcp_flows = conntrack_element.in_tcp.size();
unsigned long long total_number_of_incoming_udp_flows = conntrack_element.in_udp.size();
unsigned long long total_number_of_outgoing_tcp_flows = conntrack_element.out_tcp.size();
unsigned long long total_number_of_outgoing_udp_flows = conntrack_element.out_udp.size();
bool we_have_incoming_flows = in_tcp.length() > 0 or in_udp.length() > 0;
if (we_have_incoming_flows) {
buffer << "Incoming\n\n";
if (in_tcp.length() > 0) {
buffer << "TCP flows: " << total_number_of_incoming_tcp_flows << "\n";
buffer << in_tcp << "\n";
}
if (in_udp.length() > 0) {
buffer << "UDP flows: " << total_number_of_incoming_udp_flows << "\n";
buffer << in_udp << "\n";
}
}
std::string out_tcp =
print_flow_tracking_for_specified_protocol(conntrack_element.out_tcp, client_ip, OUTGOING);
std::string out_udp =
print_flow_tracking_for_specified_protocol(conntrack_element.out_udp, client_ip, OUTGOING);
bool we_have_outgoing_flows = out_tcp.length() > 0 or out_udp.length() > 0;
// print delimiter if we have flows in both directions
if (we_have_incoming_flows && we_have_outgoing_flows) {
buffer << "\n";
}
if (we_have_outgoing_flows) {
buffer << "Outgoing\n\n";
if (out_tcp.length() > 0) {
buffer << "TCP flows: " << total_number_of_outgoing_tcp_flows << "\n";
buffer << out_tcp << "\n";
}
if (out_udp.length() > 0) {
buffer << "UDP flows: " << total_number_of_outgoing_udp_flows << "\n";
buffer << out_udp << "\n";
}
}
return buffer.str();
}
std::string print_subnet_load() {
std::stringstream buffer;
sort_type sorter;
if (sort_parameter == "packets") {
sorter = PACKETS;
} else if (sort_parameter == "bytes") {
sorter = BYTES;
} else if (sort_parameter == "flows") {
sorter = FLOWS;
} else {
logger << log4cpp::Priority::INFO << "Unexpected sorter type: " << sort_parameter;
sorter = PACKETS;
}
std::vector<pair_of_map_for_subnet_counters_elements_t> vector_for_sort;
vector_for_sort.reserve(PerSubnetSpeedMap.size());
for (map_for_subnet_counters::iterator itr = PerSubnetSpeedMap.begin();
itr != PerSubnetSpeedMap.end(); ++itr) {
vector_for_sort.push_back(std::make_pair(itr->first, itr->second));
}
std::sort(vector_for_sort.begin(), vector_for_sort.end(),
TrafficComparatorClass<pair_of_map_for_subnet_counters_elements_t>(INCOMING, sorter));
graphite_data_t graphite_data;
for (std::vector<pair_of_map_for_subnet_counters_elements_t>::iterator itr = vector_for_sort.begin();
itr != vector_for_sort.end(); ++itr) {
map_element* speed = &itr->second;
std::string subnet_as_string = convert_subnet_to_string(itr->first);
buffer << std::setw(18) << std::left << subnet_as_string;
if (graphite_enabled) {
std::string subnet_as_string_as_dash_delimiters = subnet_as_string;
// Replace dots by dashes
std::replace(subnet_as_string_as_dash_delimiters.begin(),
subnet_as_string_as_dash_delimiters.end(), '.', '_');
// Replace / by dashes too
std::replace(subnet_as_string_as_dash_delimiters.begin(),
subnet_as_string_as_dash_delimiters.end(), '/', '_');
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".incoming.pps"] =
speed->in_packets;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".outgoing.pps"] =
speed->out_packets;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".incoming.bps"] =
speed->in_bytes * 8;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".outgoing.bps"] =
speed->out_bytes * 8;
}
buffer << " "
<< "pps in: " << std::setw(8) << speed->in_packets << " out: " << std::setw(8)
<< speed->out_packets << " mbps in: " << std::setw(5) << convert_speed_to_mbps(speed->in_bytes)
<< " out: " << std::setw(5) << convert_speed_to_mbps(speed->out_bytes) << "\n";
}
if (graphite_enabled) {
bool graphite_put_result = store_data_to_graphite(graphite_port, graphite_host, graphite_data);
if (!graphite_put_result) {
logger << log4cpp::Priority::ERROR << "Can't store network load data to Graphite";
}
}
return buffer.str();
}
std::string print_ban_thresholds(ban_settings_t current_ban_settings) {
std::stringstream output_buffer;
output_buffer << "Configuration params:\n";
if (current_ban_settings.enable_ban) {
output_buffer << "We call ban script: yes\n";
} else {
output_buffer << "We call ban script: no\n";
}
output_buffer << "Packets per second: ";
if (current_ban_settings.enable_ban_for_pps) {
output_buffer << current_ban_settings.ban_threshold_pps;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
output_buffer << "Mbps per second: ";
if (current_ban_settings.enable_ban_for_bandwidth) {
output_buffer << current_ban_settings.ban_threshold_mbps;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
output_buffer << "Flows per second: ";
if (current_ban_settings.enable_ban_for_flows_per_second) {
output_buffer << current_ban_settings.ban_threshold_flows;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
return output_buffer.str();
}
void print_attack_details_to_file(std::string details, std::string client_ip_as_string, attack_details current_attack) {
std::ofstream my_attack_details_file;
std::string ban_timestamp_as_string = print_time_t_in_fastnetmon_format(current_attack.ban_timestamp);
std::string attack_dump_path =
attack_details_folder + "/" + client_ip_as_string + "_" + ban_timestamp_as_string + ".txt";
my_attack_details_file.open(attack_dump_path.c_str(), std::ios::app);
if (my_attack_details_file.is_open()) {
my_attack_details_file << details << "\n\n";
my_attack_details_file.close();
} else {
logger << log4cpp::Priority::ERROR << "Can't print attack details to file";
}
}
logging_configuration_t read_logging_settings(configuration_map_t configuration_map) {
logging_configuration_t logging_configuration_temp;
if (configuration_map.count("logging:local_syslog_logging") != 0) {
logging_configuration_temp.local_syslog_logging =
configuration_map["logging:local_syslog_logging"] == "on";
}
if (configuration_map.count("logging:remote_syslog_logging") != 0) {
logging_configuration_temp.remote_syslog_logging =
configuration_map["logging:remote_syslog_logging"] == "on";
}
if (configuration_map.count("logging:remote_syslog_server") != 0) {
logging_configuration_temp.remote_syslog_server =
configuration_map["logging:remote_syslog_server"];
}
if (configuration_map.count("logging:remote_syslog_port") != 0) {
logging_configuration_temp.remote_syslog_port =
convert_string_to_integer(configuration_map["logging:remote_syslog_port"]);
}
if (logging_configuration_temp.remote_syslog_logging) {
if (logging_configuration_temp.remote_syslog_port > 0 &&
!logging_configuration_temp.remote_syslog_server.empty()) {
logger << log4cpp::Priority::INFO << "We have configured remote syslog logging corectly";
} else {
logger << log4cpp::Priority::ERROR << "You have enabled remote logging but haven't specified port or host";
logging_configuration_temp.remote_syslog_logging = false;
}
}
if (logging_configuration_temp.local_syslog_logging) {
logger << log4cpp::Priority::INFO << "We have configured local syslog logging corectly";
}
return logging_configuration_temp;
}
ban_settings_t read_ban_settings(configuration_map_t configuration_map, std::string host_group_name) {
ban_settings_t ban_settings;
std::string prefix = "";
if (host_group_name != "") {
prefix = host_group_name + "_";
}
if (configuration_map.count(prefix + "enable_ban") != 0) {
ban_settings.enable_ban = configuration_map[prefix + "enable_ban"] == "on";
}
if (configuration_map.count(prefix + "ban_for_pps") != 0) {
ban_settings.enable_ban_for_pps = configuration_map[prefix + "ban_for_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_bandwidth") != 0) {
ban_settings.enable_ban_for_bandwidth = configuration_map[prefix + "ban_for_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_flows") != 0) {
ban_settings.enable_ban_for_flows_per_second =
configuration_map[prefix + "ban_for_flows"] == "on";
}
// Per protocol bandwidth triggers
if (configuration_map.count(prefix + "ban_for_tcp_bandwidth") != 0) {
ban_settings.enable_ban_for_tcp_bandwidth =
configuration_map[prefix + "ban_for_tcp_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_udp_bandwidth") != 0) {
ban_settings.enable_ban_for_udp_bandwidth =
configuration_map[prefix + "ban_for_udp_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_icmp_bandwidth") != 0) {
ban_settings.enable_ban_for_icmp_bandwidth =
configuration_map[prefix + "ban_for_icmp_bandwidth"] == "on";
}
// Per protocol pps ban triggers
if (configuration_map.count(prefix + "ban_for_tcp_pps") != 0) {
ban_settings.enable_ban_for_tcp_pps = configuration_map[prefix + "ban_for_tcp_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_udp_pps") != 0) {
ban_settings.enable_ban_for_udp_pps = configuration_map[prefix + "ban_for_udp_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_icmp_pps") != 0) {
ban_settings.enable_ban_for_icmp_pps =
configuration_map[prefix + "ban_for_icmp_pps"] == "on";
}
// Pps per protocol thresholds
if (configuration_map.count(prefix + "threshold_tcp_pps") != 0) {
ban_settings.ban_threshold_tcp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_tcp_pps"]);
}
if (configuration_map.count(prefix + "threshold_udp_pps") != 0) {
ban_settings.ban_threshold_udp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_udp_pps"]);
}
if (configuration_map.count(prefix + "threshold_icmp_pps") != 0) {
ban_settings.ban_threshold_icmp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_icmp_pps"]);
}
// Bandwidth per protocol thresholds
if (configuration_map.count(prefix + "threshold_tcp_mbps") != 0) {
ban_settings.ban_threshold_tcp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_tcp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_udp_mbps") != 0) {
ban_settings.ban_threshold_udp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_udp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_icmp_mbps") != 0) {
ban_settings.ban_threshold_icmp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_icmp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_pps") != 0) {
ban_settings.ban_threshold_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_pps"]);
}
if (configuration_map.count(prefix + "threshold_mbps") != 0) {
ban_settings.ban_threshold_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_mbps"]);
}
if (configuration_map.count(prefix + "threshold_flows") != 0) {
ban_settings.ban_threshold_flows =
convert_string_to_integer(configuration_map[prefix + "threshold_flows"]);
}
return ban_settings;
}
bool exceed_pps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold) {
if (in_counter > threshold or out_counter > threshold) {
return true;
} else {
return false;
}
}
bool exceed_flow_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold) {
if (in_counter > threshold or out_counter > threshold) {
return true;
} else {
return false;
}
}
bool exceed_mbps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold_mbps) {
if (convert_speed_to_mbps(in_counter) > threshold_mbps or convert_speed_to_mbps(out_counter) > threshold_mbps) {
return true;
} else {
return false;
}
}
// Return true when we should ban this IP
bool we_should_ban_this_ip(map_element* average_speed_element, ban_settings_t current_ban_settings) {
// we detect overspeed by packets
if (current_ban_settings.enable_ban_for_pps &&
exceed_pps_speed(average_speed_element->in_packets, average_speed_element->out_packets,
current_ban_settings.ban_threshold_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_bandwidth &&
exceed_mbps_speed(average_speed_element->in_bytes, average_speed_element->out_bytes,
current_ban_settings.ban_threshold_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_flows_per_second &&
exceed_flow_speed(average_speed_element->in_flows, average_speed_element->out_flows,
current_ban_settings.ban_threshold_flows)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by flow limit";
return true;
}
// We could try per protocol thresholds here
// Per protocol pps thresholds
if (current_ban_settings.enable_ban_for_tcp_pps &&
exceed_pps_speed(average_speed_element->tcp_in_packets, average_speed_element->tcp_out_packets,
current_ban_settings.ban_threshold_tcp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by tcp pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_udp_pps &&
exceed_pps_speed(average_speed_element->udp_in_packets, average_speed_element->udp_out_packets,
current_ban_settings.ban_threshold_udp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by udp pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_icmp_pps &&
exceed_pps_speed(average_speed_element->icmp_in_packets, average_speed_element->icmp_out_packets,
current_ban_settings.ban_threshold_icmp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by icmp pps limit";
return true;
}
// Per protocol bandwidth thresholds
if (current_ban_settings.enable_ban_for_tcp_bandwidth &&
exceed_mbps_speed(average_speed_element->tcp_in_bytes, average_speed_element->tcp_out_bytes,
current_ban_settings.ban_threshold_tcp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by tcp mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_udp_bandwidth &&
exceed_mbps_speed(average_speed_element->udp_in_bytes, average_speed_element->udp_out_bytes,
current_ban_settings.ban_threshold_udp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by udp mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_icmp_bandwidth &&
exceed_mbps_speed(average_speed_element->icmp_in_bytes, average_speed_element->icmp_out_bytes,
current_ban_settings.ban_threshold_icmp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by icmp mbps limit";
return true;
}
return false;
}
std::string generate_flow_spec_for_amplification_attack(amplification_attack_type_t amplification_attack_type,
std::string destination_ip) {
exabgp_flow_spec_rule_t exabgp_rule;
bgp_flow_spec_action_t my_action;
// We drop all traffic by default
my_action.set_type(FLOW_SPEC_ACTION_DISCARD);
// Assign action to the rule
exabgp_rule.set_action(my_action);
// TODO: rewrite!
exabgp_rule.set_destination_subnet(
convert_subnet_from_string_to_binary_with_cidr_format(destination_ip + "/32"));
// We use only UDP here
exabgp_rule.add_protocol(FLOW_SPEC_PROTOCOL_UDP);
if (amplification_attack_type == AMPLIFICATION_ATTACK_DNS) {
exabgp_rule.add_source_port(53);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_NTP) {
exabgp_rule.add_source_port(123);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_SSDP) {
exabgp_rule.add_source_port(1900);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_SNMP) {
exabgp_rule.add_source_port(161);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_CHARGEN) {
exabgp_rule.add_source_port(19);
}
return exabgp_rule.serialize_single_line_exabgp_v4_configuration();
}
std::string get_amplification_attack_type(amplification_attack_type_t attack_type) {
if (attack_type == AMPLIFICATION_ATTACK_UNKNOWN) {
return "unknown";
} else if (attack_type == AMPLIFICATION_ATTACK_DNS) {
return "dns_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_NTP) {
return "ntp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_SSDP) {
return "ssdp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_SNMP) {
return "snmp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_CHARGEN) {
return "chargen_amplification";
} else {
return "unexpected";
}
}
// We calculate speed from packet counters here
inline void build_speed_counters_from_packet_counters(map_element& new_speed_element,
map_element* vector_itr,
double speed_calc_period) {
// calculate_speed(new_speed_element speed_element, vector_itr* );
new_speed_element.in_packets = uint64_t((double)vector_itr->in_packets / speed_calc_period);
new_speed_element.out_packets = uint64_t((double)vector_itr->out_packets / speed_calc_period);
new_speed_element.in_bytes = uint64_t((double)vector_itr->in_bytes / speed_calc_period);
new_speed_element.out_bytes = uint64_t((double)vector_itr->out_bytes / speed_calc_period);
// Fragmented
new_speed_element.fragmented_in_packets =
uint64_t((double)vector_itr->fragmented_in_packets / speed_calc_period);
new_speed_element.fragmented_out_packets =
uint64_t((double)vector_itr->fragmented_out_packets / speed_calc_period);
new_speed_element.fragmented_in_bytes =
uint64_t((double)vector_itr->fragmented_in_bytes / speed_calc_period);
new_speed_element.fragmented_out_bytes =
uint64_t((double)vector_itr->fragmented_out_bytes / speed_calc_period);
// By protocol counters
// TCP
new_speed_element.tcp_in_packets = uint64_t((double)vector_itr->tcp_in_packets / speed_calc_period);
new_speed_element.tcp_out_packets = uint64_t((double)vector_itr->tcp_out_packets / speed_calc_period);
new_speed_element.tcp_in_bytes = uint64_t((double)vector_itr->tcp_in_bytes / speed_calc_period);
new_speed_element.tcp_out_bytes = uint64_t((double)vector_itr->tcp_out_bytes / speed_calc_period);
// TCP syn
new_speed_element.tcp_syn_in_packets = uint64_t((double)vector_itr->tcp_syn_in_packets / speed_calc_period);
new_speed_element.tcp_syn_out_packets =
uint64_t((double)vector_itr->tcp_syn_out_packets / speed_calc_period);
new_speed_element.tcp_syn_in_bytes = uint64_t((double)vector_itr->tcp_syn_in_bytes / speed_calc_period);
new_speed_element.tcp_syn_out_bytes = uint64_t((double)vector_itr->tcp_syn_out_bytes / speed_calc_period);
// UDP
new_speed_element.udp_in_packets = uint64_t((double)vector_itr->udp_in_packets / speed_calc_period);
new_speed_element.udp_out_packets = uint64_t((double)vector_itr->udp_out_packets / speed_calc_period);
new_speed_element.udp_in_bytes = uint64_t((double)vector_itr->udp_in_bytes / speed_calc_period);
new_speed_element.udp_out_bytes = uint64_t((double)vector_itr->udp_out_bytes / speed_calc_period);
// ICMP
new_speed_element.icmp_in_packets = uint64_t((double)vector_itr->icmp_in_packets / speed_calc_period);
new_speed_element.icmp_out_packets = uint64_t((double)vector_itr->icmp_out_packets / speed_calc_period);
new_speed_element.icmp_in_bytes = uint64_t((double)vector_itr->icmp_in_bytes / speed_calc_period);
new_speed_element.icmp_out_bytes = uint64_t((double)vector_itr->icmp_out_bytes / speed_calc_period);
}
inline void build_average_speed_counters_from_speed_counters(map_element* current_average_speed_element,
map_element& new_speed_element,
double exp_value,
double exp_power) {
// Global bytes counters
current_average_speed_element->in_bytes =
uint64_t(new_speed_element.in_bytes + exp_value * ((double)current_average_speed_element->in_bytes -
(double)new_speed_element.in_bytes));
current_average_speed_element->out_bytes =
uint64_t(new_speed_element.out_bytes + exp_value * ((double)current_average_speed_element->out_bytes -
(double)new_speed_element.out_bytes));
// Global packet counters
current_average_speed_element->in_packets =
uint64_t(new_speed_element.in_packets + exp_value * ((double)current_average_speed_element->in_packets -
(double)new_speed_element.in_packets));
current_average_speed_element->out_packets =
uint64_t(new_speed_element.out_packets + exp_value * ((double)current_average_speed_element->out_packets -
(double)new_speed_element.out_packets));
// Per packet type packet counters for in traffic
current_average_speed_element->fragmented_in_packets =
uint64_t(new_speed_element.fragmented_in_packets +
exp_value * ((double)current_average_speed_element->fragmented_in_packets -
(double)new_speed_element.fragmented_in_packets));
current_average_speed_element->tcp_in_packets =
uint64_t(new_speed_element.tcp_in_packets + exp_value * ((double)current_average_speed_element->tcp_in_packets -
(double)new_speed_element.tcp_in_packets));
current_average_speed_element->tcp_syn_in_packets =
uint64_t(new_speed_element.tcp_syn_in_packets +
exp_value * ((double)current_average_speed_element->tcp_syn_in_packets -
(double)new_speed_element.tcp_syn_in_packets));
current_average_speed_element->udp_in_packets =
uint64_t(new_speed_element.udp_in_packets + exp_value * ((double)current_average_speed_element->udp_in_packets -
(double)new_speed_element.udp_in_packets));
current_average_speed_element->icmp_in_packets =
uint64_t(new_speed_element.icmp_in_packets + exp_value * ((double)current_average_speed_element->icmp_in_packets -
(double)new_speed_element.icmp_in_packets));
// Per packet type packets counters for out
current_average_speed_element->fragmented_out_packets =
uint64_t(new_speed_element.fragmented_out_packets +
exp_value * ((double)current_average_speed_element->fragmented_out_packets -
(double)new_speed_element.fragmented_out_packets));
current_average_speed_element->tcp_out_packets =
uint64_t(new_speed_element.tcp_out_packets + exp_value * ((double)current_average_speed_element->tcp_out_packets -
(double)new_speed_element.tcp_out_packets));
current_average_speed_element->tcp_syn_out_packets =
uint64_t(new_speed_element.tcp_syn_out_packets +
exp_value * ((double)current_average_speed_element->tcp_syn_out_packets -
(double)new_speed_element.tcp_syn_out_packets));
current_average_speed_element->udp_out_packets =
uint64_t(new_speed_element.udp_out_packets + exp_value * ((double)current_average_speed_element->udp_out_packets -
(double)new_speed_element.udp_out_packets));
current_average_speed_element->icmp_out_packets = uint64_t(
new_speed_element.icmp_out_packets + exp_value * ((double)current_average_speed_element->icmp_out_packets -
(double)new_speed_element.icmp_out_packets));
// Per packet type bytes counter for out
current_average_speed_element->fragmented_out_bytes =
uint64_t(new_speed_element.fragmented_out_bytes +
exp_value * ((double)current_average_speed_element->fragmented_out_bytes -
(double)new_speed_element.fragmented_out_bytes));
current_average_speed_element->tcp_out_bytes =
uint64_t(new_speed_element.tcp_out_bytes + exp_value * ((double)current_average_speed_element->tcp_out_bytes -
(double)new_speed_element.tcp_out_bytes));
current_average_speed_element->tcp_syn_out_bytes = uint64_t(
new_speed_element.tcp_syn_out_bytes + exp_value * ((double)current_average_speed_element->tcp_syn_out_bytes -
(double)new_speed_element.tcp_syn_out_bytes));
current_average_speed_element->udp_out_bytes =
uint64_t(new_speed_element.udp_out_bytes + exp_value * ((double)current_average_speed_element->udp_out_bytes -
(double)new_speed_element.udp_out_bytes));
current_average_speed_element->icmp_out_bytes =
uint64_t(new_speed_element.icmp_out_bytes + exp_value * ((double)current_average_speed_element->icmp_out_bytes -
(double)new_speed_element.icmp_out_bytes));
// Per packet type bytes counter for in
current_average_speed_element->fragmented_in_bytes =
uint64_t(new_speed_element.fragmented_in_bytes +
exp_value * ((double)current_average_speed_element->fragmented_in_bytes -
(double)new_speed_element.fragmented_in_bytes));
current_average_speed_element->tcp_in_bytes =
uint64_t(new_speed_element.tcp_in_bytes + exp_value * ((double)current_average_speed_element->tcp_in_bytes -
(double)new_speed_element.tcp_in_bytes));
current_average_speed_element->tcp_syn_in_bytes = uint64_t(
new_speed_element.tcp_syn_in_bytes + exp_value * ((double)current_average_speed_element->tcp_syn_in_bytes -
(double)new_speed_element.tcp_syn_in_bytes));
current_average_speed_element->udp_in_bytes =
uint64_t(new_speed_element.udp_in_bytes + exp_value * ((double)current_average_speed_element->udp_in_bytes -
(double)new_speed_element.udp_in_bytes));
current_average_speed_element->icmp_in_bytes =
uint64_t(new_speed_element.icmp_in_bytes + exp_value * ((double)current_average_speed_element->icmp_in_bytes -
(double)new_speed_element.icmp_in_bytes));
}

717
src/fastnetmon_logic.cpp Normal file

@ -0,0 +1,717 @@
#include "fastnetmon_logic.hpp"
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <fstream>
#include "all_logcpp_libraries.h"
#include "bgp_flow_spec.h"
#include "fast_library.h"
#include "fast_platform.h"
extern configuration_map_t configuration_map;
extern log4cpp::Category& logger;
extern bool graphite_enabled;
extern std::string graphite_host;
extern unsigned short int graphite_port;
extern std::string sort_parameter;
extern std::string graphite_prefix;
extern map_for_subnet_counters PerSubnetSpeedMap;
extern unsigned int ban_details_records_count;
extern FastnetmonPlatformConfigurtion fastnetmon_platform_configuration;
// We calculate speed from packet counters here
void build_speed_counters_from_packet_counters(map_element& new_speed_element,
map_element* vector_itr,
double speed_calc_period) {
// calculate_speed(new_speed_element speed_element, vector_itr* );
new_speed_element.in_packets = uint64_t((double)vector_itr->in_packets / speed_calc_period);
new_speed_element.out_packets = uint64_t((double)vector_itr->out_packets / speed_calc_period);
new_speed_element.in_bytes = uint64_t((double)vector_itr->in_bytes / speed_calc_period);
new_speed_element.out_bytes = uint64_t((double)vector_itr->out_bytes / speed_calc_period);
// Fragmented
new_speed_element.fragmented_in_packets =
uint64_t((double)vector_itr->fragmented_in_packets / speed_calc_period);
new_speed_element.fragmented_out_packets =
uint64_t((double)vector_itr->fragmented_out_packets / speed_calc_period);
new_speed_element.fragmented_in_bytes =
uint64_t((double)vector_itr->fragmented_in_bytes / speed_calc_period);
new_speed_element.fragmented_out_bytes =
uint64_t((double)vector_itr->fragmented_out_bytes / speed_calc_period);
// By protocol counters
// TCP
new_speed_element.tcp_in_packets = uint64_t((double)vector_itr->tcp_in_packets / speed_calc_period);
new_speed_element.tcp_out_packets = uint64_t((double)vector_itr->tcp_out_packets / speed_calc_period);
new_speed_element.tcp_in_bytes = uint64_t((double)vector_itr->tcp_in_bytes / speed_calc_period);
new_speed_element.tcp_out_bytes = uint64_t((double)vector_itr->tcp_out_bytes / speed_calc_period);
// TCP syn
new_speed_element.tcp_syn_in_packets = uint64_t((double)vector_itr->tcp_syn_in_packets / speed_calc_period);
new_speed_element.tcp_syn_out_packets =
uint64_t((double)vector_itr->tcp_syn_out_packets / speed_calc_period);
new_speed_element.tcp_syn_in_bytes = uint64_t((double)vector_itr->tcp_syn_in_bytes / speed_calc_period);
new_speed_element.tcp_syn_out_bytes = uint64_t((double)vector_itr->tcp_syn_out_bytes / speed_calc_period);
// UDP
new_speed_element.udp_in_packets = uint64_t((double)vector_itr->udp_in_packets / speed_calc_period);
new_speed_element.udp_out_packets = uint64_t((double)vector_itr->udp_out_packets / speed_calc_period);
new_speed_element.udp_in_bytes = uint64_t((double)vector_itr->udp_in_bytes / speed_calc_period);
new_speed_element.udp_out_bytes = uint64_t((double)vector_itr->udp_out_bytes / speed_calc_period);
// ICMP
new_speed_element.icmp_in_packets = uint64_t((double)vector_itr->icmp_in_packets / speed_calc_period);
new_speed_element.icmp_out_packets = uint64_t((double)vector_itr->icmp_out_packets / speed_calc_period);
new_speed_element.icmp_in_bytes = uint64_t((double)vector_itr->icmp_in_bytes / speed_calc_period);
new_speed_element.icmp_out_bytes = uint64_t((double)vector_itr->icmp_out_bytes / speed_calc_period);
}
void build_average_speed_counters_from_speed_counters(map_element* current_average_speed_element,
map_element& new_speed_element,
double exp_value,
double exp_power) {
// Global bytes counters
current_average_speed_element->in_bytes =
uint64_t(new_speed_element.in_bytes + exp_value * ((double)current_average_speed_element->in_bytes -
(double)new_speed_element.in_bytes));
current_average_speed_element->out_bytes =
uint64_t(new_speed_element.out_bytes + exp_value * ((double)current_average_speed_element->out_bytes -
(double)new_speed_element.out_bytes));
// Global packet counters
current_average_speed_element->in_packets =
uint64_t(new_speed_element.in_packets + exp_value * ((double)current_average_speed_element->in_packets -
(double)new_speed_element.in_packets));
current_average_speed_element->out_packets =
uint64_t(new_speed_element.out_packets + exp_value * ((double)current_average_speed_element->out_packets -
(double)new_speed_element.out_packets));
// Per packet type packet counters for in traffic
current_average_speed_element->fragmented_in_packets =
uint64_t(new_speed_element.fragmented_in_packets +
exp_value * ((double)current_average_speed_element->fragmented_in_packets -
(double)new_speed_element.fragmented_in_packets));
current_average_speed_element->tcp_in_packets =
uint64_t(new_speed_element.tcp_in_packets + exp_value * ((double)current_average_speed_element->tcp_in_packets -
(double)new_speed_element.tcp_in_packets));
current_average_speed_element->tcp_syn_in_packets =
uint64_t(new_speed_element.tcp_syn_in_packets +
exp_value * ((double)current_average_speed_element->tcp_syn_in_packets -
(double)new_speed_element.tcp_syn_in_packets));
current_average_speed_element->udp_in_packets =
uint64_t(new_speed_element.udp_in_packets + exp_value * ((double)current_average_speed_element->udp_in_packets -
(double)new_speed_element.udp_in_packets));
current_average_speed_element->icmp_in_packets =
uint64_t(new_speed_element.icmp_in_packets + exp_value * ((double)current_average_speed_element->icmp_in_packets -
(double)new_speed_element.icmp_in_packets));
// Per packet type packets counters for out
current_average_speed_element->fragmented_out_packets =
uint64_t(new_speed_element.fragmented_out_packets +
exp_value * ((double)current_average_speed_element->fragmented_out_packets -
(double)new_speed_element.fragmented_out_packets));
current_average_speed_element->tcp_out_packets =
uint64_t(new_speed_element.tcp_out_packets + exp_value * ((double)current_average_speed_element->tcp_out_packets -
(double)new_speed_element.tcp_out_packets));
current_average_speed_element->tcp_syn_out_packets =
uint64_t(new_speed_element.tcp_syn_out_packets +
exp_value * ((double)current_average_speed_element->tcp_syn_out_packets -
(double)new_speed_element.tcp_syn_out_packets));
current_average_speed_element->udp_out_packets =
uint64_t(new_speed_element.udp_out_packets + exp_value * ((double)current_average_speed_element->udp_out_packets -
(double)new_speed_element.udp_out_packets));
current_average_speed_element->icmp_out_packets = uint64_t(
new_speed_element.icmp_out_packets + exp_value * ((double)current_average_speed_element->icmp_out_packets -
(double)new_speed_element.icmp_out_packets));
// Per packet type bytes counter for out
current_average_speed_element->fragmented_out_bytes =
uint64_t(new_speed_element.fragmented_out_bytes +
exp_value * ((double)current_average_speed_element->fragmented_out_bytes -
(double)new_speed_element.fragmented_out_bytes));
current_average_speed_element->tcp_out_bytes =
uint64_t(new_speed_element.tcp_out_bytes + exp_value * ((double)current_average_speed_element->tcp_out_bytes -
(double)new_speed_element.tcp_out_bytes));
current_average_speed_element->tcp_syn_out_bytes = uint64_t(
new_speed_element.tcp_syn_out_bytes + exp_value * ((double)current_average_speed_element->tcp_syn_out_bytes -
(double)new_speed_element.tcp_syn_out_bytes));
current_average_speed_element->udp_out_bytes =
uint64_t(new_speed_element.udp_out_bytes + exp_value * ((double)current_average_speed_element->udp_out_bytes -
(double)new_speed_element.udp_out_bytes));
current_average_speed_element->icmp_out_bytes =
uint64_t(new_speed_element.icmp_out_bytes + exp_value * ((double)current_average_speed_element->icmp_out_bytes -
(double)new_speed_element.icmp_out_bytes));
// Per packet type bytes counter for in
current_average_speed_element->fragmented_in_bytes =
uint64_t(new_speed_element.fragmented_in_bytes +
exp_value * ((double)current_average_speed_element->fragmented_in_bytes -
(double)new_speed_element.fragmented_in_bytes));
current_average_speed_element->tcp_in_bytes =
uint64_t(new_speed_element.tcp_in_bytes + exp_value * ((double)current_average_speed_element->tcp_in_bytes -
(double)new_speed_element.tcp_in_bytes));
current_average_speed_element->tcp_syn_in_bytes = uint64_t(
new_speed_element.tcp_syn_in_bytes + exp_value * ((double)current_average_speed_element->tcp_syn_in_bytes -
(double)new_speed_element.tcp_syn_in_bytes));
current_average_speed_element->udp_in_bytes =
uint64_t(new_speed_element.udp_in_bytes + exp_value * ((double)current_average_speed_element->udp_in_bytes -
(double)new_speed_element.udp_in_bytes));
current_average_speed_element->icmp_in_bytes =
uint64_t(new_speed_element.icmp_in_bytes + exp_value * ((double)current_average_speed_element->icmp_in_bytes -
(double)new_speed_element.icmp_in_bytes));
}
std::string print_flow_tracking_for_ip(conntrack_main_struct& conntrack_element, std::string client_ip) {
std::stringstream buffer;
std::string in_tcp =
print_flow_tracking_for_specified_protocol(conntrack_element.in_tcp, client_ip, INCOMING);
std::string in_udp =
print_flow_tracking_for_specified_protocol(conntrack_element.in_udp, client_ip, INCOMING);
unsigned long long total_number_of_incoming_tcp_flows = conntrack_element.in_tcp.size();
unsigned long long total_number_of_incoming_udp_flows = conntrack_element.in_udp.size();
unsigned long long total_number_of_outgoing_tcp_flows = conntrack_element.out_tcp.size();
unsigned long long total_number_of_outgoing_udp_flows = conntrack_element.out_udp.size();
bool we_have_incoming_flows = in_tcp.length() > 0 or in_udp.length() > 0;
if (we_have_incoming_flows) {
buffer << "Incoming\n\n";
if (in_tcp.length() > 0) {
buffer << "TCP flows: " << total_number_of_incoming_tcp_flows << "\n";
buffer << in_tcp << "\n";
}
if (in_udp.length() > 0) {
buffer << "UDP flows: " << total_number_of_incoming_udp_flows << "\n";
buffer << in_udp << "\n";
}
}
std::string out_tcp =
print_flow_tracking_for_specified_protocol(conntrack_element.out_tcp, client_ip, OUTGOING);
std::string out_udp =
print_flow_tracking_for_specified_protocol(conntrack_element.out_udp, client_ip, OUTGOING);
bool we_have_outgoing_flows = out_tcp.length() > 0 or out_udp.length() > 0;
// print delimiter if we have flows in both directions
if (we_have_incoming_flows && we_have_outgoing_flows) {
buffer << "\n";
}
if (we_have_outgoing_flows) {
buffer << "Outgoing\n\n";
if (out_tcp.length() > 0) {
buffer << "TCP flows: " << total_number_of_outgoing_tcp_flows << "\n";
buffer << out_tcp << "\n";
}
if (out_udp.length() > 0) {
buffer << "UDP flows: " << total_number_of_outgoing_udp_flows << "\n";
buffer << out_udp << "\n";
}
}
return buffer.str();
}
std::string print_subnet_load() {
std::stringstream buffer;
sort_type sorter;
if (sort_parameter == "packets") {
sorter = PACKETS;
} else if (sort_parameter == "bytes") {
sorter = BYTES;
} else if (sort_parameter == "flows") {
sorter = FLOWS;
} else {
logger << log4cpp::Priority::INFO << "Unexpected sorter type: " << sort_parameter;
sorter = PACKETS;
}
std::vector<pair_of_map_for_subnet_counters_elements_t> vector_for_sort;
vector_for_sort.reserve(PerSubnetSpeedMap.size());
for (map_for_subnet_counters::iterator itr = PerSubnetSpeedMap.begin();
itr != PerSubnetSpeedMap.end(); ++itr) {
vector_for_sort.push_back(std::make_pair(itr->first, itr->second));
}
std::sort(vector_for_sort.begin(), vector_for_sort.end(),
TrafficComparatorClass<pair_of_map_for_subnet_counters_elements_t>(INCOMING, sorter));
graphite_data_t graphite_data;
for (std::vector<pair_of_map_for_subnet_counters_elements_t>::iterator itr = vector_for_sort.begin();
itr != vector_for_sort.end(); ++itr) {
map_element* speed = &itr->second;
std::string subnet_as_string = convert_subnet_to_string(itr->first);
buffer << std::setw(18) << std::left << subnet_as_string;
if (graphite_enabled) {
std::string subnet_as_string_as_dash_delimiters = subnet_as_string;
// Replace dots by dashes
std::replace(subnet_as_string_as_dash_delimiters.begin(),
subnet_as_string_as_dash_delimiters.end(), '.', '_');
// Replace / by dashes too
std::replace(subnet_as_string_as_dash_delimiters.begin(),
subnet_as_string_as_dash_delimiters.end(), '/', '_');
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".incoming.pps"] =
speed->in_packets;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".outgoing.pps"] =
speed->out_packets;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".incoming.bps"] =
speed->in_bytes * 8;
graphite_data[graphite_prefix + ".networks." + subnet_as_string_as_dash_delimiters + ".outgoing.bps"] =
speed->out_bytes * 8;
}
buffer << " "
<< "pps in: " << std::setw(8) << speed->in_packets << " out: " << std::setw(8)
<< speed->out_packets << " mbps in: " << std::setw(5) << convert_speed_to_mbps(speed->in_bytes)
<< " out: " << std::setw(5) << convert_speed_to_mbps(speed->out_bytes) << "\n";
}
if (graphite_enabled) {
bool graphite_put_result = store_data_to_graphite(graphite_port, graphite_host, graphite_data);
if (!graphite_put_result) {
logger << log4cpp::Priority::ERROR << "Can't store network load data to Graphite";
}
}
return buffer.str();
}
std::string print_ban_thresholds(ban_settings_t current_ban_settings) {
std::stringstream output_buffer;
output_buffer << "Configuration params:\n";
if (current_ban_settings.enable_ban) {
output_buffer << "We call ban script: yes\n";
} else {
output_buffer << "We call ban script: no\n";
}
output_buffer << "Packets per second: ";
if (current_ban_settings.enable_ban_for_pps) {
output_buffer << current_ban_settings.ban_threshold_pps;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
output_buffer << "Mbps per second: ";
if (current_ban_settings.enable_ban_for_bandwidth) {
output_buffer << current_ban_settings.ban_threshold_mbps;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
output_buffer << "Flows per second: ";
if (current_ban_settings.enable_ban_for_flows_per_second) {
output_buffer << current_ban_settings.ban_threshold_flows;
} else {
output_buffer << "disabled";
}
output_buffer << "\n";
return output_buffer.str();
}
void print_attack_details_to_file(std::string details, std::string client_ip_as_string, attack_details current_attack) {
std::ofstream my_attack_details_file;
std::string ban_timestamp_as_string = print_time_t_in_fastnetmon_format(current_attack.ban_timestamp);
std::string attack_dump_path =
fastnetmon_platform_configuration.attack_details_folder + "/" + client_ip_as_string + "_" + ban_timestamp_as_string + ".txt";
my_attack_details_file.open(attack_dump_path.c_str(), std::ios::app);
if (my_attack_details_file.is_open()) {
my_attack_details_file << details << "\n\n";
my_attack_details_file.close();
} else {
logger << log4cpp::Priority::ERROR << "Can't print attack details to file";
}
}
logging_configuration_t read_logging_settings(configuration_map_t configuration_map) {
logging_configuration_t logging_configuration_temp;
if (configuration_map.count("logging:local_syslog_logging") != 0) {
logging_configuration_temp.local_syslog_logging =
configuration_map["logging:local_syslog_logging"] == "on";
}
if (configuration_map.count("logging:remote_syslog_logging") != 0) {
logging_configuration_temp.remote_syslog_logging =
configuration_map["logging:remote_syslog_logging"] == "on";
}
if (configuration_map.count("logging:remote_syslog_server") != 0) {
logging_configuration_temp.remote_syslog_server =
configuration_map["logging:remote_syslog_server"];
}
if (configuration_map.count("logging:remote_syslog_port") != 0) {
logging_configuration_temp.remote_syslog_port =
convert_string_to_integer(configuration_map["logging:remote_syslog_port"]);
}
if (logging_configuration_temp.remote_syslog_logging) {
if (logging_configuration_temp.remote_syslog_port > 0 &&
!logging_configuration_temp.remote_syslog_server.empty()) {
logger << log4cpp::Priority::INFO << "We have configured remote syslog logging corectly";
} else {
logger << log4cpp::Priority::ERROR << "You have enabled remote logging but haven't specified port or host";
logging_configuration_temp.remote_syslog_logging = false;
}
}
if (logging_configuration_temp.local_syslog_logging) {
logger << log4cpp::Priority::INFO << "We have configured local syslog logging corectly";
}
return logging_configuration_temp;
}
ban_settings_t read_ban_settings(configuration_map_t configuration_map, std::string host_group_name) {
ban_settings_t ban_settings;
std::string prefix = "";
if (host_group_name != "") {
prefix = host_group_name + "_";
}
if (configuration_map.count(prefix + "enable_ban") != 0) {
ban_settings.enable_ban = configuration_map[prefix + "enable_ban"] == "on";
}
if (configuration_map.count(prefix + "ban_for_pps") != 0) {
ban_settings.enable_ban_for_pps = configuration_map[prefix + "ban_for_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_bandwidth") != 0) {
ban_settings.enable_ban_for_bandwidth = configuration_map[prefix + "ban_for_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_flows") != 0) {
ban_settings.enable_ban_for_flows_per_second =
configuration_map[prefix + "ban_for_flows"] == "on";
}
// Per protocol bandwidth triggers
if (configuration_map.count(prefix + "ban_for_tcp_bandwidth") != 0) {
ban_settings.enable_ban_for_tcp_bandwidth =
configuration_map[prefix + "ban_for_tcp_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_udp_bandwidth") != 0) {
ban_settings.enable_ban_for_udp_bandwidth =
configuration_map[prefix + "ban_for_udp_bandwidth"] == "on";
}
if (configuration_map.count(prefix + "ban_for_icmp_bandwidth") != 0) {
ban_settings.enable_ban_for_icmp_bandwidth =
configuration_map[prefix + "ban_for_icmp_bandwidth"] == "on";
}
// Per protocol pps ban triggers
if (configuration_map.count(prefix + "ban_for_tcp_pps") != 0) {
ban_settings.enable_ban_for_tcp_pps = configuration_map[prefix + "ban_for_tcp_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_udp_pps") != 0) {
ban_settings.enable_ban_for_udp_pps = configuration_map[prefix + "ban_for_udp_pps"] == "on";
}
if (configuration_map.count(prefix + "ban_for_icmp_pps") != 0) {
ban_settings.enable_ban_for_icmp_pps =
configuration_map[prefix + "ban_for_icmp_pps"] == "on";
}
// Pps per protocol thresholds
if (configuration_map.count(prefix + "threshold_tcp_pps") != 0) {
ban_settings.ban_threshold_tcp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_tcp_pps"]);
}
if (configuration_map.count(prefix + "threshold_udp_pps") != 0) {
ban_settings.ban_threshold_udp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_udp_pps"]);
}
if (configuration_map.count(prefix + "threshold_icmp_pps") != 0) {
ban_settings.ban_threshold_icmp_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_icmp_pps"]);
}
// Bandwidth per protocol thresholds
if (configuration_map.count(prefix + "threshold_tcp_mbps") != 0) {
ban_settings.ban_threshold_tcp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_tcp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_udp_mbps") != 0) {
ban_settings.ban_threshold_udp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_udp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_icmp_mbps") != 0) {
ban_settings.ban_threshold_icmp_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_icmp_mbps"]);
}
if (configuration_map.count(prefix + "threshold_pps") != 0) {
ban_settings.ban_threshold_pps =
convert_string_to_integer(configuration_map[prefix + "threshold_pps"]);
}
if (configuration_map.count(prefix + "threshold_mbps") != 0) {
ban_settings.ban_threshold_mbps =
convert_string_to_integer(configuration_map[prefix + "threshold_mbps"]);
}
if (configuration_map.count(prefix + "threshold_flows") != 0) {
ban_settings.ban_threshold_flows =
convert_string_to_integer(configuration_map[prefix + "threshold_flows"]);
}
return ban_settings;
}
bool exceed_pps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold) {
if (in_counter > threshold or out_counter > threshold) {
return true;
} else {
return false;
}
}
bool exceed_flow_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold) {
if (in_counter > threshold or out_counter > threshold) {
return true;
} else {
return false;
}
}
bool exceed_mbps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold_mbps) {
if (convert_speed_to_mbps(in_counter) > threshold_mbps or convert_speed_to_mbps(out_counter) > threshold_mbps) {
return true;
} else {
return false;
}
}
// Return true when we should ban this IP
bool we_should_ban_this_ip(map_element* average_speed_element, ban_settings_t current_ban_settings) {
// we detect overspeed by packets
if (current_ban_settings.enable_ban_for_pps &&
exceed_pps_speed(average_speed_element->in_packets, average_speed_element->out_packets,
current_ban_settings.ban_threshold_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_bandwidth &&
exceed_mbps_speed(average_speed_element->in_bytes, average_speed_element->out_bytes,
current_ban_settings.ban_threshold_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_flows_per_second &&
exceed_flow_speed(average_speed_element->in_flows, average_speed_element->out_flows,
current_ban_settings.ban_threshold_flows)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by flow limit";
return true;
}
// We could try per protocol thresholds here
// Per protocol pps thresholds
if (current_ban_settings.enable_ban_for_tcp_pps &&
exceed_pps_speed(average_speed_element->tcp_in_packets, average_speed_element->tcp_out_packets,
current_ban_settings.ban_threshold_tcp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by tcp pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_udp_pps &&
exceed_pps_speed(average_speed_element->udp_in_packets, average_speed_element->udp_out_packets,
current_ban_settings.ban_threshold_udp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by udp pps limit";
return true;
}
if (current_ban_settings.enable_ban_for_icmp_pps &&
exceed_pps_speed(average_speed_element->icmp_in_packets, average_speed_element->icmp_out_packets,
current_ban_settings.ban_threshold_icmp_pps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by icmp pps limit";
return true;
}
// Per protocol bandwidth thresholds
if (current_ban_settings.enable_ban_for_tcp_bandwidth &&
exceed_mbps_speed(average_speed_element->tcp_in_bytes, average_speed_element->tcp_out_bytes,
current_ban_settings.ban_threshold_tcp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by tcp mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_udp_bandwidth &&
exceed_mbps_speed(average_speed_element->udp_in_bytes, average_speed_element->udp_out_bytes,
current_ban_settings.ban_threshold_udp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by udp mbps limit";
return true;
}
if (current_ban_settings.enable_ban_for_icmp_bandwidth &&
exceed_mbps_speed(average_speed_element->icmp_in_bytes, average_speed_element->icmp_out_bytes,
current_ban_settings.ban_threshold_icmp_mbps)) {
logger << log4cpp::Priority::DEBUG << "We detected this attack by icmp mbps limit";
return true;
}
return false;
}
std::string generate_flow_spec_for_amplification_attack(amplification_attack_type_t amplification_attack_type,
std::string destination_ip) {
exabgp_flow_spec_rule_t exabgp_rule;
bgp_flow_spec_action_t my_action;
// We drop all traffic by default
my_action.set_type(FLOW_SPEC_ACTION_DISCARD);
// Assign action to the rule
exabgp_rule.set_action(my_action);
// TODO: rewrite!
exabgp_rule.set_destination_subnet(
convert_subnet_from_string_to_binary_with_cidr_format(destination_ip + "/32"));
// We use only UDP here
exabgp_rule.add_protocol(FLOW_SPEC_PROTOCOL_UDP);
if (amplification_attack_type == AMPLIFICATION_ATTACK_DNS) {
exabgp_rule.add_source_port(53);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_NTP) {
exabgp_rule.add_source_port(123);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_SSDP) {
exabgp_rule.add_source_port(1900);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_SNMP) {
exabgp_rule.add_source_port(161);
} else if (amplification_attack_type == AMPLIFICATION_ATTACK_CHARGEN) {
exabgp_rule.add_source_port(19);
}
return exabgp_rule.serialize_single_line_exabgp_v4_configuration();
}
std::string get_amplification_attack_type(amplification_attack_type_t attack_type) {
if (attack_type == AMPLIFICATION_ATTACK_UNKNOWN) {
return "unknown";
} else if (attack_type == AMPLIFICATION_ATTACK_DNS) {
return "dns_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_NTP) {
return "ntp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_SSDP) {
return "ssdp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_SNMP) {
return "snmp_amplification";
} else if (attack_type == AMPLIFICATION_ATTACK_CHARGEN) {
return "chargen_amplification";
} else {
return "unexpected";
}
}
std::string print_flow_tracking_for_specified_protocol(contrack_map_type& protocol_map,
std::string client_ip,
direction_t flow_direction) {
std::stringstream buffer;
// We shoud iterate over all fields
int printed_records = 0;
for (contrack_map_type::iterator itr = protocol_map.begin(); itr != protocol_map.end(); ++itr) {
// We should limit number of records in flow dump because syn flood attacks produce
// thounsands of lines
if (printed_records > ban_details_records_count) {
buffer << "Flows have cropped due to very long list.\n";
break;
}
uint64_t packed_connection_data = itr->first;
packed_conntrack_hash unpacked_key_struct;
convert_integer_to_conntrack_hash_struct(&packed_connection_data, &unpacked_key_struct);
std::string opposite_ip_as_string = convert_ip_as_uint_to_string(unpacked_key_struct.opposite_ip);
if (flow_direction == INCOMING) {
buffer << client_ip << ":" << unpacked_key_struct.dst_port << " < "
<< opposite_ip_as_string << ":" << unpacked_key_struct.src_port << " ";
} else if (flow_direction == OUTGOING) {
buffer << client_ip << ":" << unpacked_key_struct.src_port << " > "
<< opposite_ip_as_string << ":" << unpacked_key_struct.dst_port << " ";
}
buffer << itr->second.bytes << " bytes " << itr->second.packets << " packets";
buffer << "\n";
printed_records++;
}
return buffer.str();
}
void convert_integer_to_conntrack_hash_struct(packed_session* packed_connection_data,
packed_conntrack_hash* unpacked_data) {
memcpy(unpacked_data, packed_connection_data, sizeof(uint64_t));
}

32
src/fastnetmon_logic.hpp Normal file

@ -0,0 +1,32 @@
#include "fastnetmon_types.h"
void build_speed_counters_from_packet_counters(map_element& new_speed_element,
map_element* vector_itr,
double speed_calc_period) ;
void build_average_speed_counters_from_speed_counters(map_element* current_average_speed_element,
map_element& new_speed_element,
double exp_value,
double exp_power);
std::string get_amplification_attack_type(amplification_attack_type_t attack_type);
std::string generate_flow_spec_for_amplification_attack(amplification_attack_type_t amplification_attack_type,
std::string destination_ip);
bool we_should_ban_this_ip(map_element* average_speed_element, ban_settings_t current_ban_settings);
bool exceed_mbps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold_mbps);
bool exceed_flow_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold);
bool exceed_pps_speed(uint64_t in_counter, uint64_t out_counter, unsigned int threshold);
ban_settings_t read_ban_settings(configuration_map_t configuration_map, std::string host_group_name);
logging_configuration_t read_logging_settings(configuration_map_t configuration_map);
void print_attack_details_to_file(std::string details, std::string client_ip_as_string, attack_details current_attack);
std::string print_ban_thresholds(ban_settings_t current_ban_settings);
std::string print_subnet_load();
std::string print_flow_tracking_for_ip(conntrack_main_struct& conntrack_element, std::string client_ip);
std::string print_flow_tracking_for_specified_protocol(contrack_map_type& protocol_map,
std::string client_ip,
direction_t flow_direction);
void convert_integer_to_conntrack_hash_struct(packed_session* packed_connection_data,
packed_conntrack_hash* unpacked_data);

@ -14,6 +14,57 @@
#include "fastnetmon_simple_packet.h"
typedef std::map<std::string, std::string> configuration_map_t;
typedef std::map<std::string, uint64_t> graphite_data_t;
// Enum with available sort by field
enum sort_type { PACKETS, BYTES, FLOWS };
/* Class for custom comparison fields by different fields */
template <typename T> class TrafficComparatorClass {
private:
sort_type sort_field;
direction_t sort_direction;
public:
TrafficComparatorClass(direction_t sort_direction, sort_type sort_field) {
this->sort_field = sort_field;
this->sort_direction = sort_direction;
}
bool operator()(T a, T b) {
if (sort_field == FLOWS) {
if (sort_direction == INCOMING) {
return a.second.in_flows > b.second.in_flows;
} else if (sort_direction == OUTGOING) {
return a.second.out_flows > b.second.out_flows;
} else {
return false;
}
} else if (sort_field == PACKETS) {
if (sort_direction == INCOMING) {
return a.second.in_packets > b.second.in_packets;
} else if (sort_direction == OUTGOING) {
return a.second.out_packets > b.second.out_packets;
} else {
return false;
}
} else if (sort_field == BYTES) {
if (sort_direction == INCOMING) {
return a.second.in_bytes > b.second.in_bytes;
} else if (sort_direction == OUTGOING) {
return a.second.out_bytes > b.second.out_bytes;
} else {
return false;
}
} else {
return false;
}
}
};
class logging_configuration_t {
public:
logging_configuration_t()
@ -38,9 +89,6 @@ typedef std::map<std::string, subnet_vector_t> host_group_map_t;
typedef void (*process_packet_pointer)(simple_packet_t&);
// Enum with available sort by field
enum sort_type { PACKETS, BYTES, FLOWS };
// Attack types
enum attack_type_t {
ATTACK_UNKNOWN = 1,