diff --git a/ChangeLog b/ChangeLog index 8db6ceb19..d25d12545 100644 --- a/ChangeLog +++ b/ChangeLog @@ -73,6 +73,9 @@ * require C++11 to build libtorrent + * bind upnp requests to correct local address + * save resume data when removing web seeds + * fix proxying of https connections * fix race condition in disk I/O storage class * fix http connection timeout on multi-homed hosts * removed depdendency on boost::uintptr_t for better compatibility diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp index b27c88880..9de59b56f 100644 --- a/include/libtorrent/http_connection.hpp +++ b/include/libtorrent/http_connection.hpp @@ -100,7 +100,7 @@ struct TORRENT_EXTRA_EXPORT http_connection std::string m_sendbuffer; void get(std::string const& url, time_duration timeout = seconds(30) - , int prio = 0, aux::proxy_settings const* ps = 0, int handle_redirects = 5 + , int prio = 0, aux::proxy_settings const* ps = NULL, int handle_redirects = 5 , std::string const& user_agent = std::string() , boost::optional
const& bind_addr = boost::optional
() , int resolve_flags = 0, std::string const& auth_ = std::string() @@ -110,7 +110,7 @@ struct TORRENT_EXTRA_EXPORT http_connection ); void start(std::string const& hostname, int port - , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = 0 + , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = NULL , bool ssl = false, int handle_redirect = 5 , boost::optional
const& bind_addr = boost::optional
() , int resolve_flags = 0 diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp index 1a9742e3d..57345fc01 100644 --- a/include/libtorrent/natpmp.hpp +++ b/include/libtorrent/natpmp.hpp @@ -55,7 +55,7 @@ struct TORRENT_EXTRA_EXPORT natpmp // maps the ports, if a port is set to 0 // it will not be mapped - int add_mapping(aux::portmap_protocol p, int external_port, int local_port); + int add_mapping(aux::portmap_protocol p, int external_port, tcp::endpoint local_ep); void delete_mapping(int mapping_index); bool get_mapping(int mapping_index, int& local_port, int& external_port , aux::portmap_protocol& protocol) const; diff --git a/include/libtorrent/proxy_base.hpp b/include/libtorrent/proxy_base.hpp index 76b1f7c46..fd1622574 100644 --- a/include/libtorrent/proxy_base.hpp +++ b/include/libtorrent/proxy_base.hpp @@ -249,8 +249,8 @@ protected: bool handle_error(error_code const& e, handler_type const& h); tcp::socket m_sock; - std::string m_hostname; - int m_port; + std::string m_hostname; // proxy host + int m_port; // proxy port endpoint_type m_remote_endpoint; diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index d207760a7..9d053a39c 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -172,13 +172,13 @@ struct TORRENT_EXTRA_EXPORT upnp final // portmap_alert_ respectively. If The mapping fails immediately, the return value // is -1, which means failure. There will not be any error alert notification for // mappings that fail with a -1 return value. - int add_mapping(aux::portmap_protocol p, int external_port, int local_port); + int add_mapping(aux::portmap_protocol p, int external_port, tcp::endpoint local_ep); // This function removes a port mapping. ``mapping_index`` is the index that refers // to the mapping you want to remove, which was returned from add_mapping(). void delete_mapping(int mapping_index); - bool get_mapping(int mapping_index, int& local_port, int& external_port + bool get_mapping(int mapping_index, tcp::endpoint& local_ep, int& external_port , aux::portmap_protocol& protocol) const; void discover_device(); @@ -249,7 +249,7 @@ private: { aux::portmap_protocol protocol = aux::portmap_protocol::none; int external_port = 0; - int local_port = 0; + tcp::endpoint local_ep; }; struct mapping_t @@ -263,7 +263,7 @@ private: // the local port for this mapping. If this is set // to 0, the mapping is not in use - int local_port = 0; + tcp::endpoint local_ep; // the external (on the NAT router) port // for the mapping. This is the port we diff --git a/simulation/libsimulator b/simulation/libsimulator index 0e8d74baf..70feadef8 160000 --- a/simulation/libsimulator +++ b/simulation/libsimulator @@ -1 +1 @@ -Subproject commit 0e8d74baf1f6d9db19857eaa87734faecd530f94 +Subproject commit 70feadef80dc76ae6d5e7c2f92334377d698dd7d diff --git a/simulation/test_http_connection.cpp b/simulation/test_http_connection.cpp index f301448cb..e813a2f7c 100644 --- a/simulation/test_http_connection.cpp +++ b/simulation/test_http_connection.cpp @@ -602,6 +602,53 @@ TORRENT_TEST(http_connection_http_error) test_proxy_failure(settings_pack::http); } +// Requests a proxied SSL connection. This test just ensures that the correct CONNECT request +// is sent to the proxy server. +TORRENT_TEST(http_connection_ssl_proxy) +{ + using sim::asio::ip::address_v4; + sim_config network_cfg; + sim::simulation sim{network_cfg}; + + sim::asio::io_service client_ios(sim, address_v4::from_string("10.0.0.1")); + sim::asio::io_service proxy_ios(sim, address_v4::from_string("50.50.50.50")); + lt::resolver res(client_ios); + + sim::http_server http_proxy(proxy_ios, 4445); + + lt::aux::proxy_settings ps = make_proxy_settings(settings_pack::http); + + int client_counter = 0; + int proxy_counter = 0; + + http_proxy.register_handler("10.0.0.2:8080" + , [&proxy_counter](std::string method, std::string req, std::map& headers) + { + proxy_counter++; + TEST_EQUAL(method, "CONNECT"); + return sim::send_response(403, "Not supported", 1337); + }); + + auto h = std::make_shared(client_ios + , res + , [&client_counter](error_code const& ec, http_parser const& parser + , char const* data, const int size, http_connection& c) + { + client_counter++; + TEST_EQUAL(ec, boost::asio::error::operation_not_supported); + }); + + h->start("10.0.0.2", 8080, seconds(1), 0, &ps, true /*ssl*/); + + error_code e; + sim.run(e); + + TEST_EQUAL(client_counter, 1); + TEST_EQUAL(proxy_counter, 1); + if (e) std::cerr << " run failed: " << e.message() << std::endl; + TEST_EQUAL(e, error_code()); +} + // TODO: test http proxy with password // TODO: test socks5 with password // TODO: test SSL diff --git a/src/http_stream.cpp b/src/http_stream.cpp index 982c60dca..d2da3ed80 100644 --- a/src/http_stream.cpp +++ b/src/http_stream.cpp @@ -64,15 +64,7 @@ namespace libtorrent { // send CONNECT std::back_insert_iterator> p(m_buffer); - std::string endpoint; - if (!m_hostname.empty()) - { - endpoint = m_hostname + ':' + to_string(m_remote_endpoint.port()).data(); - } - else - { - endpoint = print_endpoint(m_remote_endpoint); - } + std::string const endpoint = print_endpoint(m_remote_endpoint); write_string("CONNECT " + endpoint + " HTTP/1.0\r\n", p); if (!m_user.empty()) { diff --git a/src/natpmp.cpp b/src/natpmp.cpp index 3cc84794e..5546d9413 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -229,7 +229,7 @@ void natpmp::delete_mapping(int const index) } int natpmp::add_mapping(portmap_protocol const p, int const external_port - , int const local_port) + , tcp::endpoint const local_ep) { TORRENT_ASSERT(is_single_thread()); @@ -244,7 +244,7 @@ int natpmp::add_mapping(portmap_protocol const p, int const external_port } i->protocol = p; i->external_port = external_port; - i->local_port = local_port; + i->local_port = local_ep.port(); i->act = mapping_t::action::add; int const mapping_index = int(i - m_mappings.begin()); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 6193bb638..148fa95ae 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1528,7 +1528,7 @@ namespace { } #endif // TORRENT_DISABLE_LOGGING } -#endif // TORRENT_WINDOWS +#else { // this is best-effort. ignore errors @@ -1542,6 +1542,7 @@ namespace { } #endif // TORRENT_DISABLE_LOGGING } +#endif // TORRENT_WINDOWS #if TORRENT_USE_IPV6 if (bind_ep.address().is_v6()) @@ -2200,7 +2201,12 @@ namespace { // only update this mapping if we actually have a socket listening if (ep != EndpointType()) - map_handle = m.add_mapping(protocol, ep.port(), ep.port()); + map_handle = m.add_mapping(protocol, ep.port(), ep); + } + + tcp::endpoint to_tcp(udp::endpoint const ep) + { + return tcp::endpoint(ep.address(), ep.port()); } } @@ -2213,12 +2219,12 @@ namespace { if ((mask & remap_natpmp) && m_natpmp) { map_port(*m_natpmp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]); - map_port(*m_natpmp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[0]); + map_port(*m_natpmp, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[0]); } if ((mask & remap_upnp) && m_upnp) { map_port(*m_upnp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[1]); - map_port(*m_upnp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[1]); + map_port(*m_upnp, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[1]); } } @@ -5011,8 +5017,9 @@ namespace { { #ifdef TORRENT_WINDOWS s.set_option(exclusive_address_use(true), ec); -#endif +#else s.set_option(tcp::acceptor::reuse_address(true), ec); +#endif // ignore errors because the underlying socket may not // be opened yet. This happens when we're routing through // a proxy. In that case, we don't yet know the address of @@ -6613,9 +6620,9 @@ namespace { { int ret = 0; if (m_upnp) ret = m_upnp->add_mapping(static_cast(t), external_port - , local_port); + , tcp::endpoint({}, static_cast(local_port))); if (m_natpmp) ret = m_natpmp->add_mapping(static_cast(t), external_port - , local_port); + , tcp::endpoint({}, static_cast(local_port))); return ret; } diff --git a/src/torrent.cpp b/src/torrent.cpp index 7a29f23e6..94d4ee127 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -9776,7 +9776,11 @@ namespace libtorrent { auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end() , [&] (web_seed_t const& w) { return w.url == url && w.type == type; }); - if (i != m_web_seeds.end()) remove_web_seed_iter(i); + if (i != m_web_seeds.end()) + { + remove_web_seed_iter(i); + set_need_save_resume(); + } } void torrent::disconnect_web_seed(peer_connection* p) diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 839ca35b5..0e8cac571 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -433,8 +433,9 @@ void udp_socket::open(udp const& protocol, error_code& ec) error_code err; #ifdef TORRENT_WINDOWS m_socket.set_option(exclusive_address_use(true), err); -#endif +#else m_socket.set_option(boost::asio::socket_base::reuse_address(true), err); +#endif } void udp_socket::bind(udp::endpoint const& ep, error_code& ec) diff --git a/src/upnp.cpp b/src/upnp.cpp index 8558f8bd7..54f02e257 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -182,7 +182,7 @@ void upnp::discover_device_impl() // returns a reference to a mapping or -1 on failure int upnp::add_mapping(portmap_protocol const p, int const external_port - , int const local_port) + , tcp::endpoint const local_ep) { TORRENT_ASSERT(is_single_thread()); // external port 0 means _every_ port @@ -190,9 +190,9 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port #ifndef TORRENT_DISABLE_LOGGING log("adding port map: [ protocol: %s ext_port: %u " - "local_port: %u ] %s", (p == portmap_protocol::tcp?"tcp":"udp") + "local_ep: %s ] %s", (p == portmap_protocol::tcp?"tcp":"udp") , external_port - , local_port, m_disabled ? "DISABLED": ""); + , print_endpoint(local_ep).c_str(), m_disabled ? "DISABLED": ""); #endif if (m_disabled) return -1; @@ -208,7 +208,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port mapping_it->protocol = p; mapping_it->external_port = external_port; - mapping_it->local_port = local_port; + mapping_it->local_ep = local_ep; int const mapping_index = int(mapping_it - m_mappings.begin()); @@ -224,7 +224,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port m.act = mapping_t::action::add; m.protocol = p; m.external_port = external_port; - m.local_port = local_port; + m.local_ep = local_ep; if (!d.service_namespace.empty()) update_map(d, mapping_index); } @@ -242,8 +242,8 @@ void upnp::delete_mapping(int const mapping) #ifndef TORRENT_DISABLE_LOGGING log("deleting port map: [ protocol: %s ext_port: %u " - "local_port: %u ]", (m.protocol == portmap_protocol::tcp?"tcp":"udp"), m.external_port - , m.local_port); + "local_ep: %s ]", (m.protocol == portmap_protocol::tcp?"tcp":"udp"), m.external_port + , print_endpoint(m.local_ep).c_str()); #endif if (m.protocol == portmap_protocol::none) return; @@ -261,7 +261,7 @@ void upnp::delete_mapping(int const mapping) } bool upnp::get_mapping(int const index - , int& local_port + , tcp::endpoint& local_ep , int& external_port , portmap_protocol& protocol) const { @@ -270,7 +270,7 @@ bool upnp::get_mapping(int const index if (index >= int(m_mappings.size()) || index < 0) return false; global_mapping_t const& m = m_mappings[index]; if (m.protocol == portmap_protocol::none) return false; - local_port = m.local_port; + local_ep = m.local_ep; external_port = m.external_port; protocol = m.protocol; return true; @@ -586,7 +586,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer { mapping_t m; m.act = mapping_t::action::add; - m.local_port = j.local_port; + m.local_ep = j.local_ep; m.external_port = j.external_port; m.protocol = j.protocol; d.mapping.push_back(m); @@ -744,9 +744,9 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int const i) "" , soap_action, d.service_namespace.c_str(), d.mapping[i].external_port , (d.mapping[i].protocol == portmap_protocol::udp ? "UDP" : "TCP") - , d.mapping[i].local_port + , d.mapping[i].local_ep.port() , local_endpoint.c_str() - , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_port + , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_ep.port() , d.lease_duration, soap_action); post(d, soap, soap_action); @@ -817,7 +817,7 @@ void upnp::update_map(rootdevice& d, int const i) , std::bind(&upnp::create_port_mapping, self(), _1, std::ref(d), i)); d.upnp_connection->start(d.hostname, d.port - , seconds(10), 1); + , seconds(10), 1, NULL, false, 5, m.local_ep.address()); } else if (m.act == mapping_t::action::del) { @@ -828,7 +828,7 @@ void upnp::update_map(rootdevice& d, int const i) , std::ref(d), i, _5), true, default_max_bottled_buffer_size , std::bind(&upnp::delete_port_mapping, self(), std::ref(d), i)); d.upnp_connection->start(d.hostname, d.port - , seconds(10), 1); + , seconds(10), 1, NULL, false, 5, m.local_ep.address()); } m.act = mapping_t::action::none; diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 631a8289b..8379531ae 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -135,6 +135,7 @@ struct mock_dht_socket final : aux::session_listen_socket tcp::endpoint m_local_endpoint; }; +#if TORRENT_USE_IPV6 struct mock_dht_socket6 final : aux::session_listen_socket { address get_external_address() override { return m_external_address; } @@ -143,6 +144,7 @@ struct mock_dht_socket6 final : aux::session_listen_socket address m_external_address = addr6("2002::1"); tcp::endpoint m_local_endpoint = tcp::endpoint(addr6("2002::1"), 6881); }; +#endif node* get_foreign_node_stub(node_id const&, std::string const&) { diff --git a/test/test_natpmp.cpp b/test/test_natpmp.cpp index 75205a715..61c5dde67 100644 --- a/test/test_natpmp.cpp +++ b/test/test_natpmp.cpp @@ -87,8 +87,9 @@ int main(int argc, char* argv[]) deadline_timer timer(ios); int const tcp_map = natpmp_handler->add_mapping(portmap_protocol::tcp - , atoi(argv[1]), atoi(argv[1])); - natpmp_handler->add_mapping(portmap_protocol::udp, atoi(argv[2]), atoi(argv[2])); + , atoi(argv[1]), tcp::endpoint({}, atoi(argv[1]))); + natpmp_handler->add_mapping(portmap_protocol::udp, atoi(argv[2]) + , tcp::endpoint({}, atoi(argv[2]))); error_code ec; timer.expires_from_now(seconds(2), ec); diff --git a/test/test_session_params.cpp b/test/test_session_params.cpp index 7102919df..80588724f 100644 --- a/test/test_session_params.cpp +++ b/test/test_session_params.cpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/bdecode.hpp" #include "libtorrent/hex.hpp" +#include "setup_transfer.hpp" // for addr6 #include "settings.hpp" #include "test.hpp" @@ -112,8 +113,10 @@ TORRENT_TEST(dht_state) s.nids.emplace_back(addr4("0.0.0.0"), to_hash("0000000000000000000000000000000000000001")); s.nodes.push_back(uep("1.1.1.1", 1)); s.nodes.push_back(uep("2.2.2.2", 2)); +#if TORRENT_USE_IPV6 // not important that IPv6 is disabled here s.nids.emplace_back(addr6("::"), to_hash("0000000000000000000000000000000000000002")); +#endif session_params params(p); params.dht_settings = sett; diff --git a/test/test_upnp.cpp b/test/test_upnp.cpp index 039283093..c992d5296 100644 --- a/test/test_upnp.cpp +++ b/test/test_upnp.cpp @@ -198,8 +198,8 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con std::cout << "router: " << upnp_handler->router_model() << std::endl; TEST_EQUAL(upnp_handler->router_model(), router_model); - int mapping1 = upnp_handler->add_mapping(portmap_protocol::tcp, 500, 500); - int mapping2 = upnp_handler->add_mapping(portmap_protocol::udp, 501, 501); + int const mapping1 = upnp_handler->add_mapping(portmap_protocol::tcp, 500, ep("127.0.0.1", 500)); + int const mapping2 = upnp_handler->add_mapping(portmap_protocol::udp, 501, ep("127.0.0.1", 501)); for (int i = 0; i < 40; ++i) {