mirror of
https://github.com/arvidn/libtorrent.git
synced 2026-07-28 06:51:37 -04:00
167 lines
5.5 KiB
C++
167 lines
5.5 KiB
C++
/*
|
|
|
|
Copyright (c) 2026, Arvid Norberg
|
|
All rights reserved.
|
|
|
|
You may use, distribute and modify this code under the terms of the BSD license,
|
|
see LICENSE file.
|
|
*/
|
|
|
|
#include "libtorrent/session.hpp"
|
|
#include "libtorrent/torrent_handle.hpp"
|
|
#include "libtorrent/settings_pack.hpp"
|
|
#include "libtorrent/alert_types.hpp"
|
|
#include "libtorrent/aux_/deadline_timer.hpp"
|
|
#include "settings.hpp"
|
|
#include "create_torrent.hpp"
|
|
#include "simulator/simulator.hpp"
|
|
#include "simulator/socks_server.hpp"
|
|
#include "simulator/utils.hpp"
|
|
#include "fake_peer.hpp"
|
|
#include "utils.hpp"
|
|
|
|
using namespace sim;
|
|
|
|
namespace {
|
|
|
|
// under the simulator, enum_net_interfaces() always reports the interface
|
|
// name "eth0" for every address on a node (see enum_net_interfaces() in
|
|
// src/enum_net.cpp).
|
|
constexpr char const* device_name = "eth0";
|
|
|
|
template <typename Settings, typename Alert, typename Test>
|
|
void run_test(Settings const& make_settings, Alert const& on_alert, Test const& test)
|
|
{
|
|
// setup the simulation
|
|
sim::default_config network_cfg;
|
|
sim::simulation sim{network_cfg};
|
|
sim::asio::io_context ios(sim, asio::ip::make_address_v4("50.0.0.1"));
|
|
lt::session_proxy zombie;
|
|
|
|
// a real, working SOCKS5 relay, used by the proxy test below to make sure
|
|
// outgoing connections actually go all the way through and reach
|
|
// verify_bound_address(), instead of failing earlier for unrelated
|
|
// reasons (e.g. a proxy that doesn't exist).
|
|
sim::asio::io_context proxy_ios{sim, asio::ip::make_address_v4("50.50.50.50")};
|
|
sim::socks_server socks5(proxy_ios, 5555, 5);
|
|
|
|
lt::settings_pack pack = settings();
|
|
make_settings(pack);
|
|
std::shared_ptr<lt::session> ses = std::make_shared<lt::session>(pack, ios);
|
|
|
|
fake_peer p1(sim, "60.0.0.0");
|
|
|
|
lt::add_torrent_params params = ::create_torrent(0, false);
|
|
params.flags &= ~lt::torrent_flags::auto_managed;
|
|
params.flags &= ~lt::torrent_flags::paused;
|
|
ses->async_add_torrent(params);
|
|
|
|
print_alerts(*ses, [&](lt::session&, lt::alert const* a) {
|
|
if (auto at = lt::alert_cast<lt::add_torrent_alert>(a))
|
|
{
|
|
lt::torrent_handle h = at->handle;
|
|
add_fake_peer(h, 0);
|
|
}
|
|
on_alert(a);
|
|
});
|
|
|
|
sim::timer t(sim, lt::seconds(60), [&](boost::system::error_code const&) {
|
|
test(p1);
|
|
|
|
// shut down
|
|
zombie = ses->abort();
|
|
p1.close();
|
|
ses.reset();
|
|
});
|
|
|
|
sim.run();
|
|
}
|
|
|
|
template <typename Settings, typename Test>
|
|
void run_test(Settings const& make_settings, Test const& test)
|
|
{
|
|
run_test(make_settings, [](lt::alert const*) {}, test);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// settings_pack::outgoing_interfaces restricts which local device outgoing
|
|
// peer connections may bind to. session_impl caches the result of
|
|
// enumerating the local network interfaces (m_cached_interfaces) instead of
|
|
// asking the OS every time verify_bound_address() is called. This makes sure
|
|
// that cache is actually populated and used correctly: when the configured
|
|
// device matches the one we're bound to, the connection is allowed through.
|
|
TORRENT_TEST(outgoing_interfaces_matching_device_allowed)
|
|
{
|
|
run_test(
|
|
[](lt::settings_pack& pack) {
|
|
pack.set_str(lt::settings_pack::outgoing_interfaces, device_name);
|
|
},
|
|
[](fake_peer& p) { TEST_EQUAL(p.connected(), true); });
|
|
}
|
|
|
|
// the opposite of outgoing_interfaces_matching_device_allowed: when the
|
|
// configured device does not match, verify_bound_address() must reject the
|
|
// connection and it must never complete a BT handshake.
|
|
TORRENT_TEST(outgoing_interfaces_wrong_device_blocked)
|
|
{
|
|
run_test(
|
|
[](lt::settings_pack& pack) {
|
|
pack.set_str(lt::settings_pack::outgoing_interfaces, "nonexistent0");
|
|
},
|
|
[](fake_peer& p) { TEST_EQUAL(p.connected(), false); });
|
|
}
|
|
|
|
// same as outgoing_interfaces_matching_device_allowed, but with peer
|
|
// connections proxied. reopen_listen_sockets() only refreshes
|
|
// m_cached_interfaces unconditionally when it also needs the interface list
|
|
// to build listen endpoints; when proxying peer connections it must still
|
|
// populate the cache whenever outgoing_interfaces is set, since
|
|
// verify_bound_address() depends on it for every connection attempt.
|
|
TORRENT_TEST(outgoing_interfaces_matching_device_allowed_with_proxy)
|
|
{
|
|
run_test(
|
|
[](lt::settings_pack& pack) {
|
|
pack.set_str(lt::settings_pack::outgoing_interfaces, device_name);
|
|
pack.set_int(lt::settings_pack::proxy_type, lt::settings_pack::socks5);
|
|
pack.set_str(lt::settings_pack::proxy_hostname, "50.50.50.50");
|
|
pack.set_int(lt::settings_pack::proxy_port, 5555);
|
|
pack.set_bool(lt::settings_pack::proxy_peer_connections, true);
|
|
},
|
|
[](fake_peer& p) { TEST_EQUAL(p.connected(), true); });
|
|
}
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
// peer_dscp must be applied after opening the socket but before initiating
|
|
// the outgoing TCP connection. Otherwise set_traffic_class() fails with
|
|
// error::bad_descriptor and the SYN is sent without the configured DSCP.
|
|
TORRENT_TEST(outgoing_peer_dscp)
|
|
{
|
|
bool socket_opened = false;
|
|
bool dscp_error = false;
|
|
run_test(
|
|
[](lt::settings_pack& pack) {
|
|
pack.set_int(lt::settings_pack::peer_dscp, 0x04);
|
|
pack.set_bool(lt::settings_pack::enable_outgoing_utp, false);
|
|
},
|
|
[&](lt::alert const* a) {
|
|
auto const* pl = lt::alert_cast<lt::peer_log_alert>(a);
|
|
if (pl == nullptr)
|
|
return;
|
|
|
|
if (pl->event_type == lt::peer_log_alert::open)
|
|
socket_opened = true;
|
|
else if (pl->event_type == lt::peer_log_alert::set_dscp)
|
|
{
|
|
TEST_EQUAL(socket_opened, true);
|
|
dscp_error = true;
|
|
}
|
|
},
|
|
[&](fake_peer& p) {
|
|
TEST_EQUAL(p.connected(), true);
|
|
TEST_EQUAL(socket_opened, true);
|
|
TEST_EQUAL(dscp_error, false);
|
|
});
|
|
}
|
|
#endif
|