32#include <boost/asio/buffer.hpp>
33#include <boost/asio/read.hpp>
34#include <boost/asio/write.hpp>
35#include <boost/endian/arithmetic.hpp>
36#include <boost/endian/conversion.hpp>
51 constexpr const unsigned v4_reply_size = 8;
52 constexpr const std::uint8_t v4_connect_command = 1;
53 constexpr const std::uint8_t v4tor_resolve_command = 0xf0;
54 constexpr const std::uint8_t v4_request_granted = 90;
59 std::uint8_t command_code;
60 boost::endian::big_uint16_t port;
61 boost::endian::big_uint32_t ip;
64 std::size_t write_domain_header(epee::span<std::uint8_t> out,
const std::uint8_t command,
const std::uint16_t port,
const boost::string_ref domain)
66 if (std::numeric_limits<std::size_t>::max() -
sizeof(v4_header) - 2 < domain.size())
69 const std::size_t buf_size =
sizeof(v4_header) + domain.size() + 2;
70 if (
out.size() < buf_size)
74 const v4_header temp{4, command, port, std::uint32_t(1)};
75 std::memcpy(
out.data(), std::addressof(temp),
sizeof(temp));
76 out.remove_prefix(
sizeof(temp));
81 std::memcpy(
out.data(), domain.data(), domain.size());
82 out.remove_prefix(domain.size());
88 struct socks_category : boost::system::error_category
90 explicit socks_category() noexcept
94 const char*
name() const noexcept
override
96 return "net::socks::error_category";
104 return "Socks request rejected or failed";
106 return "Socks request rejected because server cannot connect to identd on the client";
108 return "Socks request rejected because the client program and identd report different user-ids";
111 return "Socks boost::async_read read fewer bytes than expected";
113 return "Socks boost::async_write wrote fewer bytes than expected";
115 return "Socks server returned unexpected version in reply";
120 return "Unknown net::socks::error";
123 boost::system::error_condition default_error_condition(
int value)
const noexcept override
129 return boost::system::errc::io_error;
131 return boost::system::errc::protocol_error;
136 return boost::system::errc::protocol_error;
138 return boost::system::error_condition{
value, *
this};
145 static const socks_category instance{};
155 static_assert(1 <
sizeof(
self_->buffer_),
"buffer too small for v4 response");
160 self.buffer_size_ = std::min(bytes,
sizeof(self.buffer_));
164 else if (self.
buffer().
size() <
sizeof(v4_header))
166 else if (self.buffer_[0] != 0)
168 else if (self.buffer_[1] != v4_request_granted)
171 self.done(boost::system::error_code{}, std::move(
self_));
182 static_assert(
sizeof(v4_header) <=
sizeof(self.buffer_),
"buffer too small for v4 response");
183 return boost::asio::buffer(self.buffer_,
sizeof(v4_header));
196 boost::asio::async_read(self.proxy_,
get_buffer(self), self.strand_.wrap(
completed{std::move(self_)}));
207 return boost::asio::buffer(self.buffer_, self.buffer_size_);
218 boost::asio::async_write(self.proxy_,
get_buffer(self), self.strand_.wrap(
read{std::move(self_)}));
224 : proxy_(
std::move(proxy)), strand_(
GET_IO_SERVICE(proxy_)), buffer_size_(0), buffer_(), ver_(ver)
241 static_assert(
sizeof(v4_header) <
sizeof(buffer_),
"buffer size too small for request");
242 static_assert(0 <
sizeof(buffer_),
"buffer size too small for null termination");
245 const v4_header temp{4, v4_connect_command,
address.port(), boost::endian::big_to_native(
address.ip())};
246 std::memcpy(std::addressof(buffer_), std::addressof(temp),
sizeof(temp));
247 buffer_[
sizeof(temp)] = 0;
248 buffer_size_ =
sizeof(temp) + 1;
265 const std::size_t buf_used = write_domain_header(buffer_, v4_connect_command, port, domain);
266 buffer_size_ = buf_used;
267 return buf_used != 0;
289 const std::size_t buf_used = write_domain_header(buffer_, v4tor_resolve_command, 0, domain);
290 buffer_size_ = buf_used;
291 return buf_used != 0;
296 if (self && !self->buffer().empty())
299 alias.proxy_.async_connect(proxy_address, alias.strand_.wrap(
write{std::move(self)}));
307 if (self && !self->buffer().empty())
310 boost::asio::async_write(alias.proxy_,
write::get_buffer(alias), alias.strand_.wrap(
read{std::move(self)}));
318 if (
self_ &&
error != boost::system::errc::operation_canceled)
320 const std::shared_ptr<client> self = std::move(
self_);
321 self->strand_.dispatch([self] ()
323 if (self && self->proxy_.is_open())
325 self->proxy_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
326 self->proxy_.close();
constexpr std::size_t size() const noexcept
b32 i2p address; internal format not condensed/decoded.
bool set_resolve_command(boost::string_ref domain)
Try to set domain as remote DNS A record lookup request.
bool set_connect_command(const epee::net_utils::ipv4_network_address &address)
Try to set address as remote connection request.
epee::span< const std::uint8_t > buffer() const noexcept
static bool connect_and_send(std::shared_ptr< client > self, const stream_type::endpoint &proxy_address)
client(stream_type::socket &&proxy, socks::version ver)
static bool send(std::shared_ptr< client > self)
socks::version socks_version() const noexcept
Tor onion address; internal format not condensed/decoded.
std::string message("Message requiring signing")
const boost::system::error_category & error_category() noexcept
error
Possible errors with socks communication. Defined in https://www.openssh.com/txt/socks4....
version
Supported socks variants.
@ v4a_tor
Extensions defined in Tor codebase.
#define GET_IO_SERVICE(s)
const GenericPointer< typename T::ValueType > T2 value
void operator()(boost::system::error_code error=boost::system::error_code{})
std::shared_ptr< client > self_
void operator()(const boost::system::error_code error, const std::size_t bytes) const
std::shared_ptr< client > self_
std::shared_ptr< client > self_
static boost::asio::mutable_buffers_1 get_buffer(client &self) noexcept
void operator()(const boost::system::error_code error, const std::size_t bytes)
void operator()(const boost::system::error_code error)
std::shared_ptr< client > self_
static boost::asio::const_buffers_1 get_buffer(client const &self) noexcept