32 #include <boost/asio/buffer.hpp> 33 #include <boost/asio/io_service.hpp> 34 #include <boost/asio/ip/tcp.hpp> 35 #include <boost/asio/read.hpp> 36 #include <boost/asio/steady_timer.hpp> 37 #include <boost/asio/write.hpp> 38 #include <boost/endian/conversion.hpp> 39 #include <boost/system/error_code.hpp> 40 #include <boost/thread/scoped_thread.hpp> 41 #include <boost/thread/thread.hpp> 44 #include <gtest/gtest.h> 60 static constexpr
const char v2_onion[] =
61 "etnto2bturnore26.onion";
62 static constexpr
const char v3_onion[] =
63 "vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion";
66 TEST(tor_address, constants)
98 TEST(tor_address, unblockable_types)
188 TEST(tor_address, generic_network_address)
223 TEST(tor_address, epee_serializev_v2)
238 test_command command{};
260 ASSERT_TRUE(stg.get_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
261 EXPECT_EQ(std::strlen(v2_onion), host.size());
264 EXPECT_TRUE(stg.set_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
274 TEST(tor_address, epee_serializev_v3)
289 test_command command{};
311 ASSERT_TRUE(stg.get_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
312 EXPECT_EQ(std::strlen(v3_onion), host.size());
315 EXPECT_TRUE(stg.set_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
325 TEST(tor_address, epee_serialize_unknown)
340 test_command command{};
362 ASSERT_TRUE(stg.get_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
366 EXPECT_TRUE(stg.set_value(
"host", host, stg.open_section(
"tor",
nullptr,
false)));
376 TEST(tor_address, boost_serialize_v2)
386 std::ostringstream stream{};
391 buffer = stream.str();
401 std::istringstream stream{buffer};
411 TEST(tor_address, boost_serialize_v3)
421 std::ostringstream stream{};
426 buffer = stream.str();
436 std::istringstream stream{buffer};
446 TEST(tor_address, boost_serialize_unknown)
456 std::ostringstream stream{};
461 buffer = stream.str();
471 std::istringstream stream{buffer};
531 using stream_type = boost::asio::ip::tcp;
535 boost::asio::io_service io_service;
536 boost::asio::io_service::work work;
538 stream_type::acceptor acceptor;
540 std::atomic<bool> connected;
546 acceptor(io_service),
547 io([this] () {
try { this->io_service.run(); }
catch (
const std::exception& e) {
MERROR(e.what()); }}),
550 acceptor.open(boost::asio::ip::tcp::v4());
551 acceptor.bind(stream_type::endpoint{boost::asio::ip::address_v4::loopback(), 0});
553 acceptor.async_accept(server, [
this] (boost::system::error_code
error) {
554 this->connected =
true;
556 throw boost::system::system_error{
error};
560 ~io_thread() noexcept
568 struct checked_client
570 std::atomic<bool>* called_;
582 TEST(socks_client, unsupported_command)
584 boost::asio::io_service io_service{};
593 EXPECT_FALSE(test_client->set_connect_command(
"example.com", 8080));
596 EXPECT_FALSE(test_client->set_resolve_command(
"example.com"));
602 boost::asio::io_service io_service{};
612 TEST(socks_client, connect_command)
617 std::atomic<bool> called{
false};
623 ASSERT_TRUE(test_client->set_connect_command(
"example.com", 8080));
626 while (!io.connected)
630 4, 1, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00,
631 'e',
'x',
'a',
'm',
'p',
'l',
'e',
'.',
'c',
'o',
'm', 0x00
635 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
636 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
638 const std::uint8_t reply_bytes[] = {0, 90, 0, 0, 0, 0, 0, 0};
639 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
645 TEST(socks_client, connect_command_failed)
650 std::atomic<bool> called{
false};
657 test_client->set_connect_command(
663 while (!io.connected)
667 4, 1, 0x0b, 0xb8, 0x00, 0x00, 0x13, 0x88, 0x00
671 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
672 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
674 const std::uint8_t reply_bytes[] = {0, 91, 0, 0, 0, 0, 0, 0};
675 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
681 TEST(socks_client, resolve_command)
683 static std::uint8_t reply_bytes[] = {0, 90, 0, 0, 0xff, 0, 0xad, 0};
687 std::atomic<unsigned> called_;
696 virtual void done(boost::system::error_code
error, std::shared_ptr<client>
self)
override 703 ASSERT_EQ(
sizeof(reply_bytes), buffer().size());
704 EXPECT_EQ(0u, std::memcmp(buffer().data(), reply_bytes,
sizeof(reply_bytes)));
714 auto test_client = std::make_shared<resolve_client>(
std::move(client));
717 ASSERT_TRUE(test_client->set_resolve_command(
"example.com"));
720 while (!io.connected)
724 4, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
725 'e',
'x',
'a',
'm',
'p',
'l',
'e',
'.',
'c',
'o',
'm', 0x00
729 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
730 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
732 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
735 while (test_client->called_ == 0);
737 test_client->expected_ =
true;
738 ASSERT_TRUE(test_client->set_resolve_command(
"example.com"));
742 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
743 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
746 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
749 while (test_client->called_ == 1);
755 boost::asio::steady_timer timeout{io.io_service};
756 timeout.expires_from_now(std::chrono::seconds{5});
758 boost::unique_future<boost::asio::ip::tcp::socket> sock =
761 while (!io.connected)
764 4, 1, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00,
765 'e',
'x',
'a',
'm',
'p',
'l',
'e',
'.',
'c',
'o',
'm', 0x00
769 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
770 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
772 const std::uint8_t reply_bytes[] = {0, 90, 0, 0, 0, 0, 0, 0};
773 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
775 ASSERT_EQ(boost::future_status::ready, sock.wait_for(boost::chrono::seconds{3}));
782 boost::asio::steady_timer timeout{io.io_service};
783 timeout.expires_from_now(std::chrono::seconds{5});
785 boost::unique_future<boost::asio::ip::tcp::socket> sock =
788 while (!io.connected)
791 4, 1, 0x1f, 0x90, 0xfa, 0x58, 0x7d, 0x63, 0x00
795 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
796 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
798 const std::uint8_t reply_bytes[] = {0, 90, 0, 0, 0, 0, 0, 0};
799 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
801 ASSERT_EQ(boost::future_status::ready, sock.wait_for(boost::chrono::seconds{3}));
808 boost::asio::steady_timer timeout{io.io_service};
809 timeout.expires_from_now(std::chrono::seconds{5});
811 boost::unique_future<boost::asio::ip::tcp::socket> sock =
814 while (!io.connected)
817 4, 1, 0x1f, 0x90, 0xfa, 0x58, 0x7d, 0x63, 0x00
821 boost::asio::read(io.server, boost::asio::buffer(actual_bytes));
822 EXPECT_TRUE(std::memcmp(expected_bytes, actual_bytes,
sizeof(actual_bytes)) == 0);
824 const std::uint8_t reply_bytes[] = {0, 91, 0, 0, 0, 0, 0, 0};
825 boost::asio::write(io.server, boost::asio::buffer(reply_bytes));
827 ASSERT_EQ(boost::future_status::ready, sock.wait_for(boost::chrono::seconds{3}));
828 EXPECT_THROW(sock.get().is_open(), boost::system::system_error);
834 boost::asio::steady_timer timeout{io.io_service};
835 timeout.expires_from_now(std::chrono::milliseconds{10});
837 boost::unique_future<boost::asio::ip::tcp::socket> sock =
840 ASSERT_EQ(boost::future_status::ready, sock.wait_for(boost::chrono::seconds{3}));
841 EXPECT_THROW(sock.get().is_open(), boost::system::system_error);
851 std::make_error_condition(std::errc::not_a_socket),
860 }().matches(std::errc::not_a_socket)
868 catch (
const std::system_error& e)
871 EXPECT_EQ(std::make_error_condition(std::errc::not_a_socket), e.code());
886 ASSERT_EQ(0u, zmq_bind(recv_socket.get(),
"inproc://testing"));
887 ASSERT_EQ(0u, zmq_connect(send_socket.get(),
"inproc://testing"));
900 TEST(zmq, read_write_multipart)
910 ASSERT_EQ(0u, zmq_bind(recv_socket.get(),
"inproc://testing"));
911 ASSERT_EQ(0u, zmq_connect(send_socket.get(),
"inproc://testing"));
917 for (
unsigned i = 0; i < 3; ++i)
934 TEST(zmq, read_write_termination)
940 boost::scoped_thread<> thread{};
947 ASSERT_EQ(0u, zmq_bind(recv_socket.get(),
"inproc://testing"));
948 ASSERT_EQ(0u, zmq_connect(send_socket.get(),
"inproc://testing"));
960 thread = boost::scoped_thread<>{
static bool connect_and_send(std::shared_ptr< client > self, const stream_type::endpoint &proxy_address)
#define EXPECT_TRUE(condition)
Type not supported by get_network_address
std::error_code make_error_code(int code) noexcept
#define EXPECT_STREQ(s1, s2)
expect< std::string > receive(void *const socket, const int flags)
#define EXPECT_THROW(statement, expected_exception)
static const char * unknown_str() noexcept
const std::error_category & error_category() noexcept
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
static tor_address unknown() noexcept
#define EXPECT_STRNE(s1, s2)
#define KV_SERIALIZE(varialble)
#define ELECTRONEUM_ZMQ_THROW(msg)
Throw an exception with a custom msg, current ZMQ error code, filename, and line number.
bool load_from_binary(const epee::span< const uint8_t > target)
std::shared_ptr< client > make_connect_client(client::stream_type::socket &&proxy, socks::version ver, Handler handler)
static constexpr bool is_loopback() noexcept
std::error_code error() const noexcept
Extensions defined in Tor codebase.
#define ASSERT_FALSE(condition)
static constexpr bool is_local() noexcept
Primarily for use with epee::net_utils::http_client.
#define EXPECT_LT(val1, val2)
#define ASSERT_EQ(val1, val2)
void rand(size_t N, uint8_t *bytes)
expect< epee::net_utils::network_address > get_network_address(const boost::string_ref address, const std::uint16_t default_port)
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
#define EXPECT_NE(val1, val2)
static constexpr epee::net_utils::address_type get_type_id() noexcept
std::string message("Message requiring signing")
TEST(tor_address, constants)
boost::endian::big_uint32_t ip
Client support for socks connect and resolve commands.
expect< void > success() noexcept
#define ELECTRONEUM_UNWRAP(...)
const T & move(const T &t)
Tor onion address; internal format not condensed/decoded.
#define ASSERT_TRUE(condition)
Invalid base32 or length.
expect< void > send(const epee::span< const std::uint8_t > payload, void *const socket, const int flags) noexcept
#define EXPECT_FALSE(condition)
#define END_KV_SERIALIZE_MAP()
Outside of 0-65535 range.
static expect< tor_address > make(boost::string_ref address, std::uint16_t default_port=0)
error
Tracks LMDB error codes.
static bool send(std::shared_ptr< client > self)
#define EXPECT_EQ(val1, val2)
#define ELECTRONEUM_ZMQ_CHECK(...)
If the expression is less than 0, return the current ZMQ error code.
#define BEGIN_KV_SERIALIZE_MAP()
#define ASSERT_NE(val1, val2)