1
0
mirror of https://github.com/pavel-odintsov/fastnetmon synced 2024-11-22 16:32:22 +01:00

Introduced detailed attack reporting logic

This commit is contained in:
Pavel Odintsov 2024-11-16 16:25:25 +03:00
parent a427d8b6f0
commit a813f7da83
5 changed files with 105 additions and 6 deletions

@ -2475,3 +2475,39 @@ void print_simple_packet_buffer_to_string(const boost::circular_buffer<simple_pa
}
// Write circular buffer with simple packets to json document
bool write_simple_packet_as_separate_fields_dump_to_json(const boost::circular_buffer<simple_packet_t>& simple_packets_buffer,
nlohmann::json& packet_array) {
extern log4cpp::Category& logger;
// Even if we have no data we need empty array here
packet_array = nlohmann::json::array();
try {
if (simple_packets_buffer.size() == 0) {
logger << log4cpp::Priority::INFO << "Packet buffer is blank";
return true;
}
// Add all pack descriptions as strings array
for (const simple_packet_t& packet : simple_packets_buffer) {
nlohmann::json json_packet;
if (!serialize_simple_packet_to_json(packet, json_packet)) {
continue;
}
// Append to document as normal STL container
packet_array.push_back(json_packet);
}
} catch (...) {
logger << log4cpp::Priority::ERROR << "Cannot create packet list in JSON";
return false;
}
return true;
}

@ -171,3 +171,5 @@ bool read_ipv6_subnet_from_string(subnet_ipv6_cidr_mask_t& ipv6_address, const s
bool subnet_belongs_to_patricia_tree(patricia_tree_t* patricia_tree, const subnet_cidr_mask_t& subnet);
// Prepares textual dump of simple packets buffer
void print_simple_packet_buffer_to_string(const boost::circular_buffer<simple_packet_t>& simple_packets_buffer, std::string& output);
bool write_simple_packet_as_separate_fields_dump_to_json(const boost::circular_buffer<simple_packet_t>& simple_packets_buffer,
nlohmann::json& packet_array);

@ -256,6 +256,9 @@ std::vector<flow_spec_rule_t> static_flowspec_based_whitelist;
std::string graphite_thread_execution_time_desc = "Time consumed by pushing data to Graphite";
struct timeval graphite_thread_execution_time;
// Run stats thread
bool usage_stats = true;
void init_global_ban_settings() {
// ban Configuration params
global_ban_settings.enable_ban_for_pps = false;
@ -2052,9 +2055,6 @@ int main(int argc, char** argv) {
set_boost_process_name(inaccurate_time_generator_thread, "fast_time");
service_thread_group.add_thread(inaccurate_time_generator_thread);
// Run stats thread
bool usage_stats = true;
if (configuration_map.count("disable_usage_report") != 0 && configuration_map["disable_usage_report"] == "on") {
usage_stats = false;
}

@ -1011,7 +1011,8 @@ std::string get_attack_description_in_json_for_web_hooks(uint32_t client_ip,
const subnet_ipv6_cidr_mask_t& client_ipv6,
bool ipv6,
const std::string& action_type,
const attack_details_t& current_attack) {
const attack_details_t& current_attack,
const boost::circular_buffer<simple_packet_t>& simple_packets_buffer) {
nlohmann::json callback_info;
callback_info["alert_scope"] = "host";
@ -1034,6 +1035,18 @@ std::string get_attack_description_in_json_for_web_hooks(uint32_t client_ip,
logger << log4cpp::Priority::ERROR << "Cannot generate attack details for get_attack_description_in_json_for_web_hooks";
}
// We add these sections only if we have anything in packet dump
if (simple_packets_buffer.size() != 0) {
// Detailed per field packet dump
nlohmann::json packet_dump_per_field;
if (write_simple_packet_as_separate_fields_dump_to_json(simple_packets_buffer, packet_dump_per_field)) {
callback_info["packet_dump_detailed"] = packet_dump_per_field;
} else {
logger << log4cpp::Priority::ERROR << "Cannot generate detailed packet dump";
}
}
std::string json_as_text = callback_info.dump();
@ -1197,6 +1210,8 @@ void call_blackhole_actions_per_host(attack_action_t attack_action,
const boost::circular_buffer<simple_packet_t>& simple_packets_buffer,
const boost::circular_buffer<fixed_size_packet_storage_t>& raw_packets_buffer) {
extern bool usage_stats;
bool ipv4 = !ipv6;
std::string client_ip_as_string = "";
@ -1218,7 +1233,7 @@ void call_blackhole_actions_per_host(attack_action_t attack_action,
print_simple_packet_buffer_to_string(simple_packets_buffer, simple_packets_dump);
std::string basic_attack_information_in_json =
get_attack_description_in_json_for_web_hooks(client_ip, subnet_ipv6_cidr_mask_t{}, false, action_name, current_attack);
get_attack_description_in_json_for_web_hooks(client_ip, subnet_ipv6_cidr_mask_t{}, false, action_name, current_attack, simple_packets_buffer);
bool store_attack_details_to_file = true;
@ -1315,7 +1330,7 @@ void call_blackhole_actions_per_host(attack_action_t attack_action,
boost::thread redis_store_thread(store_data_in_redis, redis_key_name, flow_attack_details);
redis_store_thread.detach();
logger << log4cpp::Priority::INFO << "Finish data save in redis in key: " << redis_key_name;
}
}
}
#endif
@ -1337,6 +1352,11 @@ void call_blackhole_actions_per_host(attack_action_t attack_action,
}
#endif
}
if (usage_stats) {
boost::thread attack_report_thread(send_attack_data_to_reporting_server, basic_attack_information_in_json);
attack_report_thread.detach();
}
}
@ -3173,6 +3193,7 @@ void send_usage_data_to_reporting_server() {
}
}
void collect_stats() {
extern unsigned int stats_thread_initial_call_delay;
extern unsigned int stats_thread_sleep_time;
@ -3451,3 +3472,42 @@ std::string get_human_readable_attack_detection_direction(attack_detection_direc
}
}
// Sends attack information to reporting server
void send_attack_data_to_reporting_server(const std::string& attack_json_string) {
extern std::string reporting_server;
// Build query
std::stringstream request_stream;
request_stream << "https://" << reporting_server << "/attacks_v1";
uint32_t response_code = 0;
std::string response_body;
std::string error_text;
std::map<std::string, std::string> headers;
// I think we need to do it to make clear about format for remote app
headers["Content-Type"] = "application/json";
// Just do it to know about DNS issues, execute_web_request can do DNS resolution on it's own
std::string reporting_server_ip_address = dns_lookup(reporting_server);
if (reporting_server_ip_address.empty()) {
logger << log4cpp::Priority::DEBUG << "Stats server resolver failed, please check your DNS";
return;
}
bool result = execute_web_request_secure(request_stream.str(), "post", attack_json_string, response_code,
response_body, headers, error_text);
if (!result) {
logger << log4cpp::Priority::DEBUG << "Can't collect attack stats data";
return;
}
if (response_code != 200) {
logger << log4cpp::Priority::DEBUG << "Got code " << response_code << " from stats server instead of 200";
return;
}
}

@ -106,3 +106,4 @@ void inaccurate_time_generator();
void collect_stats();
void start_prometheus_web_server();
std::string get_human_readable_attack_detection_direction(attack_detection_direction_type_t attack_detection_direction);
void send_attack_data_to_reporting_server(const std::string& attack_json_string);