From 747c5b76131c26a310f4b7490b65f6927adf1658 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 9 Apr 2022 14:37:25 +0200 Subject: [PATCH 1/4] fix jamfile to not apply -export-dynamic to clang --- Jamfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Jamfile b/Jamfile index 48a22c66554..12314ad3d9a 100644 --- a/Jamfile +++ b/Jamfile @@ -141,8 +141,7 @@ rule linking ( properties * ) result += libiconv ; } - if ( gcc in $(properties) - || clang in $(properties) ) + if gcc in $(properties) && linux in $(properties) && ( on in $(properties) || production in $(properties) From 41e17c4efafc41066ab94ce1fb770e7d1719fec3 Mon Sep 17 00:00:00 2001 From: Raymond Wong Date: Mon, 4 Apr 2022 18:08:37 +0800 Subject: [PATCH 2/4] cmake: refine atomics check Check for 8-bit atomic operation. Fixes linking on RISC-V systems. Closes #6794 Signed-off-by: Raymond Wong --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b124d54bbf4..f85276fa049 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -659,18 +659,21 @@ if (NOT Windows) return 0; } ]=]) + string(REPLACE "std::atomic" "std::atomic" ATOMICS8_TEST_SOURCE "${ATOMICS_TEST_SOURCE}") string(REPLACE "std::atomic" "std::atomic" ATOMICS64_TEST_SOURCE "${ATOMICS_TEST_SOURCE}") if(APPLE) set(CMAKE_REQUIRED_FLAGS "-std=c++11") endif() check_cxx_source_compiles("${ATOMICS_TEST_SOURCE}" HAVE_CXX_ATOMICS_WITHOUT_LIB) + check_cxx_source_compiles("${ATOMICS8_TEST_SOURCE}" HAVE_CXX_ATOMICS8_WITHOUT_LIB) check_cxx_source_compiles("${ATOMICS64_TEST_SOURCE}" HAVE_CXX_ATOMICS64_WITHOUT_LIB) - if((NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) OR (NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)) + if((NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) OR (NOT HAVE_CXX_ATOMICS8_WITHOUT_LIB) OR (NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)) set(CMAKE_REQUIRED_LIBRARIES "atomic") check_cxx_source_compiles("${ATOMICS_TEST_SOURCE}" HAVE_CXX_ATOMICS_WITH_LIB) + check_cxx_source_compiles("${ATOMICS8_TEST_SOURCE}" HAVE_CXX_ATOMICS8_WITH_LIB) check_cxx_source_compiles("${ATOMICS64_TEST_SOURCE}" HAVE_CXX_ATOMICS64_WITH_LIB) - if ((NOT HAVE_CXX_ATOMICS_WITH_LIB) OR (NOT HAVE_CXX_ATOMICS64_WITH_LIB)) + if ((NOT HAVE_CXX_ATOMICS_WITH_LIB) OR (NOT HAVE_CXX_ATOMICS8_WITH_LIB) OR (NOT HAVE_CXX_ATOMICS64_WITH_LIB)) message(FATAL_ERROR "No native support for std::atomic, or libatomic not found!") else() message(STATUS "Linking with libatomic for atomics support") From 175c20a897ce29a6ba42b564d015d90d7dceefb1 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 9 Apr 2022 13:27:03 +0200 Subject: [PATCH 3/4] simplify part of pe_crypto, init_bt_handshake and stats accounting --- include/libtorrent/bt_peer_connection.hpp | 5 +- include/libtorrent/pe_crypto.hpp | 1 - src/bt_peer_connection.cpp | 155 +++++++++++----------- 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index 94f30b1eb53..66a8b1169a8 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -345,6 +345,10 @@ namespace libtorrent { private: +#if !defined TORRENT_DISABLE_ENCRYPTION + void init_bt_handshake(); +#endif + enum class state_t : std::uint8_t { #if !defined TORRENT_DISABLE_ENCRYPTION @@ -355,7 +359,6 @@ namespace libtorrent { read_pe_cryptofield, read_pe_pad, read_pe_ia, - init_bt_handshake, #endif read_protocol_identifier, read_info_hash, diff --git a/include/libtorrent/pe_crypto.hpp b/include/libtorrent/pe_crypto.hpp index 3bc150025a7..da786918008 100644 --- a/include/libtorrent/pe_crypto.hpp +++ b/include/libtorrent/pe_crypto.hpp @@ -73,7 +73,6 @@ namespace libtorrent { { public: dh_key_exchange(); - bool good() const { return true; } // Get local public key key_t const& get_local_key() const { return m_dh_local_key; } diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 9d0029e189a..3ce0d8df6c7 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -488,7 +488,7 @@ namespace { #endif m_dh_key_exchange.reset(new (std::nothrow) dh_key_exchange); - if (!m_dh_key_exchange || !m_dh_key_exchange->good()) + if (!m_dh_key_exchange) { disconnect(errors::no_memory, operation_t::encryption); return; @@ -2451,6 +2451,44 @@ namespace { on_receive_impl(bytes_transferred); } +#if !defined TORRENT_DISABLE_ENCRYPTION + void bt_peer_connection::init_bt_handshake() + { + m_encrypted = true; + if (m_rc4_encrypted) + { + switch_send_crypto(m_rc4); + switch_recv_crypto(m_rc4); + } + + // decrypt remaining received bytes + if (m_rc4_encrypted) + { + span const remaining = m_recv_buffer.mutable_buffer() + .subspan(m_recv_buffer.packet_size()); + rc4_decrypt(remaining); + +#ifndef TORRENT_DISABLE_LOGGING + peer_log(peer_log_alert::info, "ENCRYPTION" + , "decrypted remaining %d bytes", int(remaining.size())); +#endif + } + m_rc4.reset(); + + // encrypted portion of handshake completed, toggle + // peer_info pe_support flag back to true + if (is_outgoing() && + m_settings.get_int(settings_pack::out_enc_policy) + == settings_pack::pe_enabled) + { + torrent_peer* pi = peer_info_struct(); + TORRENT_ASSERT(pi); + + pi->pe_support = true; + } + } +#endif + void bt_peer_connection::on_receive_impl(std::size_t bytes_transferred) { std::shared_ptr t = associated_torrent().lock(); @@ -2826,30 +2864,28 @@ namespace { m_rc4_encrypted = true; } - int const len_pad = aux::read_int16(recv_buffer); + int len_pad = aux::read_int16(recv_buffer); if (len_pad < 0 || len_pad > 512) { disconnect(errors::invalid_pad_size, operation_t::encryption, peer_error); return; } - m_state = state_t::read_pe_pad; + // len(IA) at the end of pad if (!is_outgoing()) - m_recv_buffer.reset(len_pad + 2); // len(IA) at the end of pad + len_pad += 2; + + if (len_pad > 0) + { + m_state = state_t::read_pe_pad; + m_recv_buffer.reset(len_pad); + } else { - if (len_pad == 0) - { - m_encrypted = true; - if (m_rc4_encrypted) - { - switch_send_crypto(m_rc4); - switch_recv_crypto(m_rc4); - } - m_state = state_t::init_bt_handshake; - } - else - m_recv_buffer.reset(len_pad); + TORRENT_ASSERT(len_pad == 0); + init_bt_handshake(); + m_state = state_t::read_protocol_identifier; + m_recv_buffer.reset(20); } } @@ -2871,55 +2907,51 @@ namespace { recv_buffer = recv_buffer.subspan(pad_size); int const len_ia = aux::read_int16(recv_buffer); - if (len_ia < 0) +#ifndef TORRENT_DISABLE_LOGGING + peer_log(peer_log_alert::info, "ENCRYPTION", "len(IA) : %d", len_ia); +#endif + if (len_ia < 0 || len_ia > 68) { disconnect(errors::invalid_encrypt_handshake, operation_t::encryption, peer_error); return; } -#ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::info, "ENCRYPTION", "len(IA) : %d", len_ia); -#endif if (len_ia == 0) { - // everything after this is Encrypt2 - m_encrypted = true; - if (m_rc4_encrypted) - { - switch_send_crypto(m_rc4); - switch_recv_crypto(m_rc4); - } - m_state = state_t::init_bt_handshake; + // everything after this is encrypted + init_bt_handshake(); + m_state = state_t::read_protocol_identifier; + m_recv_buffer.reset(20); } else { + // The other peer indicated that a non-zero bytes will be + // encrypted at the start of the underlying bittorrent + // protocol. This number of bytes, len_ia, is not + // necessarily aligned to message boundaries. We first read + // that many bytes, decrypt it, and then pass it back into + // the regular protocol parser m_state = state_t::read_pe_ia; m_recv_buffer.reset(len_ia); } } else // is_outgoing() { - // everything that arrives after this is Encrypt2 - m_encrypted = true; - if (m_rc4_encrypted) - { - switch_send_crypto(m_rc4); - switch_recv_crypto(m_rc4); - } - m_state = state_t::init_bt_handshake; + // everything that arrives after this is encrypted + init_bt_handshake(); + m_state = state_t::read_protocol_identifier; + m_recv_buffer.reset(20); } } if (m_state == state_t::read_pe_ia) { - received_bytes(0, int(bytes_transferred)); - bytes_transferred = 0; TORRENT_ASSERT(!is_outgoing()); TORRENT_ASSERT(!m_encrypted); if (!m_recv_buffer.packet_finished()) return; - // ia is always rc4, so decrypt it + // the IA bytes are always rc4, so decrypt it rc4_decrypt(m_recv_buffer.mutable_buffer().first(m_recv_buffer.packet_size())); #ifndef TORRENT_DISABLE_LOGGING @@ -2936,47 +2968,14 @@ namespace { } m_rc4.reset(); + // now that we have decrypted IA length of bytes, we + // reinterpret the receive buffer as the very start of a normal + // connection. First we expect to find the protocol identifier + // (i.e. "BitTorrent Protocol") m_state = state_t::read_protocol_identifier; m_recv_buffer.cut(0, 20); } - if (m_state == state_t::init_bt_handshake) - { - received_bytes(0, int(bytes_transferred)); - bytes_transferred = 0; - TORRENT_ASSERT(m_encrypted); - - // decrypt remaining received bytes - if (m_rc4_encrypted) - { - span const remaining = m_recv_buffer.mutable_buffer() - .subspan(m_recv_buffer.packet_size()); - rc4_decrypt(remaining); - -#ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::info, "ENCRYPTION" - , "decrypted remaining %d bytes", int(remaining.size())); -#endif - } - m_rc4.reset(); - - // payload stream, start with 20 handshake bytes - m_state = state_t::read_protocol_identifier; - m_recv_buffer.reset(20); - - // encrypted portion of handshake completed, toggle - // peer_info pe_support flag back to true - if (is_outgoing() && - m_settings.get_int(settings_pack::out_enc_policy) - == settings_pack::pe_enabled) - { - torrent_peer* pi = peer_info_struct(); - TORRENT_ASSERT(pi); - - pi->pe_support = true; - } - } - #endif // #if !defined TORRENT_DISABLE_ENCRYPTION if (m_state == state_t::read_protocol_identifier) @@ -3034,6 +3033,10 @@ namespace { peer_log(peer_log_alert::info, "ENCRYPTION", "attempting encrypted connection"); #endif m_state = state_t::read_pe_dhkey; + // we're "cutting" off 0 bytes from the receive buffer here + // because we want to interpret it as something else. It didn't + // contain the expected bittorrent handshake string, so let's + // try again to interpret it as an encrypted handshake m_recv_buffer.cut(0, dh_key_len); TORRENT_ASSERT(!m_recv_buffer.packet_finished()); return; From 07a5305a95096ea76633c1b6a7943026608d2bb0 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 11 Apr 2022 16:46:16 +0200 Subject: [PATCH 4/4] fix build with encryption support disabled --- include/libtorrent/aux_/torrent_list.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/libtorrent/aux_/torrent_list.hpp b/include/libtorrent/aux_/torrent_list.hpp index f2449a4d339..99dd0f30a62 100644 --- a/include/libtorrent/aux_/torrent_list.hpp +++ b/include/libtorrent/aux_/torrent_list.hpp @@ -234,7 +234,9 @@ struct torrent_list #endif TORRENT_ASSERT(all_torrents == all_indexed_torrents); +#if !defined TORRENT_DISABLE_ENCRYPTION TORRENT_ASSERT(all_torrents == all_obf_indexed_torrents); +#endif } #endif