From dd8b618ca1775cf49d606ba5ec405aec4f655307 Mon Sep 17 00:00:00 2001 From: Pavel Odintsov Date: Fri, 25 Mar 2022 19:34:29 +0000 Subject: [PATCH] Added logic to ban IPv6 hosts --- src/api.hpp | 150 +++++++++++++++++++++------------- src/fast_library.cpp | 17 ++++ src/fast_library.h | 1 + src/fastnetmon_api_client.cpp | 4 +- 4 files changed, 112 insertions(+), 60 deletions(-) diff --git a/src/api.hpp b/src/api.hpp index 8694a5385..3b719a874 100644 --- a/src/api.hpp +++ b/src/api.hpp @@ -1,46 +1,69 @@ - Status FastnetmonApiServiceImpl::GetBanlist(::grpc::ServerContext* context, - const ::fastmitigation::BanListRequest* request, - ::grpc::ServerWriter< ::fastmitigation::BanListReply>* writer) { - logger << log4cpp::Priority::INFO << "API we asked for banlist"; +Status FastnetmonApiServiceImpl::GetBanlist(::grpc::ServerContext* context, + const ::fastmitigation::BanListRequest* request, + ::grpc::ServerWriter< ::fastmitigation::BanListReply>* writer) { + logger << log4cpp::Priority::INFO << "API we asked for banlist"; - for (std::map::iterator itr = ban_list.begin(); itr != ban_list.end(); ++itr) { - std::string client_ip_as_string = convert_ip_as_uint_to_string(itr->first); + for (std::map::iterator itr = ban_list.begin(); itr != ban_list.end(); ++itr) { + std::string client_ip_as_string = convert_ip_as_uint_to_string(itr->first); - BanListReply reply; - reply.set_ip_address(client_ip_as_string + "/32"); - writer->Write(reply); - } - - // IPv6 - std::map ban_list_copy; + BanListReply reply; + reply.set_ip_address(client_ip_as_string + "/32"); + writer->Write(reply); + } - // Get whole ban list content atomically - ban_list_ipv6_ng.get_whole_banlist(ban_list_copy); + // IPv6 + std::map ban_list_copy; + // Get whole ban list content atomically + ban_list_ipv6_ng.get_whole_banlist(ban_list_copy); - for (auto itr : ban_list_copy) { - BanListReply reply; - reply.set_ip_address( print_ipv6_cidr_subnet(itr.first) ); - writer->Write(reply); - } - return Status::OK; + for (auto itr : ban_list_copy) { + BanListReply reply; + reply.set_ip_address( print_ipv6_cidr_subnet(itr.first) ); + writer->Write(reply); } + return Status::OK; +} + Status FastnetmonApiServiceImpl::ExecuteBan(ServerContext* context, const fastmitigation::ExecuteBanRequest* request, fastmitigation::ExecuteBanReply* reply) { logger << log4cpp::Priority::INFO << "API we asked for ban for IP: " << request->ip_address(); - if (!is_v4_host(request->ip_address())) { - logger << log4cpp::Priority::ERROR << "IP bad format"; - return Status::CANCELLED; - } + if (!validate_ipv6_or_ipv4_host(request->ip_address())) { + logger << log4cpp::Priority::ERROR << "You specified malformed IP address"; + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Malformed IP address"); + } + + // At this step IP should be valid IPv4 or IPv6 address + bool ipv6 = false; + + if (request->ip_address().find(":") != std::string::npos) { + ipv6 = true; + } + + bool ipv4 = !ipv6; + + uint32_t client_ip = 0; + + subnet_ipv6_cidr_mask_t ipv6_address; + ipv6_address.cidr_prefix_length = 128; + + attack_details_t current_attack; + current_attack.ipv6 = ipv6; + + boost::circular_buffer empty_simple_packets_buffer; + + std::string flow_attack_details = "manually triggered attack"; - uint32_t client_ip = convert_ip_as_string_to_uint(request->ip_address()); - attack_details_t current_attack; + + if (ipv4) { + client_ip = convert_ip_as_string_to_uint(request->ip_address()); + ban_list_mutex.lock(); ban_list[client_ip] = current_attack; ban_list_mutex.unlock(); @@ -48,48 +71,59 @@ ban_list_details_mutex.lock(); ban_list_details[client_ip] = std::vector(); ban_list_details_mutex.unlock(); + } else { + bool parsed_ipv6 = read_ipv6_host_from_string(request->ip_address(), ipv6_address.subnet_address); + if (!parsed_ipv6) { + logger << log4cpp::Priority::ERROR << "Can't parse IPv6 address: " << request->ip_address(); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Can't parse IPv6 address"); + } - subnet_ipv6_cidr_mask_t zero_ipv6_address; - boost::circular_buffer empty_simple_packets_buffer; - - logger << log4cpp::Priority::INFO << "API call ban handlers manually"; + bool in_our_networks_list = ip_belongs_to_patricia_tree_ipv6(lookup_tree_ipv6, ipv6_address.subnet_address); - std::string flow_attack_details = "manually triggered attack"; - call_ban_handlers(client_ip, zero_ipv6_address, false, current_attack, flow_attack_details, attack_detection_source_t::Automatic, "", empty_simple_packets_buffer); + if (!in_our_networks_list) { + logger << log4cpp::Priority::ERROR << "IP address " << request->ip_address() << " is not belongs to our networks."; + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "This IP not belongs to our subnets"); + } - return Status::OK; + ban_list_ipv6_ng.add_to_blackhole(ipv6_address, current_attack); } - Status FastnetmonApiServiceImpl::ExecuteUnBan(ServerContext* context, - const fastmitigation::ExecuteBanRequest* request, - fastmitigation::ExecuteBanReply* reply) { - logger << log4cpp::Priority::INFO << "API: We asked for unban for IP: " << request->ip_address(); + logger << log4cpp::Priority::INFO << "API call ban handlers manually"; + call_ban_handlers(client_ip, ipv6_address, ipv6, current_attack, flow_attack_details, attack_detection_source_t::Automatic, "", empty_simple_packets_buffer); - if (!is_v4_host(request->ip_address())) { - logger << log4cpp::Priority::ERROR << "IP bad format"; - return Status::CANCELLED; - } + return Status::OK; +} - uint32_t banned_ip = convert_ip_as_string_to_uint(request->ip_address()); +Status FastnetmonApiServiceImpl::ExecuteUnBan(ServerContext* context, + const fastmitigation::ExecuteBanRequest* request, + fastmitigation::ExecuteBanReply* reply) { + logger << log4cpp::Priority::INFO << "API: We asked for unban for IP: " << request->ip_address(); - if (ban_list.count(banned_ip) == 0) { - logger << log4cpp::Priority::ERROR << "API: Could not find IP in ban list"; - return Status::CANCELLED; - } + if (!is_v4_host(request->ip_address())) { + logger << log4cpp::Priority::ERROR << "IP bad format"; + return Status::CANCELLED; + } - banlist_item_t ban_details = ban_list[banned_ip]; + uint32_t banned_ip = convert_ip_as_string_to_uint(request->ip_address()); - logger << log4cpp::Priority::INFO << "API: call unban handlers"; - - subnet_ipv6_cidr_mask_t zero_ipv6_address; - call_unban_handlers(banned_ip, zero_ipv6_address, false, ban_details, attack_detection_source_t::Automatic); + if (ban_list.count(banned_ip) == 0) { + logger << log4cpp::Priority::ERROR << "API: Could not find IP in ban list"; + return Status::CANCELLED; + } - logger << log4cpp::Priority::INFO << "API: remove IP from ban list"; + banlist_item_t ban_details = ban_list[banned_ip]; - ban_list_mutex.lock(); - ban_list.erase(banned_ip); - ban_list_mutex.unlock(); + logger << log4cpp::Priority::INFO << "API: call unban handlers"; + + subnet_ipv6_cidr_mask_t zero_ipv6_address; + call_unban_handlers(banned_ip, zero_ipv6_address, false, ban_details, attack_detection_source_t::Automatic); - return Status::OK; - } + logger << log4cpp::Priority::INFO << "API: remove IP from ban list"; + + ban_list_mutex.lock(); + ban_list.erase(banned_ip); + ban_list_mutex.unlock(); + + return Status::OK; +} diff --git a/src/fast_library.cpp b/src/fast_library.cpp index 372b2850a..041d61a34 100644 --- a/src/fast_library.cpp +++ b/src/fast_library.cpp @@ -1471,3 +1471,20 @@ bool read_ipv6_host_from_string(std::string ipv6_host_as_string, in6_addr& resul } } +// Validates IPv4 or IPv6 address in host form: +// 127.0.0.1 or ::1 +bool validate_ipv6_or_ipv4_host(const std::string host) { + // Validate host address + boost::system::error_code ec; + + // Try to build it from string representation + auto parsed_ip_address = boost::asio::ip::address::from_string(host, ec); + + // If we failed to parse it + if (ec) { + return false; + } + + return true; +} + diff --git a/src/fast_library.h b/src/fast_library.h index 25bb53bae..504322fc8 100644 --- a/src/fast_library.h +++ b/src/fast_library.h @@ -122,3 +122,4 @@ bool set_boost_process_name(boost::thread* thread, std::string process_name); std::string convert_any_ip_to_string(subnet_ipv6_cidr_mask_t subnet); bool convert_string_to_positive_integer_safe(std::string line, int& value); bool read_ipv6_host_from_string(std::string ipv6_host_as_string, in6_addr& result); +bool validate_ipv6_or_ipv4_host(const std::string host); diff --git a/src/fastnetmon_api_client.cpp b/src/fastnetmon_api_client.cpp index 1b769a06e..74d8d0a9d 100644 --- a/src/fastnetmon_api_client.cpp +++ b/src/fastnetmon_api_client.cpp @@ -42,7 +42,7 @@ class FastnetmonClient { std::cerr << "Could not connect to API server. Timeout exceed" << std::endl; return; } else { - std::cerr << "RPC failed " + status.error_message() << std::endl; + std::cerr << "Query failed " + status.error_message() << std::endl; return; } } @@ -80,7 +80,7 @@ class FastnetmonClient { std::cerr << "Could not connect to API server. Timeout exceed" << std::endl; return; } else { - std::cerr << "RPC failed " + status.error_message() << std::endl; + std::cerr << "Query failed " + status.error_message() << std::endl; return; } }