improve the external IP discovery to work with multiple external IPs (specifically IPv4 and IPv6)
This commit is contained in:
parent
3d0e5484ee
commit
aab59d04c7
|
@ -30,6 +30,7 @@ set(sources
|
||||||
i2p_stream
|
i2p_stream
|
||||||
identify_client
|
identify_client
|
||||||
ip_filter
|
ip_filter
|
||||||
|
ip_voter
|
||||||
peer_connection
|
peer_connection
|
||||||
bt_peer_connection
|
bt_peer_connection
|
||||||
web_peer_connection
|
web_peer_connection
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -490,6 +490,7 @@ SOURCES =
|
||||||
http_parser
|
http_parser
|
||||||
identify_client
|
identify_client
|
||||||
ip_filter
|
ip_filter
|
||||||
|
ip_voter
|
||||||
peer_connection
|
peer_connection
|
||||||
bt_peer_connection
|
bt_peer_connection
|
||||||
web_connection_base
|
web_connection_base
|
||||||
|
|
|
@ -61,6 +61,7 @@ nobase_include_HEADERS = \
|
||||||
io_service.hpp \
|
io_service.hpp \
|
||||||
io_service_fwd.hpp \
|
io_service_fwd.hpp \
|
||||||
ip_filter.hpp \
|
ip_filter.hpp \
|
||||||
|
ip_voter.hpp \
|
||||||
lazy_entry.hpp \
|
lazy_entry.hpp \
|
||||||
lsd.hpp \
|
lsd.hpp \
|
||||||
magnet_uri.hpp \
|
magnet_uri.hpp \
|
||||||
|
|
|
@ -57,6 +57,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "libtorrent/ip_voter.hpp"
|
||||||
#include "libtorrent/torrent_handle.hpp"
|
#include "libtorrent/torrent_handle.hpp"
|
||||||
#include "libtorrent/entry.hpp"
|
#include "libtorrent/entry.hpp"
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
|
@ -510,7 +511,8 @@ namespace libtorrent
|
||||||
// implements dht_observer
|
// implements dht_observer
|
||||||
virtual void set_external_address(address const& ip
|
virtual void set_external_address(address const& ip
|
||||||
, int source_type, address const& source);
|
, int source_type, address const& source);
|
||||||
address const& external_address() const { return m_external_address; }
|
|
||||||
|
external_ip const& external_address() const;
|
||||||
|
|
||||||
bool can_write_to_disk() const
|
bool can_write_to_disk() const
|
||||||
{ return m_disk_thread.can_write(); }
|
{ return m_disk_thread.can_write(); }
|
||||||
|
@ -1151,36 +1153,9 @@ namespace libtorrent
|
||||||
#ifdef TORRENT_UPNP_LOGGING
|
#ifdef TORRENT_UPNP_LOGGING
|
||||||
std::ofstream m_upnp_log;
|
std::ofstream m_upnp_log;
|
||||||
#endif
|
#endif
|
||||||
// TODO: factor the IP voting out to its own type, maybe templated by the address type. Have one IPv4 vote and a separate IPv6 vote. Maybe even better, have one per local interface sockets can be bound to
|
|
||||||
struct external_ip_t
|
|
||||||
{
|
|
||||||
external_ip_t(): sources(0), num_votes(0) {}
|
|
||||||
|
|
||||||
bool add_vote(sha1_hash const& k, int type);
|
// state for keeping track of external IPs
|
||||||
bool operator<(external_ip_t const& rhs) const
|
external_ip m_external_ip;
|
||||||
{
|
|
||||||
if (num_votes < rhs.num_votes) return true;
|
|
||||||
if (num_votes > rhs.num_votes) return false;
|
|
||||||
return sources < rhs.sources;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a bloom filter of the IPs that have
|
|
||||||
// reported this address
|
|
||||||
bloom_filter<16> voters;
|
|
||||||
// this is the actual external address
|
|
||||||
address addr;
|
|
||||||
// a bitmask of sources the reporters have come from
|
|
||||||
boost::uint16_t sources;
|
|
||||||
// the total number of votes for this IP
|
|
||||||
boost::uint16_t num_votes;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is a bloom filter of all the IPs that have
|
|
||||||
// been the first to report an external address. Each
|
|
||||||
// IP only gets to add a new item once.
|
|
||||||
bloom_filter<32> m_external_address_voters;
|
|
||||||
std::vector<external_ip_t> m_external_addresses;
|
|
||||||
address m_external_address;
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
typedef std::list<boost::function<boost::shared_ptr<
|
typedef std::list<boost::function<boost::shared_ptr<
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2013, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_IP_VOTER_HPP_INCLUDED
|
||||||
|
#define TORRENT_IP_VOTER_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "libtorrent/address.hpp"
|
||||||
|
#include "libtorrent/bloom_filter.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
// this is an object that keeps the state for a single external IP
|
||||||
|
// based on peoples votes
|
||||||
|
struct ip_voter
|
||||||
|
{
|
||||||
|
// returns true if a different IP is the top vote now
|
||||||
|
// i.e. we changed our idea of what our external IP is
|
||||||
|
bool cast_vote(address const& ip, int source_type, address const& sorce);
|
||||||
|
|
||||||
|
address external_address() const { return m_external_address; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct external_ip_t
|
||||||
|
{
|
||||||
|
external_ip_t(): sources(0), num_votes(0) {}
|
||||||
|
|
||||||
|
bool add_vote(sha1_hash const& k, int type);
|
||||||
|
bool operator<(external_ip_t const& rhs) const
|
||||||
|
{
|
||||||
|
if (num_votes < rhs.num_votes) return true;
|
||||||
|
if (num_votes > rhs.num_votes) return false;
|
||||||
|
return sources < rhs.sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a bloom filter of the IPs that have
|
||||||
|
// reported this address
|
||||||
|
bloom_filter<16> voters;
|
||||||
|
// this is the actual external address
|
||||||
|
address addr;
|
||||||
|
// a bitmask of sources the reporters have come from
|
||||||
|
boost::uint16_t sources;
|
||||||
|
// the total number of votes for this IP
|
||||||
|
boost::uint16_t num_votes;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is a bloom filter of all the IPs that have
|
||||||
|
// been the first to report an external address. Each
|
||||||
|
// IP only gets to add a new item once.
|
||||||
|
bloom_filter<32> m_external_address_voters;
|
||||||
|
std::vector<external_ip_t> m_external_addresses;
|
||||||
|
address m_external_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this keeps track of multiple external IPs (for now, just IPv6 and IPv4, but
|
||||||
|
// it could be extended to deal with loopback and local network addresses as well)
|
||||||
|
struct external_ip
|
||||||
|
{
|
||||||
|
// returns true if a different IP is the top vote now
|
||||||
|
// i.e. we changed our idea of what our external IP is
|
||||||
|
bool cast_vote(address const& ip, int source_type, address const& source);
|
||||||
|
|
||||||
|
// the external IP as it would be observed from `ip`
|
||||||
|
address external_address(address const& ip) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// for now, assume one external IPv4 and one external IPv6 address
|
||||||
|
// 0 = IPv4 1 = IPv6
|
||||||
|
// TODO: instead, have one instance per possible subnet, global IPv4, global IPv6, loopback, 192.168.x.x, 10.x.x.x, etc.
|
||||||
|
ip_voter m_vote_group[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace libtorrent
|
||||||
|
|
||||||
class torrent;
|
class torrent;
|
||||||
class peer_connection;
|
class peer_connection;
|
||||||
|
struct external_ip;
|
||||||
|
|
||||||
// this is compressed as an unsigned floating point value
|
// this is compressed as an unsigned floating point value
|
||||||
// the top 13 bits are the mantissa and the low
|
// the top 13 bits are the mantissa and the low
|
||||||
|
@ -178,7 +179,7 @@ namespace libtorrent
|
||||||
size_type total_download() const;
|
size_type total_download() const;
|
||||||
size_type total_upload() const;
|
size_type total_upload() const;
|
||||||
|
|
||||||
boost::uint32_t rank(tcp::endpoint const& external) const;
|
boost::uint32_t rank(external_ip const& external, int external_port) const;
|
||||||
|
|
||||||
libtorrent::address address() const;
|
libtorrent::address address() const;
|
||||||
char const* dest() const;
|
char const* dest() const;
|
||||||
|
@ -442,7 +443,7 @@ namespace libtorrent
|
||||||
|
|
||||||
bool compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const;
|
bool compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const;
|
||||||
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||||
, tcp::endpoint const& external_ip) const;
|
, external_ip const& external, int source_port) const;
|
||||||
|
|
||||||
iterator find_connect_candidate(int session_time);
|
iterator find_connect_candidate(int session_time);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
||||||
identify_client.cpp \
|
identify_client.cpp \
|
||||||
instantiate_connection.cpp \
|
instantiate_connection.cpp \
|
||||||
ip_filter.cpp \
|
ip_filter.cpp \
|
||||||
|
ip_voter.cpp \
|
||||||
lazy_bdecode.cpp \
|
lazy_bdecode.cpp \
|
||||||
logger.cpp \
|
logger.cpp \
|
||||||
lsd.cpp \
|
lsd.cpp \
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2013, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libtorrent/ip_voter.hpp"
|
||||||
|
#include "libtorrent/broadcast_socket.hpp" // for is_any() etc.
|
||||||
|
#include "libtorrent/socket_io.hpp" // for hash_address
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
namespace libtorrent
|
||||||
|
{
|
||||||
|
bool ip_voter::cast_vote(address const& ip
|
||||||
|
, int source_type, address const& source)
|
||||||
|
{
|
||||||
|
if (is_any(ip)) return false;
|
||||||
|
if (is_local(ip)) return false;
|
||||||
|
if (is_loopback(ip)) return false;
|
||||||
|
|
||||||
|
// don't trust source that aren't connected to us
|
||||||
|
// on a different address family than the external
|
||||||
|
// IP they claim we have
|
||||||
|
if (ip.is_v4() != source.is_v4()) return false;
|
||||||
|
|
||||||
|
// this is the key to use for the bloom filters
|
||||||
|
// it represents the identity of the voter
|
||||||
|
sha1_hash k;
|
||||||
|
hash_address(source, k);
|
||||||
|
|
||||||
|
// do we already have an entry for this external IP?
|
||||||
|
std::vector<external_ip_t>::iterator i = std::find_if(m_external_addresses.begin()
|
||||||
|
, m_external_addresses.end(), boost::bind(&external_ip_t::addr, _1) == ip);
|
||||||
|
|
||||||
|
if (i == m_external_addresses.end())
|
||||||
|
{
|
||||||
|
// each IP only gets to add a new IP once
|
||||||
|
if (m_external_address_voters.find(k)) return false;
|
||||||
|
|
||||||
|
if (m_external_addresses.size() > 40)
|
||||||
|
{
|
||||||
|
if (random() % 100 < 50)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// use stable sort here to maintain the fifo-order
|
||||||
|
// of the entries with the same number of votes
|
||||||
|
// this will sort in ascending order, i.e. the lowest
|
||||||
|
// votes first. Also, the oldest are first, so this
|
||||||
|
// is a sort of weighted LRU.
|
||||||
|
std::stable_sort(m_external_addresses.begin(), m_external_addresses.end());
|
||||||
|
|
||||||
|
// erase the first element, since this is the
|
||||||
|
// oldest entry and the one with lowst number
|
||||||
|
// of votes. This makes sense because the oldest
|
||||||
|
// entry has had the longest time to receive more
|
||||||
|
// votes to be bumped up
|
||||||
|
m_external_addresses.erase(m_external_addresses.begin());
|
||||||
|
}
|
||||||
|
m_external_addresses.push_back(external_ip_t());
|
||||||
|
i = m_external_addresses.end() - 1;
|
||||||
|
i->addr = ip;
|
||||||
|
}
|
||||||
|
// add one more vote to this external IP
|
||||||
|
if (!i->add_vote(k, source_type)) return false;
|
||||||
|
|
||||||
|
i = std::max_element(m_external_addresses.begin(), m_external_addresses.end());
|
||||||
|
TORRENT_ASSERT(i != m_external_addresses.end());
|
||||||
|
|
||||||
|
if (i->addr == m_external_address) return false;
|
||||||
|
|
||||||
|
m_external_address = i->addr;
|
||||||
|
m_external_address_voters.clear();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ip_voter::external_ip_t::add_vote(sha1_hash const& k, int type)
|
||||||
|
{
|
||||||
|
sources |= type;
|
||||||
|
if (voters.find(k)) return false;
|
||||||
|
voters.set(k);
|
||||||
|
++num_votes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool external_ip::cast_vote(address const& ip, int source_type, address const& source)
|
||||||
|
{
|
||||||
|
return m_vote_group[ip.is_v6()].cast_vote(ip, source_type, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
address external_ip::external_address(address const& ip) const
|
||||||
|
{
|
||||||
|
return m_vote_group[ip.is_v6()].external_address();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ namespace libtorrent { namespace dht
|
||||||
dht_tracker::dht_tracker(libtorrent::aux::session_impl& ses, rate_limited_udp_socket& sock
|
dht_tracker::dht_tracker(libtorrent::aux::session_impl& ses, rate_limited_udp_socket& sock
|
||||||
, dht_settings const& settings, entry const* state)
|
, dht_settings const& settings, entry const* state)
|
||||||
: m_dht(&ses, this, settings, extract_node_id(state)
|
: m_dht(&ses, this, settings, extract_node_id(state)
|
||||||
, ses.external_address(), &ses)
|
, ses.external_address().external_address(address_v4()), &ses)
|
||||||
, m_sock(sock)
|
, m_sock(sock)
|
||||||
, m_last_new_key(time_now() - minutes(key_refresh))
|
, m_last_new_key(time_now() - minutes(key_refresh))
|
||||||
, m_timer(sock.get_io_service())
|
, m_timer(sock.get_io_service())
|
||||||
|
|
|
@ -1114,7 +1114,8 @@ namespace libtorrent
|
||||||
|
|
||||||
boost::uint32_t peer_connection::peer_rank() const
|
boost::uint32_t peer_connection::peer_rank() const
|
||||||
{
|
{
|
||||||
return m_peer_info->rank(tcp::endpoint(m_ses.external_address(), m_ses.listen_port()));
|
return m_peer_info->rank(m_ses.external_address()
|
||||||
|
, m_ses.listen_port());
|
||||||
}
|
}
|
||||||
|
|
||||||
// message handlers
|
// message handlers
|
||||||
|
|
|
@ -742,7 +742,8 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(m_finished == m_torrent->is_finished());
|
TORRENT_ASSERT(m_finished == m_torrent->is_finished());
|
||||||
|
|
||||||
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
||||||
tcp::endpoint external_ip(m_torrent->session().external_address(), m_torrent->session().listen_port());
|
external_ip const& external = m_torrent->session().external_address();
|
||||||
|
int external_port = m_torrent->session().listen_port();
|
||||||
|
|
||||||
if (m_round_robin >= int(m_peers.size())) m_round_robin = 0;
|
if (m_round_robin >= int(m_peers.size())) m_round_robin = 0;
|
||||||
|
|
||||||
|
@ -809,7 +810,7 @@ namespace libtorrent
|
||||||
// pe, which is the peer m_round_robin points to. If it is, just
|
// pe, which is the peer m_round_robin points to. If it is, just
|
||||||
// keep looking.
|
// keep looking.
|
||||||
if (candidate != -1
|
if (candidate != -1
|
||||||
&& compare_peer(*m_peers[candidate], pe, external_ip)) continue;
|
&& compare_peer(*m_peers[candidate], pe, external, external_port)) continue;
|
||||||
|
|
||||||
if (pe.last_connected
|
if (pe.last_connected
|
||||||
&& session_time - pe.last_connected <
|
&& session_time - pe.last_connected <
|
||||||
|
@ -831,9 +832,9 @@ namespace libtorrent
|
||||||
(*m_torrent->session().m_logger) << time_now_string()
|
(*m_torrent->session().m_logger) << time_now_string()
|
||||||
<< " *** FOUND CONNECTION CANDIDATE ["
|
<< " *** FOUND CONNECTION CANDIDATE ["
|
||||||
" ip: " << m_peers[candidate]->ip() <<
|
" ip: " << m_peers[candidate]->ip() <<
|
||||||
" d: " << cidr_distance(external_ip.address(), m_peers[candidate]->address()) <<
|
" d: " << cidr_distance(external.address(m_peers[candidate]->address()), m_peers[candidate]->address()) <<
|
||||||
" rank: " << m_peers[candidate]->rank(external_ip) <<
|
" rank: " << m_peers[candidate]->rank(external, external_port) <<
|
||||||
" external: " << external_ip.address() <<
|
" external: " << external.external_address(m_peers[candidate]->address()) <<
|
||||||
" t: " << (session_time - m_peers[candidate]->last_connected) <<
|
" t: " << (session_time - m_peers[candidate]->last_connected) <<
|
||||||
" ]\n";
|
" ]\n";
|
||||||
}
|
}
|
||||||
|
@ -1903,12 +1904,13 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOOD: pass in both an IPv6 and IPv4 address here
|
// TOOD: pass in both an IPv6 and IPv4 address here
|
||||||
boost::uint32_t policy::peer::rank(tcp::endpoint const& external) const
|
boost::uint32_t policy::peer::rank(external_ip const& external, int external_port) const
|
||||||
{
|
{
|
||||||
//TODO: really, keep track of one external IP per address family
|
//TODO: how do we deal with our external address changing? Pass in a force-update maybe? and keep a version number in policy
|
||||||
//TODO: how do we deal with our external address changing?
|
|
||||||
if (peer_rank == 0)
|
if (peer_rank == 0)
|
||||||
peer_rank = peer_priority(external, tcp::endpoint(this->address(), this->port));
|
peer_rank = peer_priority(
|
||||||
|
tcp::endpoint(external.external_address(this->address()), external_port)
|
||||||
|
, tcp::endpoint(this->address(), this->port));
|
||||||
return peer_rank;
|
return peer_rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1963,7 +1965,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// this returns true if lhs is a better connect candidate than rhs
|
// this returns true if lhs is a better connect candidate than rhs
|
||||||
bool policy::compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
bool policy::compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||||
, tcp::endpoint const& external_ip) const
|
, external_ip const& external, int external_port) const
|
||||||
{
|
{
|
||||||
// prefer peers with lower failcount
|
// prefer peers with lower failcount
|
||||||
if (lhs.failcount != rhs.failcount)
|
if (lhs.failcount != rhs.failcount)
|
||||||
|
@ -1990,8 +1992,8 @@ namespace libtorrent
|
||||||
if (lhs_as != rhs_as) return lhs_as > rhs_as;
|
if (lhs_as != rhs_as) return lhs_as > rhs_as;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
boost::uint32_t lhs_peer_rank = lhs.rank(external_ip);
|
boost::uint32_t lhs_peer_rank = lhs.rank(external, external_port);
|
||||||
boost::uint32_t rhs_peer_rank = rhs.rank(external_ip);
|
boost::uint32_t rhs_peer_rank = rhs.rank(external, external_port);
|
||||||
if (lhs_peer_rank > rhs_peer_rank) return true;
|
if (lhs_peer_rank > rhs_peer_rank) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6085,92 +6085,22 @@ retry:
|
||||||
m_upnp = 0;
|
m_upnp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool session_impl::external_ip_t::add_vote(sha1_hash const& k, int type)
|
external_ip const& session_impl::external_address() const
|
||||||
{
|
{ return m_external_ip; }
|
||||||
sources |= type;
|
|
||||||
if (voters.find(k)) return false;
|
|
||||||
voters.set(k);
|
|
||||||
++num_votes;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void session_impl::set_external_address(address const& ip
|
void session_impl::set_external_address(address const& ip
|
||||||
, int source_type, address const& source)
|
, int source_type, address const& source)
|
||||||
{
|
{
|
||||||
if (is_any(ip)) return;
|
|
||||||
if (is_local(ip)) return;
|
|
||||||
if (is_loopback(ip)) return;
|
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING
|
||||||
session_log(": set_external_address(%s, %d, %s)", print_address(ip).c_str()
|
session_log(": set_external_address(%s, %d, %s)", print_address(ip).c_str()
|
||||||
, source_type, print_address(source).c_str());
|
, source_type, print_address(source).c_str());
|
||||||
#endif
|
#endif
|
||||||
// this is the key to use for the bloom filters
|
|
||||||
// it represents the identity of the voter
|
|
||||||
sha1_hash k;
|
|
||||||
hash_address(source, k);
|
|
||||||
|
|
||||||
// do we already have an entry for this external IP?
|
if (!m_external_ip.cast_vote(ip, source_type, source));
|
||||||
std::vector<external_ip_t>::iterator i = std::find_if(m_external_addresses.begin()
|
|
||||||
, m_external_addresses.end(), boost::bind(&external_ip_t::addr, _1) == ip);
|
|
||||||
|
|
||||||
if (i == m_external_addresses.end())
|
|
||||||
{
|
|
||||||
// each IP only gets to add a new IP once
|
|
||||||
if (m_external_address_voters.find(k)) return;
|
|
||||||
|
|
||||||
if (m_external_addresses.size() > 20)
|
|
||||||
{
|
|
||||||
if (random() < UINT_MAX / 2)
|
|
||||||
{
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING
|
|
||||||
session_log(": More than 20 slots, dopped");
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// use stable sort here to maintain the fifo-order
|
|
||||||
// of the entries with the same number of votes
|
|
||||||
// this will sort in ascending order, i.e. the lowest
|
|
||||||
// votes first. Also, the oldest are first, so this
|
|
||||||
// is a sort of weighted LRU.
|
|
||||||
std::stable_sort(m_external_addresses.begin(), m_external_addresses.end());
|
|
||||||
// erase the first element, since this is the
|
|
||||||
// oldest entry and the one with lowst number
|
|
||||||
// of votes. This makes sense because the oldest
|
|
||||||
// entry has had the longest time to receive more
|
|
||||||
// votes to be bumped up
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING
|
|
||||||
session_log(" More than 20 slots, dopping %s (%d)"
|
|
||||||
, print_address(m_external_addresses.front().addr).c_str()
|
|
||||||
, m_external_addresses.front().num_votes);
|
|
||||||
#endif
|
|
||||||
m_external_addresses.erase(m_external_addresses.begin());
|
|
||||||
}
|
|
||||||
m_external_addresses.push_back(external_ip_t());
|
|
||||||
i = m_external_addresses.end() - 1;
|
|
||||||
i->addr = ip;
|
|
||||||
}
|
|
||||||
// add one more vote to this external IP
|
|
||||||
if (!i->add_vote(k, source_type)) return;
|
|
||||||
|
|
||||||
i = std::max_element(m_external_addresses.begin(), m_external_addresses.end());
|
|
||||||
TORRENT_ASSERT(i != m_external_addresses.end());
|
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING
|
|
||||||
for (std::vector<external_ip_t>::iterator j = m_external_addresses.begin()
|
|
||||||
, end(m_external_addresses.end()); j != end; ++j)
|
|
||||||
{
|
|
||||||
session_log("%s %s votes: %d", (j == i)?"-->":" "
|
|
||||||
, print_address(j->addr).c_str(), j->num_votes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (i->addr == m_external_address) return;
|
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING
|
||||||
session_log(" external IP updated");
|
session_log(" external IP updated");
|
||||||
#endif
|
#endif
|
||||||
m_external_address = i->addr;
|
|
||||||
m_external_address_voters.clear();
|
|
||||||
|
|
||||||
if (m_alerts.should_post<external_ip_alert>())
|
if (m_alerts.should_post<external_ip_alert>())
|
||||||
m_alerts.post_alert(external_ip_alert(ip));
|
m_alerts.post_alert(external_ip_alert(ip));
|
||||||
|
@ -6178,6 +6108,7 @@ retry:
|
||||||
// since we have a new external IP now, we need to
|
// since we have a new external IP now, we need to
|
||||||
// restart the DHT with a new node ID
|
// restart the DHT with a new node ID
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
// TODO: we only need to do this if our global IPv4 address has changed
|
||||||
if (m_dht)
|
if (m_dht)
|
||||||
{
|
{
|
||||||
entry s = m_dht->state();
|
entry s = m_dht->state();
|
||||||
|
|
|
@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/bloom_filter.hpp"
|
#include "libtorrent/bloom_filter.hpp"
|
||||||
#include "libtorrent/aux_/session_impl.hpp"
|
#include "libtorrent/aux_/session_impl.hpp"
|
||||||
#include "libtorrent/rsa.hpp"
|
#include "libtorrent/rsa.hpp"
|
||||||
|
#include "libtorrent/ip_voter.hpp"
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
#include "libtorrent/kademlia/node_id.hpp"
|
#include "libtorrent/kademlia/node_id.hpp"
|
||||||
#include "libtorrent/kademlia/routing_table.hpp"
|
#include "libtorrent/kademlia/routing_table.hpp"
|
||||||
|
@ -394,6 +395,13 @@ address rand_v4()
|
||||||
return address_v4((rand() << 16 | rand()) & 0xffffffff);
|
return address_v4((rand() << 16 | rand()) & 0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address rand_v6()
|
||||||
|
{
|
||||||
|
address_v6::bytes_type bytes;
|
||||||
|
for (int i = 0; i < bytes.size(); ++i) bytes[i] = rand();
|
||||||
|
return address_v6(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
int test_main()
|
int test_main()
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
@ -537,12 +545,7 @@ int test_main()
|
||||||
}
|
}
|
||||||
|
|
||||||
// test external ip voting
|
// test external ip voting
|
||||||
aux::session_impl* ses = new aux::session_impl(std::pair<int, int>(0,0)
|
external_ip ipv1;
|
||||||
, fingerprint("LT", 0, 0, 0, 0), "0.0.0.0", 0
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
, ""
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
// test a single malicious node
|
// test a single malicious node
|
||||||
// adds 50 legitimate responses from different peers
|
// adds 50 legitimate responses from different peers
|
||||||
|
@ -551,39 +554,28 @@ int test_main()
|
||||||
address malicious = address_v4::from_string("4.4.4.4");
|
address malicious = address_v4::from_string("4.4.4.4");
|
||||||
for (int i = 0; i < 50; ++i)
|
for (int i = 0; i < 50; ++i)
|
||||||
{
|
{
|
||||||
ses->set_external_address(real_external, aux::session_impl::source_dht, rand_v4());
|
ipv1.cast_vote(real_external, aux::session_impl::source_dht, rand_v4());
|
||||||
ses->set_external_address(rand_v4(), aux::session_impl::source_dht, malicious);
|
ipv1.cast_vote(rand_v4(), aux::session_impl::source_dht, malicious);
|
||||||
}
|
}
|
||||||
TEST_CHECK(ses->external_address() == real_external);
|
TEST_CHECK(ipv1.external_address(rand_v4()) == real_external);
|
||||||
ses->abort();
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
external_ip ipv2;
|
||||||
ses->m_logger.reset();
|
|
||||||
#endif
|
|
||||||
delete ses;
|
|
||||||
ses = new aux::session_impl(std::pair<int, int>(0,0)
|
|
||||||
, fingerprint("LT", 0, 0, 0, 0), "0.0.0.0", 0
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
, ""
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
// test a single malicious node
|
// test a single malicious node
|
||||||
// adds 50 legitimate responses from different peers
|
// adds 50 legitimate responses from different peers
|
||||||
// and 50 consistent malicious responses from the same peer
|
// and 50 consistent malicious responses from the same peer
|
||||||
real_external = address_v4::from_string("5.5.5.5");
|
address real_external1 = address_v4::from_string("5.5.5.5");
|
||||||
|
address real_external2 = address_v6::from_string("2f80::1");
|
||||||
malicious = address_v4::from_string("4.4.4.4");
|
malicious = address_v4::from_string("4.4.4.4");
|
||||||
address malicious_external = address_v4::from_string("3.3.3.3");
|
address malicious_external = address_v4::from_string("3.3.3.3");
|
||||||
for (int i = 0; i < 50; ++i)
|
for (int i = 0; i < 50; ++i)
|
||||||
{
|
{
|
||||||
ses->set_external_address(real_external, aux::session_impl::source_dht, rand_v4());
|
ipv2.cast_vote(real_external1, aux::session_impl::source_dht, rand_v4());
|
||||||
ses->set_external_address(malicious_external, aux::session_impl::source_dht, malicious);
|
ipv2.cast_vote(real_external2, aux::session_impl::source_dht, rand_v6());
|
||||||
|
ipv2.cast_vote(malicious_external, aux::session_impl::source_dht, malicious);
|
||||||
}
|
}
|
||||||
TEST_CHECK(ses->external_address() == real_external);
|
TEST_CHECK(ipv2.external_address(rand_v4()) == real_external1);
|
||||||
ses->abort();
|
TEST_CHECK(ipv2.external_address(rand_v6()) == real_external2);
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
ses->m_logger.reset();
|
|
||||||
#endif
|
|
||||||
delete ses;
|
|
||||||
|
|
||||||
// test bloom_filter
|
// test bloom_filter
|
||||||
bloom_filter<32> filter;
|
bloom_filter<32> filter;
|
||||||
|
|
Loading…
Reference in New Issue