diff --git a/ChangeLog b/ChangeLog index 757c1666f..995f2d049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix socks5 support for UDP * add setting urlseed_max_request_bytes to handle large web seed requests * fix python build with CC/CXX environment * add trackers from add_torrent_params/magnet links to separate tiers diff --git a/simulation/fake_peer.hpp b/simulation/fake_peer.hpp index c113680b0..deb8d3e53 100644 --- a/simulation/fake_peer.hpp +++ b/simulation/fake_peer.hpp @@ -53,10 +53,6 @@ struct fake_peer { fake_peer(simulation& sim, char const* ip) : m_ios(sim, asio::ip::address::from_string(ip)) - , m_acceptor(m_ios) - , m_in_socket(m_ios) - , m_out_socket(m_ios) - , m_tripped(false) { boost::system::error_code ec; m_acceptor.open(asio::ip::tcp::v4(), ec); @@ -177,20 +173,20 @@ private: char m_out_buffer[300]; asio::io_service m_ios; - asio::ip::tcp::acceptor m_acceptor; - asio::ip::tcp::socket m_in_socket; - asio::ip::tcp::socket m_out_socket; - bool m_tripped; + asio::ip::tcp::acceptor m_acceptor{m_ios}; + asio::ip::tcp::socket m_in_socket{m_ios}; + asio::ip::tcp::socket m_out_socket{m_ios}; + bool m_tripped = false; std::vector m_send_buffer; }; -struct fake_node +struct udp_server { - fake_node(simulation& sim, char const* ip, int port = 6881) + udp_server(simulation& sim, char const* ip, int port + , std::function(char const*, int)> handler) : m_ios(sim, asio::ip::address::from_string(ip)) - , m_socket(m_ios) - , m_tripped(false) + , m_handler(handler) { boost::system::error_code ec; m_socket.open(asio::ip::udp::v4(), ec); @@ -198,31 +194,73 @@ struct fake_node m_socket.bind(asio::ip::udp::endpoint(asio::ip::address_v4::any(), port), ec); TEST_CHECK(!ec); - fprintf(stderr, "fake_node::async_read_some\n"); - m_socket.async_receive(boost::asio::buffer(m_in_buffer) - , [&] (boost::system::error_code const& ec, size_t bytes_transferred) - { - fprintf(stderr, "fake_node::async_read_some callback. ec: %s transferred: %d\n" - , ec.message().c_str(), int(bytes_transferred)); - if (ec) return; + m_socket.io_control(lt::udp::socket::non_blocking_io(true)); + std::printf("udp_server::async_read_some\n"); + using namespace std::placeholders; + m_socket.async_receive_from(boost::asio::buffer(m_in_buffer) + , m_from, 0, std::bind(&udp_server::on_read, this, _1, _2)); + } + + void close() { m_socket.close(); } + +private: + + void on_read(boost::system::error_code const& ec, size_t bytes_transferred) + { + std::printf("udp_server::async_read_some callback. ec: %s transferred: %d\n" + , ec.message().c_str(), int(bytes_transferred)); + if (ec) return; + + std::vector send_buffer = m_handler(m_in_buffer.data(), int(bytes_transferred)); + + if (!send_buffer.empty()) + { + lt::error_code err; + m_socket.send_to(boost::asio::buffer(send_buffer), m_from, 0, err); + if (err) + { + std::printf("send_to FAILED: %s\n", err.message().c_str()); + } + else + { + std::printf("udp_server responding with %d bytes\n" + , int(send_buffer.size())); + } + } + + std::printf("udp_server::async_read_some\n"); + using namespace std::placeholders; + m_socket.async_receive_from(boost::asio::buffer(m_in_buffer) + , m_from, 0, std::bind(&udp_server::on_read, this, _1, _2)); + } + + std::array m_in_buffer; + + asio::io_service m_ios; + asio::ip::udp::socket m_socket{m_ios}; + asio::ip::udp::endpoint m_from; + + std::function(char const*, int)> m_handler; +}; + +struct fake_node : udp_server +{ + fake_node(simulation& sim, char const* ip, int port = 6881) + : udp_server(sim, ip, port, [&](char const* incoming, int size) + { lt::bdecode_node n; boost::system::error_code err; - int const ret = bdecode(m_in_buffer.data(), m_in_buffer.data() + bytes_transferred - , n, err, nullptr, 10, 200); + int const ret = bdecode(incoming, incoming + size, n, err, nullptr, 10, 200); TEST_EQUAL(ret, 0); - m_incoming_packets.emplace_back(m_in_buffer.data(), m_in_buffer.data() + bytes_transferred); + m_incoming_packets.emplace_back(incoming, incoming + size); // TODO: ideally we would validate the DHT message m_tripped = true; - }); - } - - void close() - { - m_socket.close(); - } + return std::vector(); + }) + {} bool tripped() const { return m_tripped; } @@ -231,15 +269,8 @@ struct fake_node private: - std::array m_in_buffer; - std::vector> m_incoming_packets; - - asio::io_service m_ios; - asio::ip::udp::socket m_socket; - bool m_tripped; - - std::vector m_send_buffer; + bool m_tripped = false; }; inline void add_fake_peers(lt::torrent_handle h) diff --git a/simulation/libsimulator b/simulation/libsimulator index e45086495..36b46fc2c 160000 --- a/simulation/libsimulator +++ b/simulation/libsimulator @@ -1 +1 @@ -Subproject commit e450864958668f8c2ecf8b9839fa278c9c797571 +Subproject commit 36b46fc2c316d34714315c04c87cf74de6efae90 diff --git a/simulation/test_socks5.cpp b/simulation/test_socks5.cpp index f4940ec4a..ae19e56a1 100644 --- a/simulation/test_socks5.cpp +++ b/simulation/test_socks5.cpp @@ -303,3 +303,90 @@ TORRENT_TEST(socks5_tcp_announce) TEST_CHECK(tracker_port != -1); } +TORRENT_TEST(udp_tracker) +{ + using namespace libtorrent; + bool tracker_alert = false; + bool connected = false; + bool announced = false; + run_test( + [](lt::session& ses) + { + set_proxy(ses, settings_pack::socks5); + + // The socks server in libsimulator does not support forwarding UDP + // packets to hostnames (just IPv4 destinations) + settings_pack p; + p.set_bool(settings_pack::proxy_hostnames, false); + ses.apply_settings(p); + + lt::add_torrent_params params; + params.info_hash = sha1_hash("abababababababababab"); + params.trackers.push_back("udp://2.2.2.2:8080/announce"); + params.save_path = "."; + ses.async_add_torrent(params); + }, + [&tracker_alert](lt::session& ses, lt::alert const* alert) { + if (lt::alert_cast(alert)) + tracker_alert = true; + }, + [&](sim::simulation& sim, lt::session& ses + , boost::shared_ptr ti) + { + // listen on port 8080 + udp_server tracker(sim, "2.2.2.2", 8080, + [&](char const* msg, int size) + { + using namespace libtorrent::detail; + std::vector ret; + TEST_CHECK(size >= 16); + + if (size < 16) return ret; + + std::uint64_t connection_id = read_uint64(msg); + std::uint32_t action = read_uint32(msg); + std::uint32_t transaction_id = read_uint32(msg); + + std::uint64_t const conn_id = 0xfeedface1337ull; + + if (action == 0) + { + std::printf("udp connect\n"); + // udp tracker connect + TEST_CHECK(connection_id == 0x41727101980ull); + auto inserter = std::back_inserter(ret); + write_uint32(0, inserter); // connect + write_uint32(transaction_id, inserter); + write_uint64(conn_id, inserter); + connected = true; + } + else if (action == 1) + { + std::printf("udp announce\n"); + // udp tracker announce + TEST_EQUAL(connection_id, conn_id); + + auto inserter = std::back_inserter(ret); + write_uint32(1, inserter); // announce + write_uint32(transaction_id, inserter); + write_uint32(1800, inserter); + write_uint32(0, inserter); // leechers + write_uint32(0, inserter); // seeders + announced = true; + } + else + { + std::printf("unsupported udp tracker action: %d\n", action); + } + return ret; + }); + + sim.run(); + } + ); + + TEST_CHECK(tracker_alert); + TEST_CHECK(connected); + TEST_CHECK(announced); +} + diff --git a/simulation/utils.cpp b/simulation/utils.cpp index ab1b3e432..269a5681b 100644 --- a/simulation/utils.cpp +++ b/simulation/utils.cpp @@ -112,6 +112,7 @@ void set_proxy(lt::session& ses, int proxy_type, int flags, bool proxy_peer_conn p.set_bool(settings_pack::proxy_hostnames, true); p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections); p.set_bool(settings_pack::proxy_tracker_connections, true); + p.set_bool(settings_pack::force_proxy, true); ses.apply_settings(p); } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index d24af11e8..0fdbbc047 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2109,6 +2109,7 @@ retry: maybe_update_udp_mapping(0, true, ssl_port, ssl_port); maybe_update_udp_mapping(1, true, ssl_port, ssl_port); } + m_ssl_udp_socket.set_proxy_settings(proxy()); } } else @@ -2170,6 +2171,8 @@ retry: maybe_update_udp_mapping(0, false, m_listen_interface.port(), m_listen_interface.port()); maybe_update_udp_mapping(1, false, m_listen_interface.port(), m_listen_interface.port()); } + + m_udp_socket.set_proxy_settings(proxy()); } // we made it! now post all the listen_succeeded_alerts diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 646e9d2fa..73daeadf9 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -845,10 +845,14 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec) } } #endif + + error_code err; + m_bind_port = m_ipv4_sock.local_endpoint(err).port(); + if (err) m_bind_port = ep.port(); + #if TORRENT_USE_ASSERTS m_started = true; #endif - m_bind_port = ep.port(); } void udp_socket::set_proxy_settings(aux::proxy_settings const& ps)