aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorLee Clagett <code@leeclagett.com>2019-01-23 21:37:43 +0000
committerLee Clagett <code@leeclagett.com>2019-03-25 01:35:13 +0000
commit7acfa9f3cc7b52c0f4776dde3c3f80674cc3306f (patch)
tree5d1903ab4b132c137b1bb838037f024d6fb8b0d3 /src/net
parentMerge pull request #5286 (diff)
downloadmonero-7acfa9f3cc7b52c0f4776dde3c3f80674cc3306f.tar.xz
Added socks proxy (tor/i2pd/kovri) support to wallet
Diffstat (limited to 'src/net')
-rw-r--r--src/net/CMakeLists.txt4
-rw-r--r--src/net/socks.cpp28
-rw-r--r--src/net/socks.h16
-rw-r--r--src/net/socks_connect.cpp90
-rw-r--r--src/net/socks_connect.h55
5 files changed, 184 insertions, 9 deletions
diff --git a/src/net/CMakeLists.txt b/src/net/CMakeLists.txt
index 8a3ee9e6f..738f858f0 100644
--- a/src/net/CMakeLists.txt
+++ b/src/net/CMakeLists.txt
@@ -26,8 +26,8 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-set(net_sources error.cpp parse.cpp socks.cpp tor_address.cpp i2p_address.cpp)
-set(net_headers error.h parse.h socks.h tor_address.h i2p_address.h)
+set(net_sources error.cpp i2p_address.cpp parse.cpp socks.cpp socks_connect.cpp tor_address.cpp)
+set(net_headers error.h i2p_address.h parse.h socks.h socks_connect.h tor_address.h)
monero_add_library(net ${net_sources} ${net_headers})
target_link_libraries(net common epee ${Boost_ASIO_LIBRARY})
diff --git a/src/net/socks.cpp b/src/net/socks.cpp
index 53154369b..9b81c6c2e 100644
--- a/src/net/socks.cpp
+++ b/src/net/socks.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, The Monero Project
+// Copyright (c) 2018-2019, The Monero Project
//
// All rights reserved.
//
@@ -193,7 +193,7 @@ namespace socks
else if (bytes < self.buffer().size())
self.done(socks::error::bad_write, std::move(self_));
else
- boost::asio::async_read(self.proxy_, get_buffer(self), completed{std::move(self_)});
+ boost::asio::async_read(self.proxy_, get_buffer(self), self.strand_.wrap(completed{std::move(self_)}));
}
}
};
@@ -215,13 +215,13 @@ namespace socks
if (error)
self.done(error, std::move(self_));
else
- boost::asio::async_write(self.proxy_, get_buffer(self), read{std::move(self_)});
+ boost::asio::async_write(self.proxy_, get_buffer(self), self.strand_.wrap(read{std::move(self_)}));
}
}
};
client::client(stream_type::socket&& proxy, socks::version ver)
- : proxy_(std::move(proxy)), buffer_size_(0), buffer_(), ver_(ver)
+ : proxy_(std::move(proxy)), strand_(proxy_.get_io_service()), buffer_size_(0), buffer_(), ver_(ver)
{}
client::~client() {}
@@ -296,7 +296,7 @@ namespace socks
if (self && !self->buffer().empty())
{
client& alias = *self;
- alias.proxy_.async_connect(proxy_address, write{std::move(self)});
+ alias.proxy_.async_connect(proxy_address, alias.strand_.wrap(write{std::move(self)}));
return true;
}
return false;
@@ -307,10 +307,26 @@ namespace socks
if (self && !self->buffer().empty())
{
client& alias = *self;
- boost::asio::async_write(alias.proxy_, write::get_buffer(alias), read{std::move(self)});
+ boost::asio::async_write(alias.proxy_, write::get_buffer(alias), alias.strand_.wrap(read{std::move(self)}));
return true;
}
return false;
}
+
+ void client::async_close::operator()(boost::system::error_code error)
+ {
+ if (self_ && error != boost::system::errc::operation_canceled)
+ {
+ const std::shared_ptr<client> self = std::move(self_);
+ self->strand_.dispatch([self] ()
+ {
+ if (self && self->proxy_.is_open())
+ {
+ self->proxy_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ self->proxy_.close();
+ }
+ });
+ }
+ }
} // socks
} // net
diff --git a/src/net/socks.h b/src/net/socks.h
index 825937792..4d1d34e9e 100644
--- a/src/net/socks.h
+++ b/src/net/socks.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, The Monero Project
+// Copyright (c) 2018-2019, The Monero Project
//
// All rights reserved.
//
@@ -31,6 +31,7 @@
#include <cstdint>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/io_service.hpp>
+#include <boost/asio/strand.hpp>
#include <boost/system/error_code.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/utility/string_ref.hpp>
@@ -92,6 +93,7 @@ namespace socks
class client
{
boost::asio::ip::tcp::socket proxy_;
+ boost::asio::io_service::strand strand_;
std::uint16_t buffer_size_;
std::uint8_t buffer_[1024];
socks::version ver_;
@@ -168,6 +170,8 @@ namespace socks
\note Must use one of the `self->set_*_command` calls before using
this function.
+ \note Only `async_close` can be invoked on `self` until the `done`
+ callback is invoked.
\param self ownership of object is given to function.
\param proxy_address of the socks server.
@@ -182,11 +186,21 @@ namespace socks
\note Must use one of the `self->set_*_command` calls before using
the function.
+ \note Only `async_close` can be invoked on `self` until the `done`
+ callback is invoked.
\param self ownership of object is given to function.
\return False if `self->buffer().empty()` (no command set).
*/
static bool send(std::shared_ptr<client> self);
+
+ /*! Callback for closing socket. Thread-safe with `*send` functions;
+ never blocks (uses strands). */
+ struct async_close
+ {
+ std::shared_ptr<client> self_;
+ void operator()(boost::system::error_code error = boost::system::error_code{});
+ };
};
template<typename Handler>
diff --git a/src/net/socks_connect.cpp b/src/net/socks_connect.cpp
new file mode 100644
index 000000000..a5557f6f8
--- /dev/null
+++ b/src/net/socks_connect.cpp
@@ -0,0 +1,90 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "socks_connect.h"
+
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <cstdint>
+#include <memory>
+#include <system_error>
+
+#include "net/error.h"
+#include "net/net_utils_base.h"
+#include "net/socks.h"
+#include "string_tools.h"
+
+namespace net
+{
+namespace socks
+{
+ boost::unique_future<boost::asio::ip::tcp::socket>
+ connector::operator()(const std::string& remote_host, const std::string& remote_port, boost::asio::steady_timer& timeout) const
+ {
+ struct future_socket
+ {
+ boost::promise<boost::asio::ip::tcp::socket> result_;
+
+ void operator()(boost::system::error_code error, boost::asio::ip::tcp::socket&& socket)
+ {
+ if (error)
+ result_.set_exception(boost::system::system_error{error});
+ else
+ result_.set_value(std::move(socket));
+ }
+ };
+
+ boost::unique_future<boost::asio::ip::tcp::socket> out{};
+ {
+ std::uint16_t port = 0;
+ if (!epee::string_tools::get_xtype_from_string(port, remote_port))
+ throw std::system_error{net::error::invalid_port, "Remote port for socks proxy"};
+
+ bool is_set = false;
+ std::uint32_t ip_address = 0;
+ boost::promise<boost::asio::ip::tcp::socket> result{};
+ out = result.get_future();
+ const auto proxy = net::socks::make_connect_client(
+ boost::asio::ip::tcp::socket{GET_IO_SERVICE(timeout)}, net::socks::version::v4a, future_socket{std::move(result)}
+ );
+
+ if (epee::string_tools::get_ip_int32_from_string(ip_address, remote_host))
+ is_set = proxy->set_connect_command(epee::net_utils::ipv4_network_address{ip_address, port});
+ else
+ is_set = proxy->set_connect_command(remote_host, port);
+
+ if (!is_set || !net::socks::client::connect_and_send(proxy, proxy_address))
+ throw std::system_error{net::error::invalid_host, "Address for socks proxy"};
+
+ timeout.async_wait(net::socks::client::async_close{std::move(proxy)});
+ }
+
+ return out;
+ }
+} // socks
+} // net
diff --git a/src/net/socks_connect.h b/src/net/socks_connect.h
new file mode 100644
index 000000000..44b0fa2b3
--- /dev/null
+++ b/src/net/socks_connect.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <boost/thread/future.hpp>
+#include <string>
+
+namespace net
+{
+namespace socks
+{
+ //! Primarily for use with `epee::net_utils::http_client`.
+ struct connector
+ {
+ boost::asio::ip::tcp::endpoint proxy_address;
+
+ /*! Creates a new socket, asynchronously connects to `proxy_address`,
+ and requests a connection to `remote_host` on `remote_port`. Sets
+ socket as closed if `timeout` is reached.
+
+ \return The socket if successful, and exception in the future with
+ error otherwise. */
+ boost::unique_future<boost::asio::ip::tcp::socket>
+ operator()(const std::string& remote_host, const std::string& remote_port, boost::asio::steady_timer& timeout) const;
+ };
+} // socks
+} // net