Ipv6 callback (#888)
* Added proper storage for captured IPv6 packets * Added final logic to trigger IPv6 attacks
This commit is contained in:
parent
ff69f6f42a
commit
3e9060e6b8
@ -1428,3 +1428,14 @@ std::string convert_any_ip_to_string(subnet_ipv6_cidr_mask_t subnet) {
|
||||
return print_ipv6_cidr_subnet(subnet);
|
||||
}
|
||||
|
||||
// Return true if we have this IP in patricia tree
|
||||
bool ip_belongs_to_patricia_tree_ipv6(patricia_tree_t* patricia_tree, struct in6_addr client_ipv6_address) {
|
||||
prefix_t prefix_for_check_address;
|
||||
|
||||
prefix_for_check_address.family = AF_INET6;
|
||||
prefix_for_check_address.bitlen = 128;
|
||||
prefix_for_check_address.add.sin6 = client_ipv6_address;
|
||||
|
||||
return patricia_search_best2(patricia_tree, &prefix_for_check_address, 1) != NULL;
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,7 @@ subnet_cidr_mask_t convert_subnet_from_string_to_binary_with_cidr_format(std::st
|
||||
bool manage_interface_promisc_mode(std::string interface_name, bool switch_on);
|
||||
#endif
|
||||
|
||||
bool ip_belongs_to_patricia_tree_ipv6(patricia_tree_t* patricia_tree, struct in6_addr client_ipv6_address);
|
||||
std::string serialize_attack_description(attack_details_t& current_attack);
|
||||
attack_type_t detect_attack_type(attack_details_t& current_attack);
|
||||
std::string get_printable_attack_name(attack_type_t attack);
|
||||
|
@ -17,6 +17,9 @@ logging:remote_syslog_port = 514
|
||||
# Enable/Disable any actions in case of attack
|
||||
enable_ban = on
|
||||
|
||||
# Enable ban for IPv6
|
||||
enable_ban_ipv6 = on
|
||||
|
||||
# disable processing for certain direction of traffic
|
||||
process_incoming_traffic = on
|
||||
process_outgoing_traffic = on
|
||||
|
@ -506,6 +506,12 @@ std::string print_ban_thresholds(ban_settings_t current_ban_settings) {
|
||||
output_buffer << "We call ban script: no\n";
|
||||
}
|
||||
|
||||
if (current_ban_settings.enable_ban_ipv6) {
|
||||
output_buffer << "We call ban script for IPv6: yes\n";
|
||||
} else {
|
||||
output_buffer << "We call ban script for IPv6: no\n";
|
||||
}
|
||||
|
||||
output_buffer << "Packets per second: ";
|
||||
if (current_ban_settings.enable_ban_for_pps) {
|
||||
output_buffer << current_ban_settings.ban_threshold_pps;
|
||||
@ -604,6 +610,10 @@ ban_settings_t read_ban_settings(configuration_map_t configuration_map, std::str
|
||||
ban_settings.enable_ban = configuration_map[prefix + "enable_ban"] == "on";
|
||||
}
|
||||
|
||||
if (configuration_map.count(prefix + "enable_ban_ipv6") != 0) {
|
||||
ban_settings.enable_ban_ipv6 = configuration_map[prefix + "enable_ban_ipv6"] == "on";
|
||||
}
|
||||
|
||||
if (configuration_map.count(prefix + "ban_for_pps") != 0) {
|
||||
ban_settings.enable_ban_for_pps = configuration_map[prefix + "ban_for_pps"] == "on";
|
||||
}
|
||||
@ -2304,10 +2314,212 @@ void traffic_draw_ipv4_program() {
|
||||
timeval_subtract(&drawing_thread_execution_time, &end_calc_time, &start_calc_time);
|
||||
}
|
||||
|
||||
std::string get_human_readable_threshold_type(attack_detection_threshold_type_t detecttion_type) {
|
||||
if (detecttion_type == attack_detection_threshold_type_t::unknown) {
|
||||
return "unknown";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::packets_per_second) {
|
||||
return "packets per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::bytes_per_second) {
|
||||
return "bytes per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::flows_per_second) {
|
||||
return "flows per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::tcp_packets_per_second) {
|
||||
return "tcp packets per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::tcp_syn_packets_per_second) {
|
||||
return "tcp syn packets per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::tcp_syn_bytes_per_second) {
|
||||
return "tcp syn bytes per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::udp_packets_per_second) {
|
||||
return "udp packets per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::icmp_packets_per_second) {
|
||||
return "icmp packets per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::tcp_bytes_per_second) {
|
||||
return "tcp bytes per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::udp_bytes_per_second) {
|
||||
return "udp bytes per second";
|
||||
} else if (detecttion_type == attack_detection_threshold_type_t::icmp_bytes_per_second) {
|
||||
return "icmp bytes per second";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
// This function fills attack information from different information sources
|
||||
bool fill_attack_information(map_element_t average_speed_element,
|
||||
attack_details_t& current_attack,
|
||||
std::string& host_group_name,
|
||||
std::string& parent_host_group_name,
|
||||
bool unban_enabled,
|
||||
int ban_time) {
|
||||
uint64_t pps = 0;
|
||||
|
||||
uint64_t in_pps = average_speed_element.in_packets;
|
||||
uint64_t out_pps = average_speed_element.out_packets;
|
||||
uint64_t in_bps = average_speed_element.in_bytes;
|
||||
uint64_t out_bps = average_speed_element.out_bytes;
|
||||
uint64_t in_flows = average_speed_element.in_flows;
|
||||
uint64_t out_flows = average_speed_element.out_flows;
|
||||
|
||||
direction_t data_direction;
|
||||
|
||||
// TODO: move this logic to different function!!!
|
||||
|
||||
// Detect attack direction with simple heuristic
|
||||
if (abs(int((int)in_pps - (int)out_pps)) < 1000) {
|
||||
// If difference between pps speed is so small we should do additional
|
||||
// investigation using
|
||||
// bandwidth speed
|
||||
if (in_bps > out_bps) {
|
||||
data_direction = INCOMING;
|
||||
pps = in_pps;
|
||||
} else {
|
||||
data_direction = OUTGOING;
|
||||
pps = out_pps;
|
||||
}
|
||||
} else {
|
||||
if (in_pps > out_pps) {
|
||||
data_direction = INCOMING;
|
||||
pps = in_pps;
|
||||
} else {
|
||||
data_direction = OUTGOING;
|
||||
pps = out_pps;
|
||||
}
|
||||
}
|
||||
|
||||
current_attack.attack_protocol = detect_attack_protocol(average_speed_element, data_direction);
|
||||
|
||||
current_attack.host_group = host_group_name;
|
||||
current_attack.parent_host_group = parent_host_group_name;
|
||||
|
||||
std::string data_direction_as_string = get_direction_name(data_direction);
|
||||
|
||||
logger << log4cpp::Priority::INFO << "We run attack block code with following params"
|
||||
<< " in: " << in_pps << " pps " << convert_speed_to_mbps(in_bps) << " mbps"
|
||||
<< " out: " << out_pps << " pps " << convert_speed_to_mbps(out_bps) << " mbps"
|
||||
<< " and we decided it's " << data_direction_as_string << " attack";
|
||||
|
||||
// Store ban time
|
||||
time(¤t_attack.ban_timestamp);
|
||||
// set ban time in seconds
|
||||
current_attack.ban_time = ban_time;
|
||||
current_attack.unban_enabled = unban_enabled;
|
||||
|
||||
// Pass main information about attack
|
||||
current_attack.attack_direction = data_direction;
|
||||
current_attack.attack_power = pps;
|
||||
current_attack.max_attack_power = pps;
|
||||
|
||||
current_attack.in_packets = in_pps;
|
||||
current_attack.out_packets = out_pps;
|
||||
|
||||
current_attack.in_bytes = in_bps;
|
||||
current_attack.out_bytes = out_bps;
|
||||
|
||||
// pass flow information
|
||||
current_attack.in_flows = in_flows;
|
||||
current_attack.out_flows = out_flows;
|
||||
|
||||
current_attack.fragmented_in_packets = average_speed_element.fragmented_in_packets;
|
||||
current_attack.tcp_in_packets = average_speed_element.tcp_in_packets;
|
||||
current_attack.tcp_syn_in_packets = average_speed_element.tcp_syn_in_packets;
|
||||
current_attack.udp_in_packets = average_speed_element.udp_in_packets;
|
||||
current_attack.icmp_in_packets = average_speed_element.icmp_in_packets;
|
||||
|
||||
current_attack.fragmented_out_packets = average_speed_element.fragmented_out_packets;
|
||||
current_attack.tcp_out_packets = average_speed_element.tcp_out_packets;
|
||||
current_attack.tcp_syn_out_packets = average_speed_element.tcp_syn_out_packets;
|
||||
current_attack.udp_out_packets = average_speed_element.udp_out_packets;
|
||||
current_attack.icmp_out_packets = average_speed_element.icmp_out_packets;
|
||||
|
||||
current_attack.fragmented_out_bytes = average_speed_element.fragmented_out_bytes;
|
||||
current_attack.tcp_out_bytes = average_speed_element.tcp_out_bytes;
|
||||
current_attack.tcp_syn_out_bytes = average_speed_element.tcp_syn_out_bytes;
|
||||
current_attack.udp_out_bytes = average_speed_element.udp_out_bytes;
|
||||
current_attack.icmp_out_bytes = average_speed_element.icmp_out_bytes;
|
||||
|
||||
current_attack.fragmented_in_bytes = average_speed_element.fragmented_in_bytes;
|
||||
current_attack.tcp_in_bytes = average_speed_element.tcp_in_bytes;
|
||||
current_attack.tcp_syn_in_bytes = average_speed_element.tcp_syn_in_bytes;
|
||||
current_attack.udp_in_bytes = average_speed_element.udp_in_bytes;
|
||||
current_attack.icmp_in_bytes = average_speed_element.icmp_in_bytes;
|
||||
|
||||
current_attack.average_in_packets = average_speed_element.in_packets;
|
||||
current_attack.average_in_bytes = average_speed_element.in_bytes;
|
||||
current_attack.average_in_flows = average_speed_element.in_flows;
|
||||
|
||||
current_attack.average_out_packets = average_speed_element.out_packets;
|
||||
current_attack.average_out_bytes = average_speed_element.out_bytes;
|
||||
current_attack.average_out_flows = average_speed_element.out_flows;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Speed recalculation function for IPv6 hosts calls it for each host during speed recalculation
|
||||
void speed_callback_ipv6(subnet_ipv6_cidr_mask_t* current_subnet, map_element_t* current_average_speed_element) {
|
||||
// TODO: attack action logic should be implemented here
|
||||
return;
|
||||
// We should check thresholds only for per host counters for IPv6 and only when any ban actions for IPv6 traffic were enabled
|
||||
if (!global_ban_settings.enable_ban_ipv6) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We support only global group
|
||||
std::string host_group_name = "global";
|
||||
|
||||
attack_detection_threshold_type_t attack_detection_source;
|
||||
attack_detection_direction_type_t attack_detection_direction;
|
||||
|
||||
bool should_ban = we_should_ban_this_entity(current_average_speed_element, global_ban_settings,
|
||||
attack_detection_source, attack_detection_direction);
|
||||
|
||||
if (!should_ban) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This code works only for /128 subnets
|
||||
bool in_white_list = ip_belongs_to_patricia_tree_ipv6(whitelist_tree_ipv6, current_subnet->subnet_address);
|
||||
|
||||
if (in_white_list) {
|
||||
// logger << log4cpp::Priority::INFO << "This IP was whitelisted";
|
||||
return;
|
||||
}
|
||||
|
||||
bool we_already_have_buckets_for_this_ip = packet_buckets_ipv6_storage.we_have_bucket_for_this_ip(*current_subnet);
|
||||
|
||||
if (we_already_have_buckets_for_this_ip) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool this_ip_is_already_banned = ban_list_ipv6_ng.is_blackholed(*current_subnet);
|
||||
|
||||
if (this_ip_is_already_banned) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string ddos_detection_threshold_as_string = get_human_readable_threshold_type(attack_detection_source);
|
||||
|
||||
logger << log4cpp::Priority::INFO << "We have detected IPv6 attack for " << print_ipv6_cidr_subnet(*current_subnet)
|
||||
<< " with " << ddos_detection_threshold_as_string << " threshold host group: " << host_group_name;
|
||||
|
||||
std::string parent_group;
|
||||
|
||||
attack_details_t attack_details;
|
||||
fill_attack_information(*current_average_speed_element, attack_details, host_group_name, parent_group,
|
||||
unban_enabled, global_ban_time);
|
||||
|
||||
attack_details.ipv6 = true;
|
||||
// TODO: Also, we should find IPv6 network for attack here
|
||||
|
||||
bool enable_backet_capture =
|
||||
packet_buckets_ipv6_storage.enable_packet_capture(*current_subnet, attack_details, collection_pattern_t::ONCE);
|
||||
|
||||
if (!enable_backet_capture) {
|
||||
logger << log4cpp::Priority::ERROR << "Could not enable packet capture for deep analytics for IPv6 "
|
||||
<< print_ipv6_cidr_subnet(*current_subnet);
|
||||
return;
|
||||
}
|
||||
|
||||
logger << log4cpp::Priority::INFO << "Enabled packet capture for IPv6 " << print_ipv6_address(current_subnet->subnet_address);
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,6 +169,13 @@ class attack_details_t : public map_element_t {
|
||||
customer_network.subnet_address = 0;
|
||||
customer_network.cidr_prefix_length = 0;
|
||||
}
|
||||
|
||||
// Host group for this attack
|
||||
std::string host_group;
|
||||
|
||||
// Parent hostgroup for host's host group
|
||||
std::string parent_host_group;
|
||||
|
||||
direction_t attack_direction;
|
||||
// first attackpower detected
|
||||
uint64_t attack_power;
|
||||
@ -189,6 +196,9 @@ class attack_details_t : public map_element_t {
|
||||
bool unban_enabled;
|
||||
int ban_time; // seconds of the ban
|
||||
|
||||
// If this attack was detected for IPv6 protocol
|
||||
bool ipv6 = false;
|
||||
|
||||
subnet_cidr_mask_t customer_network;
|
||||
|
||||
packet_storage_t pcap_attack_dump;
|
||||
@ -258,7 +268,7 @@ class packed_conntrack_hash_t {
|
||||
class ban_settings_t {
|
||||
public:
|
||||
ban_settings_t()
|
||||
: enable_ban(false), enable_ban_for_pps(false), enable_ban_for_bandwidth(false),
|
||||
: enable_ban(false), enable_ban_ipv6(false), enable_ban_for_pps(false), enable_ban_for_bandwidth(false),
|
||||
enable_ban_for_flows_per_second(false), enable_ban_for_tcp_pps(false),
|
||||
enable_ban_for_tcp_bandwidth(false), enable_ban_for_udp_pps(false),
|
||||
enable_ban_for_udp_bandwidth(false), enable_ban_for_icmp_pps(false),
|
||||
@ -267,6 +277,7 @@ class ban_settings_t {
|
||||
ban_threshold_icmp_pps(0), ban_threshold_mbps(0), ban_threshold_flows(0), ban_threshold_pps(0) {
|
||||
}
|
||||
bool enable_ban;
|
||||
bool enable_ban_ipv6;
|
||||
|
||||
bool enable_ban_for_pps;
|
||||
bool enable_ban_for_bandwidth;
|
||||
|
Loading…
Reference in New Issue
Block a user