limit tracker announces and SOCKS5 connection attempts to listen_socket_t that actually can reach the target
This commit is contained in:
parent
a0b0f2aec5
commit
4ceb2ea467
|
@ -169,10 +169,16 @@ class test_torrent_handle(unittest.TestCase):
|
|||
# wait a bit until the endpoints list gets populated
|
||||
while len(self.h.trackers()[0]['endpoints']) == 0:
|
||||
time.sleep(0.1)
|
||||
pickled_trackers = pickle.dumps(self.h.trackers())
|
||||
|
||||
trackers = self.h.trackers()
|
||||
self.assertEqual(trackers[0]['url'], 'udp://tracker1.com')
|
||||
# this is not necessarily 0, it could also be (EHOSTUNREACH) if the
|
||||
# local machine doesn't support the address family
|
||||
expect_value = trackers[0]['endpoints'][0]['last_error']['value']
|
||||
pickled_trackers = pickle.dumps(trackers)
|
||||
unpickled_trackers = pickle.loads(pickled_trackers)
|
||||
self.assertEqual(unpickled_trackers[0]['url'], 'udp://tracker1.com')
|
||||
self.assertEqual(unpickled_trackers[0]['endpoints'][0]['last_error']['value'], 0)
|
||||
self.assertEqual(unpickled_trackers[0]['endpoints'][0]['last_error']['value'], expect_value)
|
||||
|
||||
def test_file_status(self):
|
||||
self.setup()
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace libtorrent { namespace aux {
|
|||
|
||||
address get_external_address() const;
|
||||
tcp::endpoint get_local_endpoint() const;
|
||||
bool can_route(address const&) const;
|
||||
|
||||
bool is_ssl() const;
|
||||
|
||||
|
|
|
@ -154,6 +154,12 @@ namespace aux {
|
|||
listen_socket_t& operator=(listen_socket_t const&) = delete;
|
||||
listen_socket_t& operator=(listen_socket_t&&) = delete;
|
||||
|
||||
// returns true if this listen socket/interface can reach and be reached
|
||||
// by the given address. This is useful to know whether it should be
|
||||
// annoucned to a tracker (given the tracker's IP) or whether it should
|
||||
// have a SOCKS5 UDP tunnel set up (given the IP of the socks proxy)
|
||||
bool can_route(address const&) const;
|
||||
|
||||
// this may be empty but can be set
|
||||
// to the WAN IP address of a NAT router
|
||||
ip_voter external_address;
|
||||
|
@ -161,6 +167,8 @@ namespace aux {
|
|||
// this is a cached local endpoint for the listen TCP socket
|
||||
tcp::endpoint local_endpoint;
|
||||
|
||||
address netmask;
|
||||
|
||||
// the name of the device the socket is bound to, may be empty
|
||||
// if the socket is not bound to a device
|
||||
std::string device;
|
||||
|
@ -229,8 +237,8 @@ namespace aux {
|
|||
struct TORRENT_EXTRA_EXPORT listen_endpoint_t
|
||||
{
|
||||
listen_endpoint_t(address const& adr, int p, std::string dev, transport s
|
||||
, listen_socket_flags_t f)
|
||||
: addr(adr), port(p), device(std::move(dev)), ssl(s), flags(f) {}
|
||||
, listen_socket_flags_t f, address const& nmask = address{})
|
||||
: addr(adr), netmask(nmask), port(p), device(std::move(dev)), ssl(s), flags(f) {}
|
||||
|
||||
bool operator==(listen_endpoint_t const& o) const
|
||||
{
|
||||
|
@ -238,6 +246,10 @@ namespace aux {
|
|||
}
|
||||
|
||||
address addr;
|
||||
// if this listen endpoint/interface doesn't have a gateway, we cannot
|
||||
// route outside of our network, this netmask defines the range of our
|
||||
// local network
|
||||
address netmask;
|
||||
int port;
|
||||
std::string device;
|
||||
transport ssl;
|
||||
|
@ -258,6 +270,10 @@ namespace aux {
|
|||
span<ip_interface const> ifs
|
||||
, std::vector<listen_endpoint_t>& eps);
|
||||
|
||||
TORRENT_EXTRA_EXPORT void expand_devices(span<ip_interface const>
|
||||
, span<ip_route const> routes
|
||||
, std::vector<listen_endpoint_t>& eps);
|
||||
|
||||
// this is the link between the main thread and the
|
||||
// thread started to run the main downloader loop
|
||||
struct TORRENT_EXTRA_EXPORT session_impl final
|
||||
|
|
|
@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/utp_socket_manager.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/aux_/allocating_handler.hpp"
|
||||
#include "libtorrent/aux_/listen_socket_handle.hpp"
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
@ -47,13 +48,14 @@ namespace aux {
|
|||
|
||||
struct listen_endpoint_t;
|
||||
struct proxy_settings;
|
||||
struct listen_socket_t;
|
||||
|
||||
enum class transport : std::uint8_t { plaintext, ssl };
|
||||
|
||||
struct session_udp_socket : utp_socket_interface
|
||||
{
|
||||
explicit session_udp_socket(io_service& ios)
|
||||
: sock(ios) {}
|
||||
explicit session_udp_socket(io_service& ios, listen_socket_handle ls)
|
||||
: sock(ios, std::move(ls)) {}
|
||||
|
||||
udp::endpoint local_endpoint() override { return sock.local_endpoint(); }
|
||||
|
||||
|
@ -73,7 +75,7 @@ namespace aux {
|
|||
struct outgoing_udp_socket final : session_udp_socket
|
||||
{
|
||||
outgoing_udp_socket(io_service& ios, std::string const& dev, transport ssl_)
|
||||
: session_udp_socket(ios), device(dev), ssl(ssl_) {}
|
||||
: session_udp_socket(ios, listen_socket_handle{}), device(dev), ssl(ssl_) {}
|
||||
|
||||
// the name of the device the socket is bound to, may be empty
|
||||
// if the socket is not bound to a device
|
||||
|
|
|
@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/debug.hpp"
|
||||
#include "libtorrent/span.hpp"
|
||||
#include "libtorrent/flags.hpp"
|
||||
#include "libtorrent/aux_/listen_socket_handle.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
@ -54,7 +55,7 @@ namespace libtorrent {
|
|||
class TORRENT_EXTRA_EXPORT udp_socket : single_threaded
|
||||
{
|
||||
public:
|
||||
explicit udp_socket(io_service& ios);
|
||||
explicit udp_socket(io_service& ios, aux::listen_socket_handle ls);
|
||||
|
||||
static constexpr udp_send_flags_t peer_connection = 0_bit;
|
||||
static constexpr udp_send_flags_t tracker_connection = 1_bit;
|
||||
|
@ -145,6 +146,7 @@ namespace libtorrent {
|
|||
|
||||
using receive_buffer = std::array<char, 1500>;
|
||||
std::unique_ptr<receive_buffer> m_buf;
|
||||
aux::listen_socket_handle m_listen_socket;
|
||||
|
||||
std::uint16_t m_bind_port;
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ TORRENT_TEST(dht_rate_limit)
|
|||
asio::io_service dht_ios(sim, address_v4::from_string("40.30.20.10"));
|
||||
|
||||
// receiver (the DHT under test)
|
||||
lt::udp_socket sock(dht_ios);
|
||||
lt::udp_socket sock(dht_ios, lt::aux::listen_socket_handle{});
|
||||
obs o;
|
||||
auto ls = std::make_shared<lt::aux::listen_socket_t>();
|
||||
ls->external_address.cast_vote(address_v4::from_string("40.30.20.10")
|
||||
|
@ -230,7 +230,7 @@ TORRENT_TEST(dht_delete_socket)
|
|||
sim::simulation sim(cfg);
|
||||
sim::asio::io_service dht_ios(sim, lt::address_v4::from_string("40.30.20.10"));
|
||||
|
||||
lt::udp_socket sock(dht_ios);
|
||||
lt::udp_socket sock(dht_ios, lt::aux::listen_socket_handle{});
|
||||
error_code ec;
|
||||
sock.bind(udp::endpoint(address_v4::from_string("40.30.20.10"), 8888), ec);
|
||||
|
||||
|
|
|
@ -472,6 +472,8 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl
|
|||
|
||||
if (a1.is_v6())
|
||||
{
|
||||
if (a1.to_v6().scope_id() != a2.to_v6().scope_id()) return false;
|
||||
|
||||
address_v6::bytes_type b1 = a1.to_v6().to_bytes();
|
||||
address_v6::bytes_type b2 = a2.to_v6().to_bytes();
|
||||
address_v6::bytes_type m = mask.to_v6().to_bytes();
|
||||
|
|
|
@ -529,21 +529,9 @@ void http_connection::on_resolve(error_code const& e
|
|||
// only connect to addresses of the same family
|
||||
if (m_bind_addr)
|
||||
{
|
||||
auto new_end = std::partition(m_endpoints.begin(), m_endpoints.end()
|
||||
, [this] (tcp::endpoint const& ep)
|
||||
{
|
||||
if (is_v4(ep) != m_bind_addr->is_v4())
|
||||
return false;
|
||||
if (is_v4(ep) && m_bind_addr->is_v4())
|
||||
return true;
|
||||
TORRENT_ASSERT(is_v6(ep) && m_bind_addr->is_v6());
|
||||
// don't try to connect to a global address with a local source address
|
||||
// this is mainly needed to prevent attempting to connect to a global
|
||||
// address using a ULA as the source
|
||||
if (!is_local(ep.address()) && is_local(*m_bind_addr))
|
||||
return false;
|
||||
return ep.address().to_v6().scope_id() == m_bind_addr->to_v6().scope_id();
|
||||
});
|
||||
auto const new_end = std::remove_if(m_endpoints.begin(), m_endpoints.end()
|
||||
, [&](tcp::endpoint const& ep) { return is_v4(ep) != m_bind_addr->is_v4(); });
|
||||
|
||||
m_endpoints.erase(new_end, m_endpoints.end());
|
||||
if (m_endpoints.empty())
|
||||
{
|
||||
|
|
|
@ -272,6 +272,20 @@ namespace libtorrent {
|
|||
void http_tracker_connection::on_filter(http_connection& c
|
||||
, std::vector<tcp::endpoint>& endpoints)
|
||||
{
|
||||
// filter all endpoints we cannot reach from this listen socket, which may
|
||||
// be all of them, in which case we should not announce this listen socket
|
||||
// to this tracker
|
||||
auto const ls = bind_socket();
|
||||
endpoints.erase(std::remove_if(endpoints.begin(), endpoints.end()
|
||||
, [&](tcp::endpoint const& ep) { return !ls.can_route(ep.address()); })
|
||||
, endpoints.end());
|
||||
|
||||
if (endpoints.empty())
|
||||
{
|
||||
fail(error_code(boost::system::errc::host_unreachable, system_category()));
|
||||
return;
|
||||
}
|
||||
|
||||
TORRENT_UNUSED(c);
|
||||
if (!tracker_req().filter) return;
|
||||
|
||||
|
|
|
@ -64,4 +64,11 @@ namespace libtorrent { namespace aux {
|
|||
return m_sock.lock().get();
|
||||
}
|
||||
|
||||
bool listen_socket_handle::can_route(address const& a) const
|
||||
{
|
||||
auto s = m_sock.lock();
|
||||
if (!s) return false;
|
||||
return s->can_route(a);
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
@ -283,6 +283,70 @@ namespace aux {
|
|||
}
|
||||
}
|
||||
|
||||
void expand_devices(span<ip_interface const> const ifs
|
||||
, span<ip_route const> const routes
|
||||
, std::vector<listen_endpoint_t>& eps)
|
||||
{
|
||||
for (auto& ep : eps)
|
||||
{
|
||||
auto const iface = ep.device.empty()
|
||||
? std::find_if(ifs.begin(), ifs.end(), [&](ip_interface const& ipface)
|
||||
{
|
||||
return match_addr_mask(ipface.interface_address, ep.addr, ipface.netmask);
|
||||
})
|
||||
: std::find_if(ifs.begin(), ifs.end(), [&](ip_interface const& ipface)
|
||||
{
|
||||
return ipface.name == ep.device
|
||||
&& match_addr_mask(ipface.interface_address, ep.addr, ipface.netmask);
|
||||
});
|
||||
|
||||
if (iface == ifs.end())
|
||||
{
|
||||
// we can't find which device this is for, just assume we can't
|
||||
// reach anything on it
|
||||
ep.netmask = build_netmask(0, ep.addr.is_v4() ? AF_INET : AF_INET6);
|
||||
continue;
|
||||
}
|
||||
|
||||
ep.netmask = iface->netmask;
|
||||
|
||||
bool const v4 = iface->interface_address.is_v4();
|
||||
|
||||
// also record whether the device has a gateway associated with it
|
||||
// (which indicates it can be used to reach the internet)
|
||||
// only gateways inside the interface's network count
|
||||
bool const has_gateway = std::find_if(routes.begin(), routes.end(), [&](ip_route const& r)
|
||||
{
|
||||
return r.destination.is_unspecified()
|
||||
&& r.destination.is_v4() == v4
|
||||
&& !r.gateway.is_unspecified()
|
||||
&& match_addr_mask(r.gateway, iface->interface_address, iface->netmask)
|
||||
&& strcmp(r.name, iface->name) == 0;
|
||||
}) != routes.end();
|
||||
|
||||
if (has_gateway)
|
||||
ep.flags |= listen_socket_t::has_gateway;
|
||||
|
||||
ep.device = iface->name;
|
||||
}
|
||||
}
|
||||
|
||||
bool listen_socket_t::can_route(address const& addr) const
|
||||
{
|
||||
if (local_endpoint.address().is_v4() != addr.is_v4()) return false;
|
||||
|
||||
if (local_endpoint.address().is_v6()
|
||||
&& local_endpoint.address().to_v6().scope_id() != addr.to_v6().scope_id())
|
||||
return false;
|
||||
|
||||
if (flags & has_gateway) return true;
|
||||
if (local_endpoint.address() == addr) return true;
|
||||
if (local_endpoint.address().is_unspecified()) return true;
|
||||
if (match_addr_mask(addr, local_endpoint.address(), netmask)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void session_impl::init_peer_class_filter(bool unlimited_local)
|
||||
{
|
||||
// set the default peer_class_filter to use the local peer class
|
||||
|
@ -1328,6 +1392,7 @@ namespace aux {
|
|||
ret->ssl = lep.ssl;
|
||||
ret->original_port = bind_ep.port();
|
||||
ret->flags = lep.flags;
|
||||
ret->netmask = lep.netmask;
|
||||
operation_t last_op = operation_t::unknown;
|
||||
socket_type_t const sock_type
|
||||
= (lep.ssl == transport::ssl)
|
||||
|
@ -1535,7 +1600,7 @@ namespace aux {
|
|||
: socket_type_t::udp;
|
||||
udp::endpoint udp_bind_ep(bind_ep.address(), bind_ep.port());
|
||||
|
||||
ret->udp_sock = std::make_shared<session_udp_socket>(m_io_service);
|
||||
ret->udp_sock = std::make_shared<session_udp_socket>(m_io_service, ret);
|
||||
ret->udp_sock->sock.open(udp_bind_ep.protocol(), ec);
|
||||
if (ec)
|
||||
{
|
||||
|
@ -1798,6 +1863,8 @@ namespace aux {
|
|||
if (!ec)
|
||||
{
|
||||
expand_unspecified_address(ifs, eps);
|
||||
auto const routes = enum_routes(m_io_service, ec);
|
||||
if (!ec) expand_devices(ifs, routes, eps);
|
||||
}
|
||||
|
||||
// if no listen interfaces are specified, create sockets to use
|
||||
|
|
|
@ -10988,7 +10988,8 @@ bool is_downloading_state(int const st)
|
|||
debug_log("*** increment tracker fail count [%d]", aep->fails);
|
||||
#endif
|
||||
// don't try to announce from this endpoint again
|
||||
if (ec == boost::system::errc::address_family_not_supported)
|
||||
if (ec == boost::system::errc::address_family_not_supported
|
||||
|| ec == boost::system::errc::host_unreachable)
|
||||
{
|
||||
aep->enabled = false;
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
|
|
|
@ -69,14 +69,14 @@ std::size_t const max_header_size = 255;
|
|||
// the common case cheaper by not allocating this space unconditionally
|
||||
struct socks5 : std::enable_shared_from_this<socks5>
|
||||
{
|
||||
explicit socks5(io_service& ios, alert_manager& alerts)
|
||||
explicit socks5(io_service& ios, aux::listen_socket_handle ls
|
||||
, alert_manager& alerts)
|
||||
: m_socks5_sock(ios)
|
||||
, m_resolver(ios)
|
||||
, m_timer(ios)
|
||||
, m_retry_timer(ios)
|
||||
, m_alerts(alerts)
|
||||
, m_abort(false)
|
||||
, m_active(false)
|
||||
, m_listen_socket(std::move(ls))
|
||||
{}
|
||||
|
||||
void start(aux::proxy_settings const& ps);
|
||||
|
@ -107,6 +107,7 @@ private:
|
|||
deadline_timer m_timer;
|
||||
deadline_timer m_retry_timer;
|
||||
alert_manager& m_alerts;
|
||||
aux::listen_socket_handle m_listen_socket;
|
||||
std::array<char, tmp_buffer_size> m_tmp_buf;
|
||||
|
||||
aux::proxy_settings m_proxy_settings;
|
||||
|
@ -123,10 +124,10 @@ private:
|
|||
udp::endpoint m_udp_proxy_addr;
|
||||
|
||||
// set to true when we've been asked to shut down
|
||||
bool m_abort;
|
||||
bool m_abort = false;
|
||||
|
||||
// set to true once the tunnel is established
|
||||
bool m_active;
|
||||
bool m_active = false;
|
||||
};
|
||||
|
||||
#ifdef TORRENT_HAS_DONT_FRAGMENT
|
||||
|
@ -159,9 +160,10 @@ struct set_dont_frag
|
|||
{ set_dont_frag(udp::socket&, int) {} };
|
||||
#endif
|
||||
|
||||
udp_socket::udp_socket(io_service& ios)
|
||||
udp_socket::udp_socket(io_service& ios, aux::listen_socket_handle ls)
|
||||
: m_socket(ios)
|
||||
, m_buf(new receive_buffer())
|
||||
, m_listen_socket(std::move(ls))
|
||||
, m_bind_port(0)
|
||||
, m_abort(true)
|
||||
{}
|
||||
|
@ -495,7 +497,8 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps
|
|||
|| ps.type == settings_pack::socks5_pw)
|
||||
{
|
||||
// connect to socks5 server and open up the UDP tunnel
|
||||
m_socks5_connection = std::make_shared<socks5>(lt::get_io_service(m_socket), alerts);
|
||||
m_socks5_connection = std::make_shared<socks5>(lt::get_io_service(m_socket)
|
||||
, m_listen_socket, alerts);
|
||||
m_socks5_connection->start(ps);
|
||||
}
|
||||
}
|
||||
|
@ -528,6 +531,27 @@ void socks5::on_name_lookup(error_code const& e, tcp::resolver::iterator i)
|
|||
return;
|
||||
}
|
||||
|
||||
// only set up a SOCKS5 tunnel for sockets with the same address family
|
||||
// as the proxy
|
||||
// this is a hack to mitigate excessive SOCKS5 tunnels, until this can get
|
||||
// fixed properly.
|
||||
for (;;)
|
||||
{
|
||||
if (i == tcp::resolver::iterator{})
|
||||
{
|
||||
if (m_alerts.should_post<socks5_alert>())
|
||||
m_alerts.emplace_alert<socks5_alert>(tcp::endpoint()
|
||||
, operation_t::hostname_lookup
|
||||
, error_code(boost::system::errc::host_unreachable, generic_category()));
|
||||
return;
|
||||
}
|
||||
|
||||
// we found a match
|
||||
if (m_listen_socket.can_route(i->endpoint().address()))
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
m_proxy_addr = i->endpoint();
|
||||
|
||||
error_code ec;
|
||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/time.hpp"
|
||||
#include "libtorrent/aux_/io.hpp"
|
||||
#include "libtorrent/peer.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
#include "libtorrent/socket_io.hpp"
|
||||
|
@ -203,24 +204,20 @@ namespace libtorrent {
|
|||
return;
|
||||
}
|
||||
|
||||
auto bind_address = bind_interface();
|
||||
auto const listen_socket = bind_socket();
|
||||
|
||||
// look for an address that has the same kind as the one
|
||||
// we're listening on. To make sure the tracker get our
|
||||
// correct listening address.
|
||||
bool is_v4 = bind_address.is_v4();
|
||||
auto scope = is_v4 ? 0 : bind_address.to_v6().scope_id();
|
||||
// filter all endpoints we cannot reach from this listen socket, which may
|
||||
// be all of them, in which case we should not announce this listen socket
|
||||
// to this tracker
|
||||
for (auto const& addr : addresses)
|
||||
{
|
||||
if (addr.is_v4() != is_v4) continue;
|
||||
if (addr.is_v6() && addr.to_v6().scope_id() != scope)
|
||||
continue;
|
||||
if (!listen_socket.can_route(addr)) continue;
|
||||
m_endpoints.emplace_back(addr, std::uint16_t(port));
|
||||
}
|
||||
|
||||
if (m_endpoints.empty())
|
||||
{
|
||||
fail(error_code(boost::asio::error::address_family_not_supported));
|
||||
fail(error_code(boost::system::errc::host_unreachable, generic_category()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,24 +76,36 @@ TORRENT_TEST(is_any)
|
|||
|
||||
TORRENT_TEST(match_addr_mask)
|
||||
{
|
||||
error_code ec;
|
||||
TEST_CHECK(match_addr_mask(
|
||||
address::from_string("10.0.1.176", ec),
|
||||
address::from_string("10.0.1.176", ec),
|
||||
address::from_string("255.255.255.0", ec)));
|
||||
TEST_CHECK(!ec);
|
||||
address::from_string("10.0.1.176"),
|
||||
address::from_string("10.0.1.176"),
|
||||
address::from_string("255.255.255.0")));
|
||||
|
||||
TEST_CHECK(match_addr_mask(
|
||||
address::from_string("10.0.1.3", ec),
|
||||
address::from_string("10.0.3.3", ec),
|
||||
address::from_string("255.255.0.0", ec)));
|
||||
TEST_CHECK(!ec);
|
||||
address::from_string("10.0.1.3"),
|
||||
address::from_string("10.0.3.3"),
|
||||
address::from_string("255.255.0.0")));
|
||||
|
||||
TEST_CHECK(!match_addr_mask(
|
||||
address::from_string("10.0.1.3", ec),
|
||||
address::from_string("10.1.3.3", ec),
|
||||
address::from_string("255.255.0.0", ec)));
|
||||
TEST_CHECK(!ec);
|
||||
address::from_string("10.0.1.3"),
|
||||
address::from_string("10.1.3.3"),
|
||||
address::from_string("255.255.0.0")));
|
||||
|
||||
TEST_CHECK(match_addr_mask(
|
||||
address::from_string("ff00:1234::"),
|
||||
address::from_string("ff00:5678::"),
|
||||
address::from_string("ffff::")));
|
||||
|
||||
TEST_CHECK(!match_addr_mask(
|
||||
address::from_string("ff00:1234::"),
|
||||
address::from_string("ff00:5678::"),
|
||||
address::from_string("ffff:f000::")));
|
||||
|
||||
// different scope IDs always means a mismatch
|
||||
TEST_CHECK(!match_addr_mask(
|
||||
address::from_string("ff00:1234::%1"),
|
||||
address::from_string("ff00:1234::%2"),
|
||||
address::from_string("ffff::")));
|
||||
}
|
||||
|
||||
TORRENT_TEST(is_ip_address)
|
||||
|
|
|
@ -57,14 +57,25 @@ namespace
|
|||
TEST_EQUAL(e1.device, dev);
|
||||
}
|
||||
|
||||
ip_interface ifc(char const* ip, char const* device)
|
||||
ip_interface ifc(char const* ip, char const* device, char const* netmask = nullptr)
|
||||
{
|
||||
ip_interface ipi;
|
||||
ipi.interface_address = address::from_string(ip);
|
||||
if (netmask) ipi.netmask = address::from_string(netmask);
|
||||
strncpy(ipi.name, device, sizeof(ipi.name));
|
||||
return ipi;
|
||||
}
|
||||
|
||||
ip_route rt(char const* ip, char const* device, char const* gateway)
|
||||
{
|
||||
ip_route ret;
|
||||
ret.destination = address::from_string(ip);
|
||||
ret.gateway = address::from_string(gateway);
|
||||
std::strncpy(ret.name, device, sizeof(ret.name));
|
||||
ret.name[sizeof(ret.name) - 1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
aux::listen_endpoint_t ep(char const* ip, int port
|
||||
, tp ssl = tp::plaintext
|
||||
, std::string device = {})
|
||||
|
@ -229,6 +240,59 @@ TORRENT_TEST(partition_listen_sockets_op_ports)
|
|||
TEST_EQUAL(eps.size(), 2);
|
||||
}
|
||||
|
||||
TORRENT_TEST(expand_devices)
|
||||
{
|
||||
|
||||
// this causes us to only expand IPv6 addresses on eth0
|
||||
std::vector<ip_route> const routes = {
|
||||
rt("0.0.0.0", "eth0", "1.2.3.4"),
|
||||
rt("::", "eth0", "1234:5678::1"),
|
||||
};
|
||||
|
||||
std::vector<ip_interface> const ifs = {
|
||||
ifc("127.0.0.1", "lo", "255.0.0.0")
|
||||
, ifc("192.168.1.2", "eth0", "255.255.255.0")
|
||||
, ifc("24.172.48.90", "eth1", "255.255.255.0")
|
||||
, ifc("::1", "lo", "ffff:ffff:ffff:ffff::")
|
||||
, ifc("fe80::d250:99ff:fe0c:9b74", "eth0", "ffff:ffff:ffff:ffff::")
|
||||
, ifc("2601:646:c600:a3:d250:99ff:fe0c:9b74", "eth0", "ffff:ffff:ffff:ffff::")
|
||||
};
|
||||
|
||||
std::vector<aux::listen_endpoint_t> eps = {
|
||||
{
|
||||
address::from_string("127.0.0.1"),
|
||||
6881, // port
|
||||
"", // device
|
||||
aux::transport::plaintext,
|
||||
aux::listen_socket_flags_t{} },
|
||||
{
|
||||
address::from_string("192.168.1.2"),
|
||||
6881, // port
|
||||
"", // device
|
||||
aux::transport::plaintext,
|
||||
aux::listen_socket_flags_t{} }
|
||||
};
|
||||
|
||||
expand_devices(ifs, routes, eps);
|
||||
|
||||
TEST_CHECK((eps == std::vector<aux::listen_endpoint_t>{
|
||||
{
|
||||
address::from_string("127.0.0.1"),
|
||||
6881, // port
|
||||
"lo", // device
|
||||
aux::transport::plaintext,
|
||||
aux::listen_socket_flags_t{},
|
||||
address::from_string("255.0.0.0") },
|
||||
{
|
||||
address::from_string("192.168.1.2"),
|
||||
6881, // port
|
||||
"eth0", // device
|
||||
aux::transport::plaintext,
|
||||
aux::listen_socket_flags_t{},
|
||||
address::from_string("255.255.255.0") },
|
||||
}));
|
||||
}
|
||||
|
||||
TORRENT_TEST(expand_unspecified)
|
||||
{
|
||||
std::vector<ip_interface> const ifs = {
|
||||
|
@ -237,7 +301,7 @@ TORRENT_TEST(expand_unspecified)
|
|||
, ifc("24.172.48.90", "eth1")
|
||||
, ifc("::1", "lo")
|
||||
, ifc("fe80::d250:99ff:fe0c:9b74", "eth0")
|
||||
, ifc( "2601:646:c600:a3:d250:99ff:fe0c:9b74", "eth0")
|
||||
, ifc("2601:646:c600:a3:d250:99ff:fe0c:9b74", "eth0")
|
||||
};
|
||||
|
||||
auto v4_nossl = ep("0.0.0.0", 6881);
|
||||
|
|
|
@ -345,7 +345,6 @@ void test_udp_tracker(std::string const& iface, address tracker, tcp::endpoint c
|
|||
settings_pack pack = settings();
|
||||
pack.set_bool(settings_pack::announce_to_all_trackers, true);
|
||||
pack.set_bool(settings_pack::announce_to_all_tiers, true);
|
||||
pack.set_str(settings_pack::listen_interfaces, iface + ":48875");
|
||||
|
||||
std::unique_ptr<lt::session> s(new lt::session(pack));
|
||||
|
||||
|
@ -420,7 +419,10 @@ TORRENT_TEST(udp_tracker_v6)
|
|||
{
|
||||
if (supports_ipv6())
|
||||
{
|
||||
test_udp_tracker("[::1]", address_v6::any(), ep("::1.3.3.7", 1337));
|
||||
// if the machine running the test doesn't have an actual IPv6 connection
|
||||
// the test would fail with any other address than loopback (because it
|
||||
// would be unreachable)
|
||||
test_udp_tracker("[::1]", address_v6::any(), ep("::1", 1337));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,10 +138,10 @@ struct udp_tracker
|
|||
detail::write_uint32(0, ptr);
|
||||
detail::write_uint32(0, ptr);
|
||||
detail::write_uint32(0, ptr);
|
||||
detail::write_uint8(0, ptr);
|
||||
detail::write_uint8(0, ptr);
|
||||
detail::write_uint8(0, ptr);
|
||||
detail::write_uint8(1, ptr);
|
||||
detail::write_uint8(3, ptr);
|
||||
detail::write_uint8(3, ptr);
|
||||
detail::write_uint8(7, ptr);
|
||||
detail::write_uint16(1337, ptr);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue