diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 17 | ||||
m--------- | boost-asio-fastbuffer | 0 | ||||
-rw-r--r-- | socks5.cpp | 104 | ||||
-rw-r--r-- | socks5.hpp | 69 |
5 files changed, 81 insertions, 112 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9980dbe --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "boost-asio-fastbuffer"] + path = boost-asio-fastbuffer + url = https://github.com/utoni/boost-asio-fastbuffer.git @@ -1,5 +1,6 @@ CXX = g++ -CXXFLAGS = -Wall -Wextra +GIT = git +CXXFLAGS = -Wall -Wextra -Iboost-asio-fastbuffer SERVER_HDRS = socks5.hpp SERVER_SRCS = socks5.cpp main.cpp @@ -14,12 +15,20 @@ ifneq ($(DEBUG),) CXXFLAGS += -g #-DBOOST_ASIO_ENABLE_HANDLER_TRACKING=1 endif -all: server +all: git server -server: $(SERVER_HDRS) $(SERVER_SRCS) +git: boost-asio-fastbuffer/fastbuffer.hpp + +boost-asio-fastbuffer/fastbuffer.hpp: + $(GIT) submodule update --init + +server: boost-asio-fastbuffer/fastbuffer.hpp $(SERVER_HDRS) $(SERVER_SRCS) $(CXX) $(CXXFLAGS) $(SERVER_SRCS) -o $@ clean: rm -f server -.PHONY: clean +distclean: clean + $(GIT) submodule deinit --all --force + +.PHONY: all git clean distclean diff --git a/boost-asio-fastbuffer b/boost-asio-fastbuffer new file mode 160000 +Subproject c652e22dd1cfe059a30604e772529f1d86a1a28 @@ -28,12 +28,34 @@ ProxySessionBase::ProxySessionBase(std::uint32_t session_id, ProxySessionBase::ProxySessionBase(std::uint32_t session_id, boost::asio::ip::tcp::socket &&client_socket, - StreamBuffer &&input_buffer, - StreamBuffer &&output_buffer) + ContiguousStreamBuffer &&input_buffer, + ContiguousStreamBuffer &&output_buffer) : m_sessionId{session_id}, m_inBuf{std::move(input_buffer)}, m_outBuf{std::move(output_buffer)}, m_clientSocket{std::move(client_socket)} {} +void ProxySessionBase::async_read(const CompletionHandler &handler, + std::size_t expected_length) { + if (expected_length == 0) + m_clientSocket.async_read_some( + +m_inBuf, [this, handler](const boost::system::error_code &ec, + const std::size_t length) { + if (ec || length == 0) + return; + handler(length); + }); + else + boost::asio::async_read( + m_clientSocket, +m_inBuf, + boost::asio::transfer_exactly(expected_length), + [this, expected_length, handler](const boost::system::error_code &ec, + const std::size_t length) { + if (ec || length != expected_length) + return; + handler(length); + }); +} + ProxySessionAuth::ProxySessionAuth(std::uint32_t session_id, tcp::socket &&client_socket) : ProxySessionBase(session_id, std::move(client_socket), 32), @@ -41,28 +63,21 @@ ProxySessionAuth::ProxySessionAuth(std::uint32_t session_id, m_destinationSocket{m_clientSocket.get_executor()} {} void ProxySessionAuth::start() { - boost::asio::async_read( - m_clientSocket, +m_inBuf, boost::asio::transfer_exactly(2), - boost::bind(&ProxySessionAuth::recv_client_greeting, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + async_read([self = shared_from_this()]( + std::size_t length) { self->recv_client_greeting(length); }, + 2); } -void ProxySessionAuth::recv_client_greeting(const boost::system::error_code &ec, - std::size_t length) { - if (ec || length == 0) - return; +void ProxySessionAuth::recv_client_greeting(std::size_t length) { m_inBuf += length; if (m_inBuf[0] != 0x05 || m_inBuf[1] > 0x09 || m_inBuf[1] == 0x00) return; const std::size_t expected_size = std::size_t(2) + m_inBuf[1]; if (m_inBuf.size() < expected_size) { - boost::asio::async_read( - m_clientSocket, +m_inBuf, boost::asio::transfer_exactly(expected_size - m_inBuf.size()), - boost::bind(&ProxySessionAuth::recv_client_greeting, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + async_read([self = shared_from_this(), expected_size]( + std::size_t length) { self->recv_client_greeting(length); }, + expected_size - m_inBuf.size()); return; } @@ -95,28 +110,17 @@ void ProxySessionAuth::send_server_greeting(bool auth_supported) { boost::bind(&ProxySessionAuth::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); - process_connection_request(); + async_read([self = shared_from_this()]( + std::size_t length) { self->recv_connection_request(length); }, + 6); } -void ProxySessionAuth::recv_connection_request( - const boost::system::error_code &ec, std::size_t length) { - if (ec || length == 0) - return; +void ProxySessionAuth::recv_connection_request(std::size_t length) { m_inBuf += length; - process_connection_request(); } void ProxySessionAuth::process_connection_request() { - if (m_inBuf.size() < 6) { - boost::asio::async_read( - m_clientSocket, +m_inBuf, boost::asio::transfer_exactly(6 - m_inBuf.size()), - boost::bind(&ProxySessionAuth::recv_connection_request, - shared_from_this(), boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - return; - } - if (m_inBuf[0] != 0x05 || m_inBuf[1] > 0x03 || m_inBuf[2] != 0x00) return; @@ -142,12 +146,11 @@ void ProxySessionAuth::process_connection_request() { expected_size += std::size_t(6) + address_size; if (m_inBuf.size() < expected_size) { - boost::asio::async_read( - m_clientSocket, +m_inBuf, - boost::asio::transfer_exactly(expected_size - m_inBuf.size()), - boost::bind(&ProxySessionAuth::recv_connection_request, - shared_from_this(), boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + async_read( + [self = shared_from_this(), expected_size](std::size_t length) { + self->recv_connection_request(length); + }, + expected_size - m_inBuf.size()); return; } @@ -232,8 +235,8 @@ void ProxySessionAuth::connect_to_destination(std::uint8_t proxy_cmd) { case 0x01: // TCP client connection { m_destinationSocket.async_connect( - m_endpoint, - [this, self = shared_from_this(), proxy_cmd](const boost::system::error_code &ec) { + m_endpoint, [this, self = shared_from_this(), + proxy_cmd](const boost::system::error_code &ec) { if (ec) { send_server_response(proxy_cmd, 0x04); return; @@ -322,11 +325,9 @@ void ProxySessionTcp::start() { recv_from_both(); } void ProxySessionTcp::recv_from_both() { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__)); - m_clientSocket.async_read_some( - +m_inBuf, - boost::bind(&ProxySessionTcp::recv_from_client, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + async_read([self = shared_from_this()](std::size_t length) { + self->recv_from_client(length); + }); m_destinationSocket.async_read_some( +m_outBuf, boost::bind(&ProxySessionTcp::recv_from_destination, shared_from_this(), @@ -351,15 +352,10 @@ void ProxySessionTcp::recv_from_destination(const boost::system::error_code &ec, boost::asio::placeholders::bytes_transferred)); } -void ProxySessionTcp::recv_from_client(const boost::system::error_code &ec, +void ProxySessionTcp::recv_from_client( std::size_t length) { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__)); - if (ec || length == 0) { - m_destinationSocket.cancel(); - return; - } - m_inBuf += length; boost::asio::async_write( m_destinationSocket, -m_inBuf, boost::asio::transfer_exactly(length), @@ -395,11 +391,9 @@ void ProxySessionTcp::handle_destination_write( } m_inBuf -= length; - m_clientSocket.async_read_some( - +m_inBuf, - boost::bind(&ProxySessionTcp::recv_from_client, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + async_read([self = shared_from_this()](std::size_t length) { + self->recv_from_client(length); + }); } ProxyServer::ProxyServer(io_context &ioc, const tcp::endpoint &local_endpoint) @@ -11,63 +11,29 @@ #include <memory> #include <string_view> -namespace SOCKS5 { -class StreamBuffer : public boost::noncopyable { -public: - explicit StreamBuffer(std::size_t size) - : m_bufferUsed{0}, m_bufferSize{size} { - m_buffer = new std::uint8_t[size]; - } - StreamBuffer(StreamBuffer &&moveable) { - m_bufferUsed = moveable.m_bufferUsed; - m_bufferSize = moveable.m_bufferSize; - m_buffer = moveable.m_buffer; - moveable.m_buffer = nullptr; - } - ~StreamBuffer() { delete[] m_buffer; } - void operator+=(std::size_t commit_size) { m_bufferUsed += commit_size; } - void operator+=(const std::initializer_list<uint8_t> &to_add) { - std::copy(to_add.begin(), to_add.end(), &m_buffer[m_bufferUsed]); - m_bufferUsed += to_add.size(); - } - void operator-=(std::size_t consume_size) { m_bufferUsed -= consume_size; } - auto operator+() { - return boost::asio::buffer(&m_buffer[m_bufferUsed], - m_bufferSize - m_bufferUsed); - } - auto operator-() { return boost::asio::buffer(&m_buffer[0], m_bufferUsed); } - auto operator[](std::size_t index) const { return m_buffer[index]; } - const auto *operator()(std::size_t index = 0) const { - return &m_buffer[index]; - } - auto size() const { return m_bufferUsed; } - auto getHealth() const { - return (static_cast<float>(m_bufferUsed) / - static_cast<float>(m_bufferSize)); - } - -private: - std::size_t m_bufferUsed; - std::size_t m_bufferSize; - std::uint8_t *m_buffer; -}; +#include "fastbuffer.hpp" -class ProxySessionBase : public boost::noncopyable { +namespace SOCKS5 { +class ProxySessionBase : private boost::noncopyable { public: + using CompletionHandler = std::function<void(std::size_t length)>; ProxySessionBase(std::uint32_t session_id, boost::asio::ip::tcp::socket &&client_socket, std::size_t buffer_size = BUFSIZ); ProxySessionBase(std::uint32_t session_id, boost::asio::ip::tcp::socket &&client_socket, - StreamBuffer &&input_buffer, StreamBuffer &&output_buffer); + ContiguousStreamBuffer &&input_buffer, ContiguousStreamBuffer &&output_buffer); + void async_read(const CompletionHandler &handler, + std::size_t expected_length = 0); +protected: std::uint32_t m_sessionId; - StreamBuffer m_inBuf; - StreamBuffer m_outBuf; + ContiguousStreamBuffer m_inBuf; + ContiguousStreamBuffer m_outBuf; boost::asio::ip::tcp::socket m_clientSocket; }; -class ProxySessionAuth : public ProxySessionBase, +class ProxySessionAuth : private ProxySessionBase, public std::enable_shared_from_this<ProxySessionAuth> { public: ProxySessionAuth(std::uint32_t session_id, @@ -75,11 +41,9 @@ public: void start(); private: - void recv_client_greeting(const boost::system::error_code &ec, - std::size_t length); + void recv_client_greeting(std::size_t length); void send_server_greeting(bool auth_supported); - void recv_connection_request(const boost::system::error_code &ec, - std::size_t length); + void recv_connection_request(std::size_t length); void process_connection_request(); void send_server_response(std::uint8_t proxy_cmd, std::uint8_t status_code); void resolve_destination_host(std::uint8_t proxy_cmd, @@ -96,7 +60,7 @@ private: boost::asio::ip::tcp::socket m_destinationSocket; }; -class ProxySessionTcp : public ProxySessionBase, +class ProxySessionTcp : private ProxySessionBase, public std::enable_shared_from_this<ProxySessionTcp> { public: explicit ProxySessionTcp(std::uint32_t session_id, @@ -109,8 +73,7 @@ private: void recv_from_both(); void recv_from_destination(const boost::system::error_code &ec, std::size_t length); - void recv_from_client(const boost::system::error_code &ec, - std::size_t length); + void recv_from_client(std::size_t length); void handle_client_write(const boost::system::error_code &ec, std::size_t length); void handle_destination_write(const boost::system::error_code &ec, @@ -119,7 +82,7 @@ private: boost::asio::ip::tcp::socket m_destinationSocket; }; -class ProxyServer : public boost::noncopyable { +class ProxyServer : private boost::noncopyable { public: ProxyServer(boost::asio::io_context &ioc, const boost::asio::ip::tcp::endpoint &local_endpoint); |