Skip to content

Commit

Permalink
Introduced detailed attack reporting logic
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel-odintsov committed Nov 16, 2024
1 parent a427d8b commit a813f7d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 6 deletions.
36 changes: 36 additions & 0 deletions src/fast_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}


2 changes: 2 additions & 0 deletions src/fast_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
6 changes: 3 additions & 3 deletions src/fastnetmon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
66 changes: 63 additions & 3 deletions src/fastnetmon_logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();

Expand Down Expand Up @@ -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 = "";

Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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();
}
}


Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions src/fastnetmon_logic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

0 comments on commit a813f7d

Please sign in to comment.