Skip to content

Commit

Permalink
IPv4 filter enhancement #11IPv4 filter enhancement (Closes rakshasa#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
chros authored and chros committed Dec 10, 2017
1 parent c167c5a commit 1d18974
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 158 deletions.
23 changes: 20 additions & 3 deletions src/torrent/peer/peer_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ PeerList::insert_address(const sockaddr* sa, int flags) {

PeerInfo* peerInfo = new PeerInfo(sa);
peerInfo->set_listen_port(address->port());
peerInfo->set_flags(m_ipv4_table.at(address->sa_inet()->address_h()) & PeerInfo::mask_ip_table);
uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h();

// IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called
if(m_ipv4_table.defined(host_byte_order_ipv4_addr))
peerInfo->set_flags(m_ipv4_table.at(host_byte_order_ipv4_addr) & PeerInfo::mask_ip_table);

manager->client_list()->retrieve_unknown(&peerInfo->mutable_client_info());

Expand Down Expand Up @@ -264,12 +268,25 @@ PeerList::connected(const sockaddr* sa, int flags) {
!socket_address_key::is_comparable_sockaddr(sa))
return NULL;

int filter_value = m_ipv4_table.at(address->sa_inet()->address_h());
uint32_t host_byte_order_ipv4_addr = address->sa_inet()->address_h();
int filter_value = 0;

// IPv4 addresses stored in host byte order in ipv4_table so they are comparable. ntohl has been called
if(m_ipv4_table.defined(host_byte_order_ipv4_addr))
filter_value = m_ipv4_table.at(host_byte_order_ipv4_addr);

// We should also remove any PeerInfo objects already for this
// address.
if ((filter_value & PeerInfo::flag_unwanted))
if ((filter_value & PeerInfo::flag_unwanted)) {
char ipv4_str[INET_ADDRSTRLEN];
uint32_t net_order_addr = htonl(host_byte_order_ipv4_addr);

inet_ntop(AF_INET, &net_order_addr, ipv4_str, INET_ADDRSTRLEN);

lt_log_print(LOG_PEER_INFO, "Peer %s is unwanted: preventing connection", ipv4_str);

return NULL;
}

PeerInfo* peerInfo;
range_type range = base_type::equal_range(sock_key);
Expand Down
2 changes: 1 addition & 1 deletion src/torrent/peer/peer_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace torrent {

class DownloadInfo;

typedef extents<uint32_t, int, 32, 256, 8> ipv4_table;
typedef extents<uint32_t, int> ipv4_table;

class LIBTORRENT_EXPORT PeerList : private std::multimap<socket_address_key, PeerInfo*> {
public:
Expand Down
267 changes: 113 additions & 154 deletions src/torrent/utils/extents.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,191 +37,150 @@
#ifndef LIBTORRENT_UTILS_EXTENTS_H
#define LIBTORRENT_UTILS_EXTENTS_H

#include lt_tr1_array

#include <algorithm>
#include <map>
#include <stdexcept>

namespace torrent {

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
struct extents_base {
typedef Key key_type;
typedef std::pair<Key, Key> range_type;
typedef std::pair<extents_base*, Tp> mapped_type;
typedef Tp mapped_value_type;

typedef std::array<mapped_type, TableSize> table_type;

extents_base(key_type pos, unsigned int mb, mapped_value_type val);
extents_base(extents_base* parent, typename table_type::const_iterator itr);
~extents_base();

bool is_divisible(key_type key) const { return key % mask_bits == 0; }
bool is_leaf_branch() const { return mask_bits == 0; }
bool is_equal_range(key_type first, key_type last, const mapped_value_type& val) const;

unsigned int sizeof_data() const;

typename table_type::iterator partition_at(key_type key) { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); }
typename table_type::const_iterator partition_at(key_type key) const { return table.begin() + ((key >> mask_bits) & (TableSize - 1)); }

unsigned int mask_distance(unsigned int mb) { return (~(~key_type() << mb) >> mask_bits); }

key_type partition_pos(typename table_type::const_iterator part) const { return position + (std::distance(table.begin(), part) << mask_bits); }

void insert(key_type pos, unsigned int mb, const mapped_value_type& val);

const mapped_value_type& at(key_type key) const;

unsigned int mask_bits;
key_type position;
table_type table;
};

template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
class extents : private extents_base<Key, Tp, TableSize, TableBits> {
template <class Address, class Value, class Compare=std::less<Address> >
class extents {
public:
typedef extents_base<Key, Tp, TableSize, TableBits> base_type;

typedef typename base_type::key_type key_type;
typedef base_type value_type;
typedef typename base_type::range_type range_type;
typedef typename base_type::mapped_type mapped_type;
typedef typename base_type::mapped_value_type mapped_value_type;
typedef typename base_type::table_type table_type;

static const key_type mask_bits = MaskBits;
static const key_type table_bits = TableBits;
static const key_type table_size = TableSize;

using base_type::at;
using base_type::sizeof_data;
typedef Address key_type; // start address
typedef Value mapped_value_type; // The value mapped to the ip range
typedef std::pair<Address, Value> mapped_type; // End address, value mapped to ip range
typedef std::map<key_type, mapped_type, Compare> range_map_type; // The map itself

extents();
~extents();

bool is_equal_range(key_type first, key_type last, const mapped_value_type& val) const;

void insert(key_type pos, unsigned int mb, const mapped_value_type& val);
void insert(key_type address_start, key_type address_end, mapped_value_type value);
bool defined(key_type address_start, key_type address_end);
bool defined(key_type address);
key_type get_matching_key(key_type address_start, key_type address_end); // throws error on not defined. test with defined()
mapped_value_type at(key_type address_start, key_type address_end); // throws error on not defined. test with defined()
mapped_value_type at(key_type address); // throws error on not defined. test with defined()
unsigned int sizeof_data() const;

base_type* data() { return this; }
range_map_type range_map;
};

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
extents_base<Key, Tp, TableSize, TableBits>::extents_base(key_type pos, unsigned int mb, mapped_value_type val) :
mask_bits(mb), position(pos) {
std::fill(table.begin(), table.end(), mapped_type(NULL, mapped_value_type()));
///////////////////////////////////////
// CONSTRUCTOR [PLACEHOLDER]
///////////////////////////////////////
template <class Address, class Value, class Compare >
extents<Address, Value, Compare>::extents() {
//nothing to do
return;
}

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
extents_base<Key, Tp, TableSize, TableBits>::extents_base(extents_base* parent, typename table_type::const_iterator itr) :
mask_bits(parent->mask_bits - TableBits), position(parent->partition_pos(itr)) {
std::fill(table.begin(), table.end(), mapped_type(NULL, itr->second));
///////////////////////////////////////
// DESTRUCTOR [PLACEHOLDER]
///////////////////////////////////////
template <class Address, class Value, class Compare >
extents<Address, Value, Compare>::~extents() {
//nothing to do. map destructor can handle cleanup.
return;
}

template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
extents<Key, Tp, MaskBits, TableSize, TableBits>::extents() :
base_type(key_type(), mask_bits - table_bits, mapped_value_type())
{
}
//////////////////////////////////////////////////////////////////////////////////
// INSERT O(log N) assuming no overlapping ranges
/////////////////////////////////////////////////////////////////////////////////
template <class Address, class Value, class Compare >
void extents<Address, Value, Compare>::insert(key_type address_start, key_type address_end, mapped_value_type value) {
//we allow overlap ranges though not 100% overlap but only if mapped values are the same. first remove any overlap range that has a different value.
typename range_map_type::iterator iter = range_map.upper_bound(address_start);
if( iter != range_map.begin() ) { iter--; }
bool ignore_due_to_total_overlap = false;
while( iter->first <= address_end && iter != range_map.end() ) {
key_type delete_key = iter->first;
bool do_delete_due_to_overlap = iter->first <= address_end && (iter->second).first >= address_start && (iter->second).second != value;
bool do_delete_due_to_total_overlap = address_start <= iter->first && address_end >= (iter->second).first;
iter++;
if(do_delete_due_to_overlap || do_delete_due_to_total_overlap) {
range_map.erase (delete_key);
}
else {
ignore_due_to_total_overlap = ignore_due_to_total_overlap || ( iter->first <= address_start && (iter->second).first >= address_end );
}
}

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
extents_base<Key, Tp, TableSize, TableBits>::~extents_base() {
for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++)
delete itr->first;
if(!ignore_due_to_total_overlap) {
mapped_type entry;
entry.first = address_end;
entry.second = value;
range_map.insert( std::pair<key_type,mapped_type>(address_start, entry) );
}
}

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
unsigned int
extents_base<Key, Tp, TableSize, TableBits>::sizeof_data() const {
unsigned int sum = sizeof(*this);

for (typename table_type::const_iterator itr = table.begin(), last = table.end(); itr != last; itr++)
if (itr->first != NULL)
sum += itr->first->sizeof_data();

return sum;
//////////////////////////////////////////////////////////////////////
// DEFINED O(log N) assuming no overlapping ranges
//////////////////////////////////////////////////////////////////////
template <class Address, class Value, class Compare >
bool extents<Address, Value, Compare>::defined(key_type address_start, key_type address_end) {
bool defined = false;
typename range_map_type::iterator iter = range_map.upper_bound(address_start);
if( iter != range_map.begin() ) { iter--; }
while( iter->first <= address_end && !defined && iter != range_map.end() ) {
defined = iter->first <= address_end && (iter->second).first >= address_start;
iter++;
}
return defined;
}

template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
void
extents<Key, Tp, MaskBits, TableSize, TableBits>::insert(key_type pos, unsigned int mb, const mapped_value_type& val) {
key_type mask = ~key_type() << mb;

base_type::insert(pos & mask, mb, val);
template <class Address, class Value, class Compare >
bool extents<Address, Value, Compare>::defined(key_type address) {
return defined(address, address);
}

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
void
extents_base<Key, Tp, TableSize, TableBits>::insert(key_type pos, unsigned int mb, const mapped_value_type& val) {
// RESTRICTED
typename table_type::iterator first = partition_at(pos);
typename table_type::iterator last = partition_at(pos) + mask_distance(mb) + 1;

if (mb < mask_bits) {
if (first->first == NULL)
first->first = new extents_base(this, first);
//////////////////////////////////////////////////////////////////////
// GET_MATCHING_KEY O(log N) assuming no overlapping ranges
//////////////////////////////////////////////////////////////////////
template <class Address, class Value, class Compare >
typename extents<Address, Value, Compare>::key_type extents<Address, Value, Compare>::get_matching_key(key_type address_start, key_type address_end) {
key_type key;
bool defined = false;
typename range_map_type::iterator iter = range_map.upper_bound(address_start);
if( iter != range_map.begin() ) { iter--; }
while( iter->first <= address_end && !defined && iter != range_map.end() ) {
defined = iter->first <= address_end && (iter->second).first >= address_start;
if(defined)
key = iter->first;

first->first->insert(pos, mb, val);
return;
iter++;
}

while (first != last) {
if (first->first != NULL) {
delete first->first;
first->first = NULL;
}

(first++)->second = val;
// this will cause exception to be thrown
if(!defined) {
std::out_of_range e("nothing defined for specified key");
throw e;
}
return key;
}

template <typename Key, typename Tp, unsigned int MaskBits, unsigned int TableSize, unsigned int TableBits>
bool
extents<Key, Tp, MaskBits, TableSize, TableBits>::is_equal_range(key_type first, key_type last, const mapped_value_type& val) const {
// RESTRICTED
first = std::max(first, key_type());
last = std::min(last, key_type() + (~key_type() >> (sizeof(key_type) * 8 - MaskBits)));

if (first <= last)
return base_type::is_equal_range(first, last, val);
else
return true;
//////////////////////////////////////////////////////////////////////
// AT O(log N) assuming no overlapping ranges
//////////////////////////////////////////////////////////////////////
template <class Address, class Value, class Compare >
typename extents<Address, Value, Compare>::mapped_value_type extents<Address, Value, Compare>::at(key_type address_start, key_type address_end) {
key_type key = get_matching_key(address_start, address_end);
mapped_type entry = range_map.at(key);
return entry.second;
}

template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
bool
extents_base<Key, Tp, TableSize, TableBits>::is_equal_range(key_type key_first, key_type key_last, const mapped_value_type& val) const {
// RESTRICTED
typename table_type::const_iterator first = partition_at(key_first);
typename table_type::const_iterator last = partition_at(key_last) + 1;

do {
// std::cout << "shift_amount " << key_first << ' ' << key_last << std::endl;

if (first->first == NULL && val != first->second)
return false;

if (first->first != NULL && !first->first->is_equal_range(std::max(key_first, partition_pos(first)),
std::min(key_last, partition_pos(first + 1) - 1), val))
return false;

} while (++first != last);

return true;
template <class Address, class Value, class Compare >
typename extents<Address, Value, Compare>::mapped_value_type extents<Address, Value, Compare>::at(key_type address) {
return at(address, address);
}

// Assumes 'key' is within the range of the range.
template <typename Key, typename Tp, unsigned int TableSize, unsigned int TableBits>
const typename extents_base<Key, Tp, TableSize, TableBits>::mapped_value_type&
extents_base<Key, Tp, TableSize, TableBits>::at(key_type key) const {
typename table_type::const_iterator itr = partition_at(key);

while (itr->first != NULL)
itr = itr->first->partition_at(key);

return itr->second;
//////////////////////////////////////////////////////////////////////
// SIZEOF_DATA O(1)
//////////////////////////////////////////////////////////////////////
template <class Address, class Value, class Compare >
unsigned int extents<Address, Value, Compare>::sizeof_data() const {
// we don't know overhead on map, so this won't be accurate. just estimate.
unsigned int entry_size = sizeof(key_type) + sizeof(mapped_type);
return entry_size * range_map.size();
}


}

#endif

0 comments on commit 1d18974

Please sign in to comment.