make tracker announces happen even if there are no open listen sockets (#2529)

support announcing to IPv6 trackers and running an IPv6 DHT when not listening for incoming connections
This commit is contained in:
Arvid Norberg 2017-11-20 23:42:22 +01:00 committed by GitHub
parent 30a7b52855
commit c734f42ac3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 52 deletions

View File

@ -128,6 +128,12 @@ namespace aux {
struct tracker_logger; struct tracker_logger;
#endif #endif
enum class duplex : std::uint8_t
{
accept_incoming,
only_outgoing
};
struct listen_socket_t struct listen_socket_t
{ {
listen_socket_t() listen_socket_t()
@ -181,6 +187,8 @@ namespace aux {
// indicates whether this is an SSL listen socket or not // indicates whether this is an SSL listen socket or not
transport ssl = transport::plaintext; transport ssl = transport::plaintext;
duplex incoming = duplex::accept_incoming;
// the actual sockets (TCP listen socket and UDP socket) // the actual sockets (TCP listen socket and UDP socket)
// An entry does not necessarily have a UDP or TCP socket. One of these // An entry does not necessarily have a UDP or TCP socket. One of these
// pointers may be nullptr! // pointers may be nullptr!
@ -194,8 +202,9 @@ namespace aux {
struct TORRENT_EXTRA_EXPORT listen_endpoint_t struct TORRENT_EXTRA_EXPORT listen_endpoint_t
{ {
listen_endpoint_t(address adr, int p, std::string dev, transport s) listen_endpoint_t(address adr, int p, std::string dev, transport s
: addr(adr), port(p), device(dev), ssl(s) {} , duplex d = duplex::accept_incoming)
: addr(adr), port(p), device(dev), ssl(s), incoming(d) {}
bool operator==(listen_endpoint_t const& o) const bool operator==(listen_endpoint_t const& o) const
{ {
@ -206,6 +215,7 @@ namespace aux {
int port; int port;
std::string device; std::string device;
transport ssl; transport ssl;
duplex incoming;
}; };
// partitions sockets based on whether they match one of the given endpoints // partitions sockets based on whether they match one of the given endpoints
@ -675,6 +685,7 @@ namespace aux {
// implements session_interface // implements session_interface
tcp::endpoint bind_outgoing_socket(socket_type& s, address tcp::endpoint bind_outgoing_socket(socket_type& s, address
const& remote_address, error_code& ec) const override; const& remote_address, error_code& ec) const override;
bool verify_incoming_interface(address const& addr);
bool verify_bound_address(address const& addr, bool utp bool verify_bound_address(address const& addr, bool utp
, error_code& ec) override; , error_code& ec) override;
@ -761,8 +772,8 @@ namespace aux {
void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip
, ip_source_t const source_type, address const& source); , ip_source_t const source_type, address const& source);
void interface_to_endpoints(std::string const& device, int const port void interface_to_endpoints(std::string const& device, int port
, bool const ssl, std::vector<listen_endpoint_t>& eps); , transport ssl, duplex incoming, std::vector<listen_endpoint_t>& eps);
// the settings for the client // the settings for the client
aux::session_settings m_settings; aux::session_settings m_settings;
@ -937,8 +948,8 @@ namespace aux {
// round-robin index into m_outgoing_interfaces // round-robin index into m_outgoing_interfaces
mutable std::uint8_t m_interface_index = 0; mutable std::uint8_t m_interface_index = 0;
std::shared_ptr<listen_socket_t> setup_listener(std::string const& device std::shared_ptr<listen_socket_t> setup_listener(
, tcp::endpoint bind_ep, transport ssl, error_code& ec); listen_endpoint_t const& lep, error_code& ec);
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
dht::dht_state m_dht_state; dht::dht_state m_dht_state;

View File

@ -155,6 +155,7 @@ namespace libtorrent {
#endif #endif
sha1_hash info_hash; sha1_hash info_hash;
peer_id pid; peer_id pid;
aux::listen_socket_handle outgoing_socket; aux::listen_socket_handle outgoing_socket;
// set to true if the .torrent file this tracker announce is for is marked // set to true if the .torrent file this tracker announce is for is marked

View File

@ -97,7 +97,7 @@ namespace libtorrent {
void fail(error_code const& ec, int code = -1 void fail(error_code const& ec, int code = -1
, char const* msg = "" , char const* msg = ""
, seconds32 interval = seconds32(0) , seconds32 interval = seconds32(0)
, seconds32 min_interval = seconds32(0)); , seconds32 min_interval = seconds32(30));
void send_udp_connect(); void send_udp_connect();
void send_udp_announce(); void send_udp_announce();

View File

@ -406,6 +406,104 @@ void test_ipv6_support(char const* listen_interfaces
TEST_EQUAL(v6_announces, expect_v6); TEST_EQUAL(v6_announces, expect_v6);
} }
void test_udpv6_support(char const* listen_interfaces
, int const expect_v4, int const expect_v6)
{
using sim::asio::ip::address_v4;
sim_config network_cfg;
sim::simulation sim{network_cfg};
sim::asio::io_service web_server_v4(sim, address_v4::from_string("10.0.0.2"));
sim::asio::io_service web_server_v6(sim, address_v6::from_string("ff::dead:beef"));
int v4_announces = 0;
int v6_announces = 0;
{
lt::session_proxy zombie;
std::vector<asio::ip::address> ips;
for (int i = 0; i < num_interfaces; i++)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "10.0.0.%d", i + 1);
ips.push_back(address::from_string(ep));
std::snprintf(ep, sizeof(ep), "ffff::1337:%d", i + 1);
ips.push_back(address::from_string(ep));
}
asio::io_service ios(sim, ips);
lt::settings_pack sett = settings();
if (listen_interfaces)
{
sett.set_str(settings_pack::listen_interfaces, listen_interfaces);
}
std::unique_ptr<lt::session> ses(new lt::session(sett, ios));
// since we don't have a udp tracker to run in the sim, looking for the
// alerts is the closest proxy
ses->set_alert_notify([&]{
ses->get_io_service().post([&] {
std::vector<lt::alert*> alerts;
ses->pop_alerts(&alerts);
for (lt::alert* a : alerts)
{
lt::time_duration d = a->timestamp().time_since_epoch();
std::uint32_t const millis = std::uint32_t(
lt::duration_cast<lt::milliseconds>(d).count());
std::printf("%4d.%03d: %s\n", millis / 1000, millis % 1000,
a->message().c_str());
if (auto tr = alert_cast<tracker_announce_alert>(a))
{
if (tr->local_endpoint.address().is_v4())
++v4_announces;
else
++v6_announces;
}
else if (alert_cast<tracker_error_alert>(a))
{
TEST_CHECK(false && "unexpected tracker error");
}
}
});
});
lt::add_torrent_params p;
p.name = "test-torrent";
p.save_path = ".";
p.info_hash.assign("abababababababababab");
p.trackers.push_back("udp://tracker.com:8080/announce");
ses->async_add_torrent(p);
// stop the torrent 5 seconds in
sim::timer t1(sim, lt::seconds(5)
, [&ses](boost::system::error_code const&)
{
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
for (auto const& t : torrents)
{
t.pause();
}
});
// then shut down 10 seconds in
sim::timer t2(sim, lt::seconds(10)
, [&ses,&zombie](boost::system::error_code const&)
{
zombie = ses->abort();
ses.reset();
});
sim.run();
}
TEST_EQUAL(v4_announces, expect_v4);
TEST_EQUAL(v6_announces, expect_v6);
}
// this test makes sure that a tracker whose host name resolves to both IPv6 and // this test makes sure that a tracker whose host name resolves to both IPv6 and
// IPv4 addresses will be announced to twice, once for each address family // IPv4 addresses will be announced to twice, once for each address family
TORRENT_TEST(ipv6_support) TORRENT_TEST(ipv6_support)
@ -414,6 +512,20 @@ TORRENT_TEST(ipv6_support)
test_ipv6_support(nullptr, 2, num_interfaces * 2); test_ipv6_support(nullptr, 2, num_interfaces * 2);
} }
TORRENT_TEST(announce_no_listen)
{
// if we don't listen on any sockets at all (but only make outgoing peer
// connections) we still need to make sure we announce to trackers
test_ipv6_support("", 2, 2);
}
TORRENT_TEST(announce_udp_no_listen)
{
// since there's no actual udp tracker in this test, we will only try to
// announce once, and fail. We won't announce the event=stopped
test_udpv6_support("", 1, 1);
}
TORRENT_TEST(ipv6_support_bind_v4_v6_any) TORRENT_TEST(ipv6_support_bind_v4_v6_any)
{ {
// 2 because there's one announce on startup and one when shutting down // 2 because there's one announce on startup and one when shutting down

View File

@ -1348,7 +1348,10 @@ namespace {
!= m_settings.get_int(settings_pack::ssl_listen)) != m_settings.get_int(settings_pack::ssl_listen))
|| ||
#endif #endif
(pack.has_val(settings_pack::listen_interfaces) (pack.has_val(settings_pack::force_proxy)
&& !pack.get_bool(settings_pack::force_proxy)
&& m_settings.get_bool(settings_pack::force_proxy))
|| (pack.has_val(settings_pack::listen_interfaces)
&& pack.get_str(settings_pack::listen_interfaces) && pack.get_str(settings_pack::listen_interfaces)
!= m_settings.get_str(settings_pack::listen_interfaces)); != m_settings.get_str(settings_pack::listen_interfaces));
@ -1381,25 +1384,27 @@ namespace {
reopen_outgoing_sockets(); reopen_outgoing_sockets();
} }
std::shared_ptr<listen_socket_t> session_impl::setup_listener(std::string const& device std::shared_ptr<listen_socket_t> session_impl::setup_listener(
, tcp::endpoint bind_ep, transport const ssl, error_code& ec) listen_endpoint_t const& lep, error_code& ec)
{ {
int retries = m_settings.get_int(settings_pack::max_retry_port_bind); int retries = m_settings.get_int(settings_pack::max_retry_port_bind);
tcp::endpoint bind_ep(lep.addr, std::uint16_t(lep.port));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) if (should_log())
{ {
session_log("attempting to open listen socket to: %s on device: %s ssl: %x" session_log("attempting to open listen socket to: %s on device: %s ssl: %x"
, print_endpoint(bind_ep).c_str(), device.c_str(), static_cast<int>(ssl)); , print_endpoint(bind_ep).c_str(), lep.device.c_str(), static_cast<int>(lep.ssl));
} }
#endif #endif
auto ret = std::make_shared<listen_socket_t>(); auto ret = std::make_shared<listen_socket_t>();
ret->ssl = ssl; ret->ssl = lep.ssl;
ret->original_port = bind_ep.port(); ret->original_port = bind_ep.port();
ret->incoming = lep.incoming;
operation_t last_op = operation_t::unknown; operation_t last_op = operation_t::unknown;
socket_type_t const sock_type socket_type_t const sock_type
= (ssl == transport::ssl) = (lep.ssl == transport::ssl)
? socket_type_t::tcp_ssl ? socket_type_t::tcp_ssl
: socket_type_t::tcp; : socket_type_t::tcp;
@ -1407,7 +1412,7 @@ namespace {
// accept connections on our local machine in this case. // accept connections on our local machine in this case.
// TODO: 3 the logic in this if-block should be factored out into a // TODO: 3 the logic in this if-block should be factored out into a
// separate function. At least most of it // separate function. At least most of it
if (!m_settings.get_bool(settings_pack::force_proxy)) if (ret->incoming == duplex::accept_incoming)
{ {
ret->sock = std::make_shared<tcp::acceptor>(m_io_service); ret->sock = std::make_shared<tcp::acceptor>(m_io_service);
ret->sock->open(bind_ep.protocol(), ec); ret->sock->open(bind_ep.protocol(), ec);
@ -1423,7 +1428,7 @@ namespace {
#endif #endif
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep, last_op m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep, last_op
, ec, sock_type); , ec, sock_type);
return ret; return ret;
} }
@ -1484,26 +1489,26 @@ namespace {
} }
#endif // TORRENT_USE_IPV6 #endif // TORRENT_USE_IPV6
if (!device.empty()) if (!lep.device.empty())
{ {
// we have an actual device we're interested in listening on, if we // we have an actual device we're interested in listening on, if we
// have SO_BINDTODEVICE functionality, use it now. // have SO_BINDTODEVICE functionality, use it now.
#if TORRENT_HAS_BINDTODEVICE #if TORRENT_HAS_BINDTODEVICE
ret->sock->set_option(bind_to_device(device.c_str()), ec); ret->sock->set_option(bind_to_device(lep.device.c_str()), ec);
if (ec) if (ec)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) if (should_log())
{ {
session_log("bind to device failed (device: %s): %s" session_log("bind to device failed (device: %s): %s"
, device.c_str(), ec.message().c_str()); , lep.device.c_str(), ec.message().c_str());
} }
#endif // TORRENT_DISABLE_LOGGING #endif // TORRENT_DISABLE_LOGGING
last_op = operation_t::sock_bind_to_device; last_op = operation_t::sock_bind_to_device;
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
{ {
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
, last_op, ec, sock_type); , last_op, ec, sock_type);
} }
return ret; return ret;
@ -1523,7 +1528,7 @@ namespace {
session_log("failed to bind listen socket to: %s on device: %s :" session_log("failed to bind listen socket to: %s on device: %s :"
" [%s] (%d) %s (retries: %d)" " [%s] (%d) %s (retries: %d)"
, print_endpoint(bind_ep).c_str() , print_endpoint(bind_ep).c_str()
, device.c_str() , lep.device.c_str()
, ec.category().name(), ec.value(), ec.message().c_str() , ec.category().name(), ec.value(), ec.message().c_str()
, retries); , retries);
} }
@ -1555,20 +1560,20 @@ namespace {
session_log("failed to bind listen socket to: %s on device: %s :" session_log("failed to bind listen socket to: %s on device: %s :"
" [%s] (%d) %s (giving up)" " [%s] (%d) %s (giving up)"
, print_endpoint(bind_ep).c_str() , print_endpoint(bind_ep).c_str()
, device.c_str() , lep.device.c_str()
, ec.category().name(), ec.value(), ec.message().c_str()); , ec.category().name(), ec.value(), ec.message().c_str());
} }
#endif #endif
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
{ {
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
, last_op, ec, sock_type); , last_op, ec, sock_type);
} }
ret->sock.reset(); ret->sock.reset();
return ret; return ret;
} }
ret->local_endpoint = ret->sock->local_endpoint(ec); ret->local_endpoint = ret->sock->local_endpoint(ec);
ret->device = device; ret->device = lep.device;
last_op = operation_t::getname; last_op = operation_t::getname;
if (ec) if (ec)
{ {
@ -1581,7 +1586,7 @@ namespace {
#endif #endif
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
{ {
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
, last_op, ec, sock_type); , last_op, ec, sock_type);
} }
return ret; return ret;
@ -1599,20 +1604,20 @@ namespace {
if (should_log()) if (should_log())
{ {
session_log("cannot listen on interface \"%s\": %s" session_log("cannot listen on interface \"%s\": %s"
, device.c_str(), ec.message().c_str()); , lep.device.c_str(), ec.message().c_str());
} }
#endif #endif
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
{ {
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
, last_op, ec, sock_type); , last_op, ec, sock_type);
} }
return ret; return ret;
} }
} // force-proxy mode } // accept incoming
socket_type_t const udp_sock_type socket_type_t const udp_sock_type
= (ssl == transport::ssl) = (lep.ssl == transport::ssl)
? socket_type_t::utp_ssl ? socket_type_t::utp_ssl
: socket_type_t::udp; : socket_type_t::udp;
udp::endpoint const udp_bind_ep(bind_ep.address(), bind_ep.port()); udp::endpoint const udp_bind_ep(bind_ep.address(), bind_ep.port());
@ -1625,36 +1630,36 @@ namespace {
if (should_log()) if (should_log())
{ {
session_log("failed to open UDP socket: %s: %s" session_log("failed to open UDP socket: %s: %s"
, device.c_str(), ec.message().c_str()); , lep.device.c_str(), ec.message().c_str());
} }
#endif #endif
last_op = operation_t::sock_open; last_op = operation_t::sock_open;
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
m_alerts.emplace_alert<listen_failed_alert>(device m_alerts.emplace_alert<listen_failed_alert>(lep.device
, bind_ep, last_op, ec, udp_sock_type); , bind_ep, last_op, ec, udp_sock_type);
return ret; return ret;
} }
#if TORRENT_HAS_BINDTODEVICE #if TORRENT_HAS_BINDTODEVICE
if (!device.empty()) if (!lep.device.empty())
{ {
ret->udp_sock->sock.set_option(bind_to_device(device.c_str()), ec); ret->udp_sock->sock.set_option(bind_to_device(lep.device.c_str()), ec);
if (ec) if (ec)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) if (should_log())
{ {
session_log("bind to device failed (device: %s): %s" session_log("bind to device failed (device: %s): %s"
, device.c_str(), ec.message().c_str()); , lep.device.c_str(), ec.message().c_str());
} }
#endif // TORRENT_DISABLE_LOGGING #endif // TORRENT_DISABLE_LOGGING
last_op = operation_t::sock_bind_to_device; last_op = operation_t::sock_bind_to_device;
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
{ {
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
, last_op, ec, udp_sock_type); , last_op, ec, udp_sock_type);
} }
return ret; return ret;
@ -1670,18 +1675,26 @@ namespace {
if (should_log()) if (should_log())
{ {
session_log("failed to bind UDP socket: %s: %s" session_log("failed to bind UDP socket: %s: %s"
, device.c_str(), ec.message().c_str()); , lep.device.c_str(), ec.message().c_str());
} }
#endif #endif
if (m_alerts.should_post<listen_failed_alert>()) if (m_alerts.should_post<listen_failed_alert>())
m_alerts.emplace_alert<listen_failed_alert>(device m_alerts.emplace_alert<listen_failed_alert>(lep.device
, bind_ep, last_op, ec, udp_sock_type); , bind_ep, last_op, ec, udp_sock_type);
return ret; return ret;
} }
ret->udp_external_port = ret->udp_sock->sock.local_port(); ret->udp_external_port = ret->udp_sock->sock.local_port();
// if we did not open a TCP listen socket, ret->local_endpoint was never
// initialized, so do that now, based on the UDP socket
if (ret->incoming != duplex::accept_incoming)
{
auto const udp_ep = ret->udp_sock->local_endpoint();
ret->local_endpoint = tcp::endpoint(udp_ep.address(), udp_ep.port());
}
error_code err; error_code err;
set_socket_buffer_size(ret->udp_sock->sock, m_settings, err); set_socket_buffer_size(ret->udp_sock->sock, m_settings, err);
if (err) if (err)
@ -1747,7 +1760,7 @@ namespace {
} }
void session_impl::interface_to_endpoints(std::string const& device, int const port void session_impl::interface_to_endpoints(std::string const& device, int const port
, bool const ssl, std::vector<listen_endpoint_t>& eps) , transport const ssl, duplex const incoming, std::vector<listen_endpoint_t>& eps)
{ {
// First, check to see if it's an IP address // First, check to see if it's an IP address
error_code err; error_code err;
@ -1757,8 +1770,7 @@ namespace {
#if !TORRENT_USE_IPV6 #if !TORRENT_USE_IPV6
if (adr.is_v4()) if (adr.is_v4())
#endif #endif
eps.emplace_back(adr, port, std::string() eps.emplace_back(adr, port, std::string(), ssl, incoming);
, ssl ? transport::ssl : transport::plaintext);
} }
else else
{ {
@ -1791,8 +1803,7 @@ namespace {
// (which must be of the same family as the address we're // (which must be of the same family as the address we're
// connecting to) // connecting to)
if (device != ipface.name) continue; if (device != ipface.name) continue;
eps.emplace_back(ipface.interface_address, port, device eps.emplace_back(ipface.interface_address, port, device, ssl, incoming);
, ssl ? transport::ssl : transport::plaintext);
} }
} }
} }
@ -1817,14 +1828,18 @@ namespace {
// of a new socket failing to bind due to a conflict with a stale socket // of a new socket failing to bind due to a conflict with a stale socket
std::vector<listen_endpoint_t> eps; std::vector<listen_endpoint_t> eps;
duplex const incoming = m_settings.get_bool(settings_pack::force_proxy)
? duplex::only_outgoing
: duplex::accept_incoming;
for (auto const& iface : m_listen_interfaces) for (auto const& iface : m_listen_interfaces)
{ {
std::string const& device = iface.device; std::string const& device = iface.device;
int const port = iface.port; int const port = iface.port;
bool const ssl = iface.ssl; transport const ssl = iface.ssl ? transport::ssl : transport::plaintext;
#ifndef TORRENT_USE_OPENSSL #ifndef TORRENT_USE_OPENSSL
if (ssl) if (ssl == transport::ssl)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
session_log("attempted to listen ssl with no library support on device: \"%s\"" session_log("attempted to listen ssl with no library support on device: \"%s\""
@ -1845,7 +1860,7 @@ namespace {
// IP address or a device name. In case it's a device name, we want to // IP address or a device name. In case it's a device name, we want to
// (potentially) end up binding a socket for each IP address associated // (potentially) end up binding a socket for each IP address associated
// with that device. // with that device.
interface_to_endpoints(device, port, ssl, eps); interface_to_endpoints(device, port, ssl, incoming, eps);
} }
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
@ -1856,6 +1871,18 @@ namespace {
} }
#endif #endif
// if no listen interfaces are specified, create sockets to use
// any interface
if (eps.empty())
{
eps.emplace_back(address_v4(), 0, "", transport::plaintext
, duplex::only_outgoing);
#if TORRENT_USE_IPV6
eps.emplace_back(address_v6(), 0, "", transport::plaintext
, duplex::only_outgoing);
#endif
}
auto remove_iter = partition_listen_sockets(eps, m_listen_sockets); auto remove_iter = partition_listen_sockets(eps, m_listen_sockets);
while (remove_iter != m_listen_sockets.end()) while (remove_iter != m_listen_sockets.end())
@ -1882,8 +1909,7 @@ namespace {
// an existing socket // an existing socket
for (auto const& ep : eps) for (auto const& ep : eps)
{ {
std::shared_ptr<listen_socket_t> s = setup_listener(ep.device std::shared_ptr<listen_socket_t> s = setup_listener(ep, ec);
, tcp::endpoint(ep.addr, std::uint16_t(ep.port)), ep.ssl, ec);
if (!ec && (s->sock || s->udp_sock)) if (!ec && (s->sock || s->udp_sock))
{ {
@ -1954,6 +1980,7 @@ namespace {
// initiate accepting on the listen sockets // initiate accepting on the listen sockets
for (auto& s : m_listen_sockets) for (auto& s : m_listen_sockets)
{ {
TORRENT_ASSERT((s->incoming == duplex::accept_incoming) == bool(s->sock));
if (s->sock) async_accept(s->sock, s->ssl); if (s->sock) async_accept(s->sock, s->ssl);
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s); if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
} }
@ -1972,9 +1999,9 @@ namespace {
for (auto const& iface : m_outgoing_interfaces) for (auto const& iface : m_outgoing_interfaces)
{ {
interface_to_endpoints(iface, 0, false, eps); interface_to_endpoints(iface, 0, transport::plaintext, duplex::accept_incoming, eps);
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
interface_to_endpoints(iface, 0, true, eps); interface_to_endpoints(iface, 0, transport::ssl, duplex::accept_incoming, eps);
#endif #endif
} }
@ -2411,7 +2438,7 @@ namespace {
span<char const> const buf = packet.data; span<char const> const buf = packet.data;
// give the uTP socket manager first dis on the packet. Presumably // give the uTP socket manager first dibs on the packet. Presumably
// the majority of packets are uTP packets. // the majority of packets are uTP packets.
if (!mgr.incoming_packet(socket, packet.from, buf)) if (!mgr.incoming_packet(socket, packet.from, buf))
{ {
@ -2746,7 +2773,7 @@ namespace {
} }
// if there are outgoing interfaces specified, verify this // if there are outgoing interfaces specified, verify this
// peer is correctly bound to on of them // peer is correctly bound to one of them
if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty()) if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty())
{ {
tcp::endpoint local = s->local_endpoint(ec); tcp::endpoint local = s->local_endpoint(ec);
@ -2761,6 +2788,22 @@ namespace {
#endif #endif
return; return;
} }
if (!verify_incoming_interface(local.address()))
{
#ifndef TORRENT_DISABLE_LOGGING
if (should_log())
{
error_code err;
session_log(" rejected connection, local interface has incoming connections disabled: %s"
, local.address().to_string(err).c_str());
}
#endif
if (m_alerts.should_post<peer_blocked_alert>())
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
, endp, peer_blocked_alert::invalid_local_interface);
return;
}
if (!verify_bound_address(local.address() if (!verify_bound_address(local.address()
, is_utp(*s), ec)) , is_utp(*s), ec))
{ {
@ -5022,6 +5065,19 @@ namespace {
return bind_ep; return bind_ep;
} }
// verify that the interface ``addr`` belongs to, allows incoming connections
bool session_impl::verify_incoming_interface(address const& addr)
{
for (auto const& s : m_listen_sockets)
{
if (s->local_endpoint.address() == addr)
{
return s->incoming == duplex::accept_incoming;
}
}
return false;
}
// verify that the given local address satisfies the requirements of // verify that the given local address satisfies the requirements of
// the outgoing interfaces. i.e. that one of the allowed outgoing // the outgoing interfaces. i.e. that one of the allowed outgoing
// interfaces has this address. For uTP sockets, which are all backed // interfaces has this address. For uTP sockets, which are all backed
@ -5042,7 +5098,7 @@ namespace {
for (auto const& s : m_outgoing_interfaces) for (auto const& s : m_outgoing_interfaces)
{ {
error_code err; error_code err;
address ip = address::from_string(s.c_str(), err); address const ip = address::from_string(s.c_str(), err);
if (err) continue; if (err) continue;
if (ip == addr) return true; if (ip == addr) return true;
} }

View File

@ -2771,7 +2771,7 @@ namespace libtorrent {
{ {
// update the endpoint list by adding entries for new listen sockets // update the endpoint list by adding entries for new listen sockets
// and removing entries for non-existent ones // and removing entries for non-existent ones
std::vector<announce_endpoint>::size_type valid_endpoints = 0; std::size_t valid_endpoints = 0;
m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) { m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) {
if (s.is_ssl() != is_ssl_torrent()) if (s.is_ssl() != is_ssl_torrent())
return; return;
@ -10930,6 +10930,7 @@ namespace {
, retry_interval); , retry_interval);
aep->last_error = ec; aep->last_error = ec;
aep->message = msg; aep->message = msg;
fails = aep->fails;
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
debug_log("*** increment tracker fail count [%d]", aep->fails); debug_log("*** increment tracker fail count [%d]", aep->fails);
#endif #endif