Added logic to lookup IPv6 prefix for incoming packet (#873)

This commit is contained in:
Pavel Odintsov 2020-11-14 20:41:15 +00:00 committed by GitHub
parent cc63c04334
commit f2dc853247
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 222 additions and 9 deletions

@ -737,39 +737,50 @@ std::string print_ipv6_address(struct in6_addr& ipv6_address) {
return result;
}
direction_t get_packet_direction_ipv6(patricia_tree_t* lookup_tree, struct in6_addr src_ipv6, struct in6_addr dst_ipv6) {
direction_t get_packet_direction_ipv6(patricia_tree_t* lookup_tree, struct in6_addr src_ipv6, struct in6_addr dst_ipv6, subnet_ipv6_cidr_mask_t& subnet) {
direction_t packet_direction;
bool our_ip_is_destination = false;
bool our_ip_is_source = false;
bool our_ip_is_source = false;
prefix_t prefix_for_check_address;
prefix_for_check_address.family = AF_INET6;
prefix_for_check_address.bitlen = 128;
prefix_for_check_address.bitlen = 128;
patricia_node_t* found_patrica_node = NULL;
prefix_for_check_address.add.sin6 = dst_ipv6;
prefix_for_check_address.add.sin6 = dst_ipv6;
found_patrica_node = patricia_search_best2(lookup_tree, &prefix_for_check_address, 1);
subnet_ipv6_cidr_mask_t destination_subnet;
if (found_patrica_node) {
our_ip_is_destination = true;
}
found_patrica_node = NULL;
destination_subnet.subnet_address = found_patrica_node->prefix->add.sin6;
destination_subnet.cidr_prefix_length = found_patrica_node->prefix->bitlen;
}
found_patrica_node = NULL;
prefix_for_check_address.add.sin6 = src_ipv6;
subnet_ipv6_cidr_mask_t source_subnet;
found_patrica_node = patricia_search_best2(lookup_tree, &prefix_for_check_address, 1);
if (found_patrica_node) {
our_ip_is_source = true;
}
source_subnet.subnet_address = found_patrica_node->prefix->add.sin6;
source_subnet.cidr_prefix_length = found_patrica_node->prefix->bitlen;
}
if (our_ip_is_source && our_ip_is_destination) {
packet_direction = INTERNAL;
} else if (our_ip_is_source) {
subnet = source_subnet;
packet_direction = OUTGOING;
} else if (our_ip_is_destination) {
subnet = destination_subnet;
packet_direction = INCOMING;
} else {
packet_direction = OTHER;

@ -26,6 +26,8 @@
#include "fast_endianless.hpp"
#include "fastnetmon_networks.hpp"
#define TCP_FIN_FLAG_SHIFT 1
#define TCP_SYN_FLAG_SHIFT 2
#define TCP_RST_FLAG_SHIFT 3
@ -92,7 +94,7 @@ direction_t get_packet_direction(patricia_tree_t* lookup_tree,
unsigned long& source_subnet,
unsigned int& source_subnet_cidr_mas);
direction_t get_packet_direction_ipv6(patricia_tree_t* lookup_tree, struct in6_addr src_ipv6, struct in6_addr dst_ipv6);
direction_t get_packet_direction_ipv6(patricia_tree_t* lookup_tree, struct in6_addr src_ipv6, struct in6_addr dst_ipv6, subnet_ipv6_cidr_mask_t& subnet);
std::string convert_prefix_to_string_representation(prefix_t* prefix);
std::string find_subnet_by_ip_in_string_format(patricia_tree_t* patricia_tree, std::string ip);

@ -2643,8 +2643,10 @@ void process_packet(simple_packet_t& current_packet) {
}
if (current_packet.ip_protocol_version == 6) {
subnet_ipv6_cidr_mask_t ipv6_cidr_subnet;
current_packet.packet_direction =
get_packet_direction_ipv6(lookup_tree_ipv6, current_packet.src_ipv6, current_packet.dst_ipv6);
get_packet_direction_ipv6(lookup_tree_ipv6, current_packet.src_ipv6, current_packet.dst_ipv6, ipv6_cidr_subnet);
#ifdef USE_NEW_ATOMIC_BUILTINS
__atomic_add_fetch(&total_ipv6_packets, 1, __ATOMIC_RELAXED);

198
src/fastnetmon_networks.hpp Normal file

@ -0,0 +1,198 @@
#pragma once
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <boost/functional/hash.hpp>
#include <boost/serialization/nvp.hpp>
// IPv6 subnet with mask in cidr form
class subnet_ipv6_cidr_mask_t {
public:
subnet_ipv6_cidr_mask_t() {
// Fill subnet by zeros
memset(&this->subnet_address, 0, sizeof(in6_addr));
}
void set_cidr_prefix_length(uint32_t cidr_prefix_length) {
this->cidr_prefix_length = cidr_prefix_length;
}
// Just copy this data by pointer
void set_subnet_address(in6_addr* ipv6_host_address_param) {
memcpy(&subnet_address, ipv6_host_address_param, sizeof(in6_addr));
}
template <class Archive> void serialize(Archive& ar, const unsigned int version) {
// Boost does not know how to serialize in6_addr but nested s6_addr is a just array with 16 elements of char and we do serialzie it instead
ar& BOOST_SERIALIZATION_NVP(subnet_address.s6_addr);
ar& BOOST_SERIALIZATION_NVP(cidr_prefix_length);
}
in6_addr subnet_address;
uint32_t cidr_prefix_length = 128;
};
// We need this operator because we are using this class in std::map which
// requires ordering
// We use inline to suppress angry compiler
inline bool operator<(const subnet_ipv6_cidr_mask_t& lhs, const subnet_ipv6_cidr_mask_t& rhs) {
if (lhs.cidr_prefix_length < rhs.cidr_prefix_length) {
return true;
} else if (lhs.cidr_prefix_length == rhs.cidr_prefix_length) {
// Compare addresses as memory blocks
// Order may be incorrect (desc vs asc)
return memcmp(&lhs.subnet_address, &rhs.subnet_address, sizeof(in6_addr)) < 0;
} else {
return false;
}
}
// Inject custom specialization of std::hash in namespace std
// We need it for std::unordered_map
namespace std {
template <> struct hash<subnet_ipv6_cidr_mask_t> {
typedef std::size_t result_type;
std::size_t operator()(subnet_ipv6_cidr_mask_t const& s) const {
std::size_t seed = 0;
const uint8_t* b = s.subnet_address.s6_addr;
boost::hash_combine(seed, s.cidr_prefix_length);
// Add all elements from IPv6 into hash
for (int i = 0; i < 16; i++) {
boost::hash_combine(seed, b[i]);
}
return seed;
}
};
} // namespace std
inline bool operator==(const subnet_ipv6_cidr_mask_t& lhs, const subnet_ipv6_cidr_mask_t& rhs) {
// Prefixes has different lengths
if (lhs.cidr_prefix_length != rhs.cidr_prefix_length) {
return false;
}
return memcmp(&lhs.subnet_address, &rhs.subnet_address, sizeof(in6_addr)) == 0;
}
inline bool operator!=(const subnet_ipv6_cidr_mask_t& lhs, const subnet_ipv6_cidr_mask_t& rhs) {
return !(lhs == rhs);
}
// Subnet with cidr mask
class subnet_cidr_mask_t {
public:
subnet_cidr_mask_t() {
this->subnet_address = 0;
this->cidr_prefix_length = 0;
}
subnet_cidr_mask_t(uint32_t subnet_address, uint32_t cidr_prefix_length) {
this->subnet_address = subnet_address;
this->cidr_prefix_length = cidr_prefix_length;
}
// We need this operator because we are using this class in std::map which
// requires order
bool operator<(const subnet_cidr_mask_t& rhs) {
if (this->cidr_prefix_length < rhs.cidr_prefix_length) {
return true;
} else if (this->cidr_prefix_length == rhs.cidr_prefix_length) {
return this->subnet_address < rhs.subnet_address;
} else {
return false;
}
}
bool is_zero_subnet() {
if (subnet_address == 0 && cidr_prefix_length == 0) {
return true;
} else {
return false;
}
}
void set_subnet_address(uint32_t subnet_address) {
this->subnet_address = subnet_address;
}
void set_cidr_prefix_length(uint32_t cidr_prefix_length) {
this->cidr_prefix_length = cidr_prefix_length;
}
template <class Archive> void serialize(Archive& ar, const unsigned int version) {
ar& BOOST_SERIALIZATION_NVP(subnet_address);
ar& BOOST_SERIALIZATION_NVP(cidr_prefix_length);
}
// Big endian (network byte order)
uint32_t subnet_address = 0;
// Little endian
uint32_t cidr_prefix_length = 0;
};
// TODO: move to .cpp file!!!
inline bool operator==(const subnet_cidr_mask_t& lhs, const subnet_cidr_mask_t& rhs) {
// Prefixes has different lengths
if (lhs.cidr_prefix_length != rhs.cidr_prefix_length) {
return false;
}
return lhs.subnet_address == rhs.subnet_address;
}
inline bool operator!=(const subnet_cidr_mask_t& lhs, const subnet_cidr_mask_t& rhs) {
return !(lhs == rhs);
}
// TODO: move to .cpp file!!!
// We need free function for comparision code
inline bool operator<(const subnet_cidr_mask_t& lhs, const subnet_cidr_mask_t& rhs) {
if (lhs.cidr_prefix_length < rhs.cidr_prefix_length) {
return true;
} else if (lhs.cidr_prefix_length == rhs.cidr_prefix_length) {
return lhs.subnet_address < rhs.subnet_address;
} else {
return false;
}
}
// Subnet with binary mask
class subnet_binary_netmask_t {
public:
subnet_binary_netmask_t() {
this->subnet_address = 0;
this->subnet_binary_mask = 0;
}
subnet_binary_netmask_t(uint32_t subnet_address, uint32_t subnet_binary_mask) {
this->subnet_address = subnet_address;
this->subnet_binary_mask = subnet_binary_mask;
}
uint32_t subnet_address = 0;
uint32_t subnet_binary_mask = 0;
};
namespace std {
// Inject custom specialization of std::hash in namespace std
// We need it for std::unordered_map
template <> struct hash<subnet_cidr_mask_t> {
typedef std::size_t result_type;
std::size_t operator()(subnet_cidr_mask_t const& s) const {
std::size_t seed = 0;
boost::hash_combine(seed, s.cidr_prefix_length);
boost::hash_combine(seed, s.subnet_address);
return seed;
}
};
} // namespace std