mirror of
https://github.com/monero-project/monero.git
synced 2024-10-01 11:49:47 -04:00
Add IPv6 support
new cli options (RPC ones also apply to wallet): --p2p-bind-ipv6-address (default = "::") --p2p-bind-port-ipv6 (default same as ipv4 port for given nettype) --rpc-bind-ipv6-address (default = "::1") --p2p-use-ipv6 (default false) --rpc-use-ipv6 (default false) --p2p-require-ipv4 (default true, if ipv4 bind fails and this is true, will not continue even if ipv6 bind successful) --rpc-require-ipv4 (default true, description as above) ipv6 addresses are to be specified as "[xx:xx:xx::xx:xx]:port" except in the cases of the cli args for bind address. For those the square braces can be omitted.
This commit is contained in:
parent
8adde33e01
commit
155475d971
@ -227,8 +227,12 @@ namespace net_utils
|
||||
std::map<std::string, t_connection_type> server_type_map;
|
||||
void create_server_type_map();
|
||||
|
||||
bool init_server(uint32_t port, const std::string address = "0.0.0.0", ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
bool init_server(const std::string port, const std::string& address = "0.0.0.0", ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
bool init_server(uint32_t port, const std::string& address = "0.0.0.0",
|
||||
uint32_t port_ipv6 = 0, const std::string& address_ipv6 = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
bool init_server(const std::string port, const std::string& address = "0.0.0.0",
|
||||
const std::string port_ipv6 = "", const std::string address_ipv6 = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
|
||||
@ -269,6 +273,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
int get_binded_port(){return m_port;}
|
||||
int get_binded_port_ipv6(){return m_port_ipv6;}
|
||||
|
||||
long get_connections_count() const
|
||||
{
|
||||
@ -339,7 +344,9 @@ namespace net_utils
|
||||
/// Run the server's io_service loop.
|
||||
bool worker_thread();
|
||||
/// Handle completion of an asynchronous accept operation.
|
||||
void handle_accept(const boost::system::error_code& e);
|
||||
void handle_accept_ipv4(const boost::system::error_code& e);
|
||||
void handle_accept_ipv6(const boost::system::error_code& e);
|
||||
void handle_accept(const boost::system::error_code& e, bool ipv6 = false);
|
||||
|
||||
bool is_thread_worker();
|
||||
|
||||
@ -360,11 +367,16 @@ namespace net_utils
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_ipv6;
|
||||
epee::net_utils::network_address default_remote;
|
||||
|
||||
std::atomic<bool> m_stop_signal_sent;
|
||||
uint32_t m_port;
|
||||
uint32_t m_port_ipv6;
|
||||
std::string m_address;
|
||||
std::string m_address_ipv6;
|
||||
bool m_use_ipv6;
|
||||
bool m_require_ipv4;
|
||||
std::string m_thread_name_prefix; //TODO: change to enum server_type, now used
|
||||
size_t m_threads_count;
|
||||
std::vector<boost::shared_ptr<boost::thread> > m_threads;
|
||||
@ -376,6 +388,8 @@ namespace net_utils
|
||||
|
||||
/// The next connection to be accepted
|
||||
connection_ptr new_connection_;
|
||||
connection_ptr new_connection_ipv6;
|
||||
|
||||
|
||||
boost::mutex connections_mutex;
|
||||
std::set<connection_ptr> connections_;
|
||||
|
@ -145,10 +145,18 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
boost::system::error_code ec;
|
||||
auto remote_ep = socket().remote_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
|
||||
CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here");
|
||||
CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4() || remote_ep.address().is_v6(), false, "only IPv4 and IPv6 supported here");
|
||||
|
||||
const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
|
||||
return start(is_income, is_multithreaded, ipv4_network_address{uint32_t(ip_), remote_ep.port()});
|
||||
if (remote_ep.address().is_v4())
|
||||
{
|
||||
const unsigned long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong());
|
||||
return start(is_income, is_multithreaded, ipv4_network_address{uint32_t(ip_), remote_ep.port()});
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto ip_{remote_ep.address().to_v6()};
|
||||
return start(is_income, is_multithreaded, ipv6_network_address{ip_, remote_ep.port()});
|
||||
}
|
||||
CATCH_ENTRY_L0("connection<t_protocol_handler>::start()", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -904,12 +912,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_io_service_local_instance(new worker()),
|
||||
io_service_(m_io_service_local_instance->io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
m_thread_index(0),
|
||||
m_connection_type( connection_type ),
|
||||
new_connection_()
|
||||
new_connection_(),
|
||||
new_connection_ipv6()
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
@ -920,12 +930,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
m_state(boost::make_shared<typename connection<t_protocol_handler>::shared_state>()),
|
||||
io_service_(extarnal_io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
m_thread_index(0),
|
||||
m_connection_type(connection_type),
|
||||
new_connection_()
|
||||
new_connection_(),
|
||||
new_connection_ipv6()
|
||||
{
|
||||
create_server_type_map();
|
||||
m_thread_name_prefix = "NET";
|
||||
@ -947,29 +959,92 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, ssl_options_t ssl_options)
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string& address,
|
||||
uint32_t port_ipv6, const std::string& address_ipv6, bool use_ipv6, bool require_ipv4,
|
||||
ssl_options_t ssl_options)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
m_stop_signal_sent = false;
|
||||
m_port = port;
|
||||
m_port_ipv6 = port_ipv6;
|
||||
m_address = address;
|
||||
m_address_ipv6 = address_ipv6;
|
||||
m_use_ipv6 = use_ipv6;
|
||||
m_require_ipv4 = require_ipv4;
|
||||
|
||||
if (ssl_options)
|
||||
m_state->configure_ssl(std::move(ssl_options));
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor_.bind(endpoint);
|
||||
acceptor_.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
MDEBUG("start accept");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
|
||||
std::string ipv4_failed = "";
|
||||
std::string ipv6_failed = "";
|
||||
try
|
||||
{
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor_.bind(endpoint);
|
||||
acceptor_.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv4)");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ipv4_failed = e.what();
|
||||
}
|
||||
|
||||
if (ipv4_failed != "")
|
||||
{
|
||||
MERROR("Failed to bind IPv4: " << ipv4_failed);
|
||||
if (require_ipv4)
|
||||
{
|
||||
throw std::runtime_error("Failed to bind IPv4 (set to required)");
|
||||
}
|
||||
}
|
||||
|
||||
if (use_ipv6)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (port_ipv6 == 0) port_ipv6 = port; // default arg means bind to same port as ipv4
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_ipv6.open(endpoint.protocol());
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
|
||||
acceptor_ipv6.bind(endpoint);
|
||||
acceptor_ipv6.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_ipv6.local_endpoint();
|
||||
m_port_ipv6 = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv6)");
|
||||
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_ipv6.async_accept(new_connection_ipv6->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
ipv6_failed = e.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (use_ipv6 && ipv6_failed != "")
|
||||
{
|
||||
MERROR("Failed to bind IPv6: " << ipv6_failed);
|
||||
if (ipv4_failed != "")
|
||||
{
|
||||
throw std::runtime_error("Failed to bind IPv4 and IPv6");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -988,15 +1063,23 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, ssl_options_t ssl_options)
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address,
|
||||
const std::string port_ipv6, const std::string address_ipv6, bool use_ipv6, bool require_ipv4,
|
||||
ssl_options_t ssl_options)
|
||||
{
|
||||
uint32_t p = 0;
|
||||
uint32_t p_ipv6 = 0;
|
||||
|
||||
if (port.size() && !string_tools::get_xtype_from_string(p, port)) {
|
||||
MERROR("Failed to convert port no = " << port);
|
||||
return false;
|
||||
}
|
||||
return this->init_server(p, address, std::move(ssl_options));
|
||||
|
||||
if (port_ipv6.size() && !string_tools::get_xtype_from_string(p_ipv6, port_ipv6)) {
|
||||
MERROR("Failed to convert port no = " << port_ipv6);
|
||||
return false;
|
||||
}
|
||||
return this->init_server(p, address, p_ipv6, address_ipv6, use_ipv6, require_ipv4, std::move(ssl_options));
|
||||
}
|
||||
POP_WARNINGS
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -1088,7 +1171,7 @@ POP_WARNINGS
|
||||
{
|
||||
//some problems with the listening socket ?..
|
||||
_dbg1("Net service stopped without stop request, restarting...");
|
||||
if(!this->init_server(m_port, m_address))
|
||||
if(!this->init_server(m_port, m_address, m_port_ipv6, m_address_ipv6, m_use_ipv6, m_require_ipv4))
|
||||
{
|
||||
_dbg1("Reiniting service failed, exit.");
|
||||
return false;
|
||||
@ -1154,29 +1237,52 @@ POP_WARNINGS
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e)
|
||||
void boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4(const boost::system::error_code& e)
|
||||
{
|
||||
this->handle_accept(e, false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6(const boost::system::error_code& e)
|
||||
{
|
||||
this->handle_accept(e, true);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e, bool ipv6)
|
||||
{
|
||||
MDEBUG("handle_accept");
|
||||
|
||||
boost::asio::ip::tcp::acceptor* current_acceptor = &acceptor_;
|
||||
connection_ptr* current_new_connection = &new_connection_;
|
||||
auto accept_function_pointer = &boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4;
|
||||
if (ipv6)
|
||||
{
|
||||
current_acceptor = &acceptor_ipv6;
|
||||
current_new_connection = &new_connection_ipv6;
|
||||
accept_function_pointer = &boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
if (m_connection_type == e_connection_type_RPC) {
|
||||
const char *ssl_message = "unknown";
|
||||
switch (new_connection_->get_ssl_support())
|
||||
{
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break;
|
||||
}
|
||||
MDEBUG("New server for RPC connections, SSL " << ssl_message);
|
||||
new_connection_->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move(new_connection_));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
if (m_connection_type == e_connection_type_RPC) {
|
||||
const char *ssl_message = "unknown";
|
||||
switch ((*current_new_connection)->get_ssl_support())
|
||||
{
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break;
|
||||
case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break;
|
||||
}
|
||||
MDEBUG("New server for RPC connections, SSL " << ssl_message);
|
||||
(*current_new_connection)->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move((*current_new_connection)));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
|
||||
boost::asio::socket_base::keep_alive opt(true);
|
||||
conn->socket().set_option(opt);
|
||||
@ -1208,10 +1314,10 @@ POP_WARNINGS
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
|
||||
misc_utils::sleep_no_w(100);
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support()));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
|
||||
boost::asio::placeholders::error));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
@ -1345,23 +1451,84 @@ POP_WARNINGS
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
if (!m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
|
||||
resolve_error != boost::asio::error::host_not_found_try_again))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
try_ipv6 = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
std::string bind_ip_to_use;
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
if (!m_use_ipv6)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try_ipv6 = true;
|
||||
MINFO("Resolving address as IPv4 failed, trying IPv6");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_ip_to_use = bind_ip;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bind_ip == "0.0.0.0")
|
||||
{
|
||||
bind_ip_to_use = "::";
|
||||
}
|
||||
else
|
||||
{
|
||||
bind_ip_to_use = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LOG_ERROR("Trying connect to " << adr << ":" << port << ", bind_ip = " << bind_ip_to_use);
|
||||
|
||||
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
|
||||
auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, ssl_support);
|
||||
auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_support);
|
||||
if (try_connect_result == CONNECT_FAILURE)
|
||||
return false;
|
||||
if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
|
||||
@ -1369,7 +1536,7 @@ POP_WARNINGS
|
||||
// we connected, but could not connect with SSL, try without
|
||||
MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
|
||||
new_connection_l->disable_ssl();
|
||||
try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
if (try_connect_result != CONNECT_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
@ -1409,17 +1576,59 @@ POP_WARNINGS
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
|
||||
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
if (!m_use_ipv6 || (resolve_error != boost::asio::error::host_not_found &&
|
||||
resolve_error != boost::asio::error::host_not_found_try_again))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
try_ipv6 = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
if (!try_ipv6)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MINFO("Resolving address as IPv4 failed, trying IPv6");
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
|
@ -57,6 +57,7 @@ namespace epee
|
||||
{}
|
||||
|
||||
bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
|
||||
const std::string& bind_ipv6_address = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
std::vector<std::string> access_control_origins = std::vector<std::string>(),
|
||||
boost::optional<net_utils::http::login> user = boost::none,
|
||||
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
@ -75,8 +76,12 @@ namespace epee
|
||||
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
|
||||
MGINFO("Binding on " << bind_ip << ":" << bind_port);
|
||||
bool res = m_net_server.init_server(bind_port, bind_ip, std::move(ssl_options));
|
||||
MGINFO("Binding on " << bind_ip << " (IPv4):" << bind_port);
|
||||
if (use_ipv6)
|
||||
{
|
||||
MGINFO("Binding on " << bind_ipv6_address << " (IPv6):" << bind_port);
|
||||
}
|
||||
bool res = m_net_server.init_server(bind_port, bind_ip, bind_port, bind_ipv6_address, use_ipv6, require_ipv4, std::move(ssl_options));
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to bind server");
|
||||
|
@ -27,10 +27,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
inline
|
||||
bool is_ipv6_local(const std::string& ip)
|
||||
{
|
||||
auto addr = boost::asio::ip::make_address_v6(ip);
|
||||
|
||||
// ipv6 link-local unicast addresses are fe80::/10
|
||||
bool is_link_local = addr.is_link_local();
|
||||
|
||||
auto addr_bytes = addr.to_bytes();
|
||||
|
||||
// ipv6 unique local unicast addresses start with fc00::/7 -- (fcXX or fdXX)
|
||||
bool is_unique_local_unicast = (addr_bytes[0] == 0xfc || addr_bytes[0] == 0xfd);
|
||||
|
||||
return is_link_local || is_unique_local_unicast;
|
||||
}
|
||||
|
||||
inline
|
||||
bool is_ipv6_loopback(const std::string& ip)
|
||||
{
|
||||
// ipv6 loopback is ::1
|
||||
return boost::asio::ip::address_v6::from_string(ip).is_loopback();
|
||||
}
|
||||
|
||||
inline
|
||||
bool is_ip_local(uint32_t ip)
|
||||
{
|
||||
|
@ -128,11 +128,51 @@ namespace net_utils
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool parse_url_ipv6(const std::string url_str, http::url_content& content)
|
||||
{
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(\\[(.*)\\](:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal);
|
||||
// 12 3 4 5 6 7
|
||||
|
||||
content.port = 0;
|
||||
boost::smatch result;
|
||||
if(!(boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched))
|
||||
{
|
||||
LOG_PRINT_L1("[PARSE URI] regex not matched for uri: " << rexp_match_uri);
|
||||
//content.m_path = uri;
|
||||
return false;
|
||||
}
|
||||
if(result[2].matched)
|
||||
{
|
||||
content.schema = result[2];
|
||||
}
|
||||
if(result[4].matched)
|
||||
{
|
||||
content.host = result[4];
|
||||
}
|
||||
else // if host not matched, matching should be considered failed
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result[6].matched)
|
||||
{
|
||||
content.port = boost::lexical_cast<uint64_t>(result[6]);
|
||||
}
|
||||
if(result[7].matched)
|
||||
{
|
||||
content.uri = result[7];
|
||||
return parse_uri(result[7], content.m_uri_content);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool parse_url(const std::string url_str, http::url_content& content)
|
||||
{
|
||||
|
||||
if (parse_url_ipv6(url_str, content)) return true;
|
||||
|
||||
///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
|
||||
//STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal);
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal);
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include "enums.h"
|
||||
@ -154,6 +155,59 @@ namespace net_utils
|
||||
inline bool operator>=(const ipv4_network_subnet& lhs, const ipv4_network_subnet& rhs) noexcept
|
||||
{ return !lhs.less(rhs); }
|
||||
|
||||
class ipv6_network_address
|
||||
{
|
||||
protected:
|
||||
boost::asio::ip::address_v6 m_address;
|
||||
uint16_t m_port;
|
||||
|
||||
public:
|
||||
ipv6_network_address()
|
||||
: ipv6_network_address(boost::asio::ip::address_v6::loopback(), 0)
|
||||
{}
|
||||
|
||||
ipv6_network_address(const boost::asio::ip::address_v6& ip, uint16_t port)
|
||||
: m_address(ip), m_port(port)
|
||||
{
|
||||
}
|
||||
|
||||
bool equal(const ipv6_network_address& other) const noexcept;
|
||||
bool less(const ipv6_network_address& other) const noexcept;
|
||||
bool is_same_host(const ipv6_network_address& other) const noexcept
|
||||
{ return m_address == other.m_address; }
|
||||
|
||||
boost::asio::ip::address_v6 ip() const noexcept { return m_address; }
|
||||
uint16_t port() const noexcept { return m_port; }
|
||||
std::string str() const;
|
||||
std::string host_str() const;
|
||||
bool is_loopback() const;
|
||||
bool is_local() const;
|
||||
static constexpr address_type get_type_id() noexcept { return address_type::ipv6; }
|
||||
static constexpr zone get_zone() noexcept { return zone::public_; }
|
||||
static constexpr bool is_blockable() noexcept { return true; }
|
||||
|
||||
static const uint8_t ID = 2;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
boost::asio::ip::address_v6::bytes_type bytes = this_ref.m_address.to_bytes();
|
||||
epee::serialization::selector<is_store>::serialize_t_val_as_blob(bytes, stg, hparent_section, "addr");
|
||||
const_cast<boost::asio::ip::address_v6&>(this_ref.m_address) = boost::asio::ip::address_v6(bytes);
|
||||
KV_SERIALIZE(m_port)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
inline bool operator==(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return lhs.equal(rhs); }
|
||||
inline bool operator!=(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return !lhs.equal(rhs); }
|
||||
inline bool operator<(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return lhs.less(rhs); }
|
||||
inline bool operator<=(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return !rhs.less(lhs); }
|
||||
inline bool operator>(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return rhs.less(lhs); }
|
||||
inline bool operator>=(const ipv6_network_address& lhs, const ipv6_network_address& rhs) noexcept
|
||||
{ return !lhs.less(rhs); }
|
||||
|
||||
class network_address
|
||||
{
|
||||
struct interface
|
||||
@ -261,6 +315,8 @@ namespace net_utils
|
||||
{
|
||||
case address_type::ipv4:
|
||||
return this_ref.template serialize_addr<ipv4_network_address>(is_store_, stg, hparent_section);
|
||||
case address_type::ipv6:
|
||||
return this_ref.template serialize_addr<ipv6_network_address>(is_store_, stg, hparent_section);
|
||||
case address_type::tor:
|
||||
return this_ref.template serialize_addr<net::tor_address>(is_store_, stg, hparent_section);
|
||||
case address_type::i2p:
|
||||
|
@ -11,10 +11,39 @@ namespace net_utils
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(GET_IO_SERVICE(timeout));
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
|
||||
|
||||
bool try_ipv6 = false;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end) // Documentation states that successful call is guaranteed to be non-empty
|
||||
throw boost::system::system_error{boost::asio::error::fault, "Failed to resolve " + addr};
|
||||
boost::system::error_code resolve_error;
|
||||
try
|
||||
{
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
if(iterator == end) // Documentation states that successful call is guaranteed to be non-empty
|
||||
{
|
||||
// if IPv4 resolution fails, try IPv6. Unintentional outgoing IPv6 connections should only
|
||||
// be possible if for some reason a hostname was given and that hostname fails IPv4 resolution,
|
||||
// so at least for now there should not be a need for a flag "using ipv6 is ok"
|
||||
try_ipv6 = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
if (resolve_error != boost::asio::error::host_not_found &&
|
||||
resolve_error != boost::asio::error::host_not_found_try_again)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
try_ipv6 = true;
|
||||
}
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
iterator = resolver.resolve(query6);
|
||||
if (iterator == end)
|
||||
throw boost::system::system_error{boost::asio::error::fault, "Failed to resolve " + addr};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -21,6 +21,19 @@ namespace epee { namespace net_utils
|
||||
bool ipv4_network_address::is_loopback() const { return net_utils::is_ip_loopback(ip()); }
|
||||
bool ipv4_network_address::is_local() const { return net_utils::is_ip_local(ip()); }
|
||||
|
||||
bool ipv6_network_address::equal(const ipv6_network_address& other) const noexcept
|
||||
{ return is_same_host(other) && port() == other.port(); }
|
||||
|
||||
bool ipv6_network_address::less(const ipv6_network_address& other) const noexcept
|
||||
{ return is_same_host(other) ? port() < other.port() : m_address < other.m_address; }
|
||||
|
||||
std::string ipv6_network_address::str() const
|
||||
{ return std::string("[") + host_str() + "]:" + std::to_string(port()); }
|
||||
|
||||
std::string ipv6_network_address::host_str() const { return m_address.to_string(); }
|
||||
bool ipv6_network_address::is_loopback() const { return m_address.is_loopback(); }
|
||||
bool ipv6_network_address::is_local() const { return m_address.is_link_local(); }
|
||||
|
||||
|
||||
bool ipv4_network_subnet::equal(const ipv4_network_subnet& other) const noexcept
|
||||
{ return is_same_host(other) && m_mask == other.m_mask; }
|
||||
|
@ -68,7 +68,7 @@ namespace {
|
||||
std::string id_str;
|
||||
std::string port_str;
|
||||
std::string elapsed = peer.last_seen == 0 ? "never" : epee::misc_utils::get_time_interval_string(now - last_seen);
|
||||
std::string ip_str = epee::string_tools::get_ip_string_from_int32(peer.ip);
|
||||
std::string ip_str = peer.ip != 0 ? epee::string_tools::get_ip_string_from_int32(peer.ip) : std::string("[") + peer.host + "]";
|
||||
std::stringstream peer_id_str;
|
||||
peer_id_str << std::hex << std::setw(16) << peer.id;
|
||||
peer_id_str >> id_str;
|
||||
|
@ -34,28 +34,69 @@
|
||||
|
||||
namespace net
|
||||
{
|
||||
void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port)
|
||||
{
|
||||
// require ipv6 address format "[addr:addr:addr:...:addr]:port"
|
||||
if (address.find(']') != std::string::npos)
|
||||
{
|
||||
host = address.substr(1, address.rfind(']') - 1);
|
||||
if ((host.size() + 2) < address.size())
|
||||
{
|
||||
port = address.substr(address.rfind(':') + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
host = address.substr(0, address.rfind(':'));
|
||||
if (host.size() < address.size())
|
||||
{
|
||||
port = address.substr(host.size() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect<epee::net_utils::network_address>
|
||||
get_network_address(const boost::string_ref address, const std::uint16_t default_port)
|
||||
{
|
||||
const boost::string_ref host = address.substr(0, address.rfind(':'));
|
||||
std::string host_str = "";
|
||||
std::string port_str = "";
|
||||
|
||||
if (host.empty())
|
||||
bool ipv6 = false;
|
||||
|
||||
get_network_address_host_and_port(std::string(address), host_str, port_str);
|
||||
|
||||
boost::string_ref host_str_ref(host_str);
|
||||
boost::string_ref port_str_ref(port_str);
|
||||
|
||||
if (host_str.empty())
|
||||
return make_error_code(net::error::invalid_host);
|
||||
if (host.ends_with(".onion"))
|
||||
if (host_str_ref.ends_with(".onion"))
|
||||
return tor_address::make(address, default_port);
|
||||
if (host.ends_with(".i2p"))
|
||||
if (host_str_ref.ends_with(".i2p"))
|
||||
return i2p_address::make(address, default_port);
|
||||
|
||||
boost::system::error_code ec;
|
||||
boost::asio::ip::address_v6 v6 = boost::asio::ip::make_address_v6(host_str, ec);
|
||||
ipv6 = !ec;
|
||||
|
||||
std::uint16_t port = default_port;
|
||||
if (host.size() < address.size())
|
||||
if (port_str.size())
|
||||
{
|
||||
if (!epee::string_tools::get_xtype_from_string(port, std::string{address.substr(host.size() + 1)}))
|
||||
if (!epee::string_tools::get_xtype_from_string(port, port_str))
|
||||
return make_error_code(net::error::invalid_port);
|
||||
}
|
||||
|
||||
std::uint32_t ip = 0;
|
||||
if (epee::string_tools::get_ip_int32_from_string(ip, std::string{host}))
|
||||
return {epee::net_utils::ipv4_network_address{ip, port}};
|
||||
if (ipv6)
|
||||
{
|
||||
return {epee::net_utils::ipv6_network_address{v6, port}};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uint32_t ip = 0;
|
||||
if (epee::string_tools::get_ip_int32_from_string(ip, host_str))
|
||||
return {epee::net_utils::ipv4_network_address{ip, port}};
|
||||
}
|
||||
|
||||
return make_error_code(net::error::unsupported_address);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@
|
||||
|
||||
namespace net
|
||||
{
|
||||
void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port);
|
||||
|
||||
/*!
|
||||
Identifies onion, i2p and IPv4 addresses and returns them as a generic
|
||||
`network_address`. If the type is unsupported, it might be a hostname,
|
||||
|
@ -108,10 +108,11 @@ namespace
|
||||
|
||||
namespace nodetool
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
|
||||
const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol (IPv4)", "0.0.0.0"};
|
||||
const command_line::arg_descriptor<std::string> arg_p2p_bind_ipv6_address = {"p2p-bind-ipv6-address", "Interface for p2p network protocol (IPv6)", "::"};
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port = {
|
||||
"p2p-bind-port"
|
||||
, "Port for p2p network protocol"
|
||||
, "Port for p2p network protocol (IPv4)"
|
||||
, std::to_string(config::P2P_DEFAULT_PORT)
|
||||
, {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }}
|
||||
, [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
|
||||
@ -122,6 +123,20 @@ namespace nodetool
|
||||
return val;
|
||||
}
|
||||
};
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port_ipv6 = {
|
||||
"p2p-bind-port-ipv6"
|
||||
, "Port for p2p network protocol (IPv6)"
|
||||
, std::to_string(config::P2P_DEFAULT_PORT)
|
||||
, {{ &cryptonote::arg_testnet_on, &cryptonote::arg_stagenet_on }}
|
||||
, [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
|
||||
if (testnet_stagenet[0] && defaulted)
|
||||
return std::to_string(config::testnet::P2P_DEFAULT_PORT);
|
||||
else if (testnet_stagenet[1] && defaulted)
|
||||
return std::to_string(config::stagenet::P2P_DEFAULT_PORT);
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<uint32_t> arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"};
|
||||
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"};
|
||||
@ -136,6 +151,8 @@ namespace nodetool
|
||||
|
||||
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
|
||||
const command_line::arg_descriptor<std::string> arg_igd = {"igd", "UPnP port mapping (disabled, enabled, delayed)", "delayed"};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_use_ipv6 = {"p2p-use-ipv6", "Enable IPv6 for p2p", false};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_require_ipv4 = {"p2p-require-ipv4", "Require successful IPv4 bind for p2p", true};
|
||||
const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1};
|
||||
const command_line::arg_descriptor<int64_t> arg_in_peers = {"in-peers", "set max number of in peers", -1};
|
||||
const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1};
|
||||
|
@ -151,7 +151,9 @@ namespace nodetool
|
||||
: m_connect(nullptr),
|
||||
m_net_server(epee::net_utils::e_connection_type_P2P),
|
||||
m_bind_ip(),
|
||||
m_bind_ipv6_address(),
|
||||
m_port(),
|
||||
m_port_ipv6(),
|
||||
m_our_address(),
|
||||
m_peerlist(),
|
||||
m_config{},
|
||||
@ -167,7 +169,9 @@ namespace nodetool
|
||||
: m_connect(nullptr),
|
||||
m_net_server(public_service, epee::net_utils::e_connection_type_P2P),
|
||||
m_bind_ip(),
|
||||
m_bind_ipv6_address(),
|
||||
m_port(),
|
||||
m_port_ipv6(),
|
||||
m_our_address(),
|
||||
m_peerlist(),
|
||||
m_config{},
|
||||
@ -182,7 +186,9 @@ namespace nodetool
|
||||
connect_func* m_connect;
|
||||
net_server m_net_server;
|
||||
std::string m_bind_ip;
|
||||
std::string m_bind_ipv6_address;
|
||||
std::string m_port;
|
||||
std::string m_port_ipv6;
|
||||
epee::net_utils::network_address m_our_address; // in anonymity networks
|
||||
peerlist_manager m_peerlist;
|
||||
config m_config;
|
||||
@ -357,7 +363,13 @@ namespace nodetool
|
||||
bool is_peer_used(const peerlist_entry& peer);
|
||||
bool is_peer_used(const anchor_peerlist_entry& peer);
|
||||
bool is_addr_connected(const epee::net_utils::network_address& peer);
|
||||
void add_upnp_port_mapping(uint32_t port);
|
||||
void add_upnp_port_mapping_impl(uint32_t port, bool ipv6=false);
|
||||
void add_upnp_port_mapping_v4(uint32_t port);
|
||||
void add_upnp_port_mapping_v6(uint32_t port);
|
||||
void add_upnp_port_mapping(uint32_t port, bool ipv4=true, bool ipv6=false);
|
||||
void delete_upnp_port_mapping_impl(uint32_t port, bool ipv6=false);
|
||||
void delete_upnp_port_mapping_v4(uint32_t port);
|
||||
void delete_upnp_port_mapping_v6(uint32_t port);
|
||||
void delete_upnp_port_mapping(uint32_t port);
|
||||
template<class t_callback>
|
||||
bool try_ping(basic_node_data& node_data, p2p_connection_context& context, const t_callback &cb);
|
||||
@ -419,12 +431,15 @@ namespace nodetool
|
||||
bool m_have_address;
|
||||
bool m_first_connection_maker_call;
|
||||
uint32_t m_listening_port;
|
||||
uint32_t m_listening_port_ipv6;
|
||||
uint32_t m_external_port;
|
||||
uint16_t m_rpc_port;
|
||||
bool m_allow_local_ip;
|
||||
bool m_hide_my_port;
|
||||
igd_t m_igd;
|
||||
bool m_offline;
|
||||
bool m_use_ipv6;
|
||||
bool m_require_ipv4;
|
||||
std::atomic<bool> is_closing;
|
||||
std::unique_ptr<boost::thread> mPeersLoggerThread;
|
||||
//critical_section m_connections_lock;
|
||||
@ -485,7 +500,11 @@ namespace nodetool
|
||||
const int64_t default_limit_up = P2P_DEFAULT_LIMIT_RATE_UP; // kB/s
|
||||
const int64_t default_limit_down = P2P_DEFAULT_LIMIT_RATE_DOWN; // kB/s
|
||||
extern const command_line::arg_descriptor<std::string> arg_p2p_bind_ip;
|
||||
extern const command_line::arg_descriptor<std::string> arg_p2p_bind_ipv6_address;
|
||||
extern const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port;
|
||||
extern const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port_ipv6;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_use_ipv6;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_require_ipv4;
|
||||
extern const command_line::arg_descriptor<uint32_t> arg_p2p_external_port;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip;
|
||||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer;
|
||||
|
@ -93,7 +93,11 @@ namespace nodetool
|
||||
void node_server<t_payload_net_handler>::init_options(boost::program_options::options_description& desc)
|
||||
{
|
||||
command_line::add_arg(desc, arg_p2p_bind_ip);
|
||||
command_line::add_arg(desc, arg_p2p_bind_ipv6_address);
|
||||
command_line::add_arg(desc, arg_p2p_bind_port, false);
|
||||
command_line::add_arg(desc, arg_p2p_bind_port_ipv6, false);
|
||||
command_line::add_arg(desc, arg_p2p_use_ipv6);
|
||||
command_line::add_arg(desc, arg_p2p_require_ipv4);
|
||||
command_line::add_arg(desc, arg_p2p_external_port);
|
||||
command_line::add_arg(desc, arg_p2p_allow_local_ip);
|
||||
command_line::add_arg(desc, arg_p2p_add_peer);
|
||||
@ -341,7 +345,9 @@ namespace nodetool
|
||||
network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_];
|
||||
public_zone.m_connect = &public_connect;
|
||||
public_zone.m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip);
|
||||
public_zone.m_bind_ipv6_address = command_line::get_arg(vm, arg_p2p_bind_ipv6_address);
|
||||
public_zone.m_port = command_line::get_arg(vm, arg_p2p_bind_port);
|
||||
public_zone.m_port_ipv6 = command_line::get_arg(vm, arg_p2p_bind_port_ipv6);
|
||||
public_zone.m_can_pingback = true;
|
||||
m_external_port = command_line::get_arg(vm, arg_p2p_external_port);
|
||||
m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip);
|
||||
@ -375,6 +381,8 @@ namespace nodetool
|
||||
return false;
|
||||
}
|
||||
m_offline = command_line::get_arg(vm, cryptonote::arg_offline);
|
||||
m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6);
|
||||
m_require_ipv4 = command_line::get_arg(vm, arg_p2p_require_ipv4);
|
||||
|
||||
if (command_line::has_arg(vm, arg_p2p_add_peer))
|
||||
{
|
||||
@ -518,12 +526,17 @@ namespace nodetool
|
||||
|
||||
std::string host = addr;
|
||||
std::string port = std::to_string(default_port);
|
||||
size_t pos = addr.find_last_of(':');
|
||||
if (std::string::npos != pos)
|
||||
size_t colon_pos = addr.find_last_of(':');
|
||||
size_t dot_pos = addr.find_last_of('.');
|
||||
size_t square_brace_pos = addr.find('[');
|
||||
|
||||
// IPv6 will have colons regardless. IPv6 and IPv4 address:port will have a colon but also either a . or a [
|
||||
// as IPv6 addresses specified as address:port are to be specified as "[addr:addr:...:addr]:port"
|
||||
// One may also specify an IPv6 address as simply "[addr:addr:...:addr]" without the port; in that case
|
||||
// the square braces will be stripped here.
|
||||
if ((std::string::npos != colon_pos && std::string::npos != dot_pos) || std::string::npos != square_brace_pos)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(addr.length() - 1 != pos && 0 != pos, false, "Failed to parse seed address from string: '" << addr << '\'');
|
||||
host = addr.substr(0, pos);
|
||||
port = addr.substr(pos + 1);
|
||||
net::get_network_address_host_and_port(addr, host, port);
|
||||
}
|
||||
MINFO("Resolving node address: host=" << host << ", port=" << port);
|
||||
|
||||
@ -546,7 +559,9 @@ namespace nodetool
|
||||
}
|
||||
else
|
||||
{
|
||||
MWARNING("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec));
|
||||
epee::net_utils::network_address na{epee::net_utils::ipv6_network_address{endpoint.address().to_v6(), endpoint.port()}};
|
||||
seed_nodes.push_back(na);
|
||||
MINFO("Added node: " << na.str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -780,21 +795,40 @@ namespace nodetool
|
||||
|
||||
if (!zone.second.m_bind_ip.empty())
|
||||
{
|
||||
std::string ipv6_addr = "";
|
||||
std::string ipv6_port = "";
|
||||
zone.second.m_net_server.set_connection_filter(this);
|
||||
MINFO("Binding on " << zone.second.m_bind_ip << ":" << zone.second.m_port);
|
||||
res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
MINFO("Binding (IPv4) on " << zone.second.m_bind_ip << ":" << zone.second.m_port);
|
||||
if (!zone.second.m_bind_ipv6_address.empty() && m_use_ipv6)
|
||||
{
|
||||
ipv6_addr = zone.second.m_bind_ipv6_address;
|
||||
ipv6_port = zone.second.m_port_ipv6;
|
||||
MINFO("Binding (IPv6) on " << zone.second.m_bind_ipv6_address << ":" << zone.second.m_port_ipv6);
|
||||
}
|
||||
res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip, ipv6_port, ipv6_addr, m_use_ipv6, m_require_ipv4, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to bind server");
|
||||
}
|
||||
}
|
||||
|
||||
m_listening_port = public_zone.m_net_server.get_binded_port();
|
||||
MLOG_GREEN(el::Level::Info, "Net service bound to " << public_zone.m_bind_ip << ":" << m_listening_port);
|
||||
MLOG_GREEN(el::Level::Info, "Net service bound (IPv4) to " << public_zone.m_bind_ip << ":" << m_listening_port);
|
||||
if (m_use_ipv6)
|
||||
{
|
||||
m_listening_port_ipv6 = public_zone.m_net_server.get_binded_port_ipv6();
|
||||
MLOG_GREEN(el::Level::Info, "Net service bound (IPv6) to " << public_zone.m_bind_ipv6_address << ":" << m_listening_port_ipv6);
|
||||
}
|
||||
if(m_external_port)
|
||||
MDEBUG("External port defined as " << m_external_port);
|
||||
|
||||
// add UPnP port mapping
|
||||
if(m_igd == igd)
|
||||
add_upnp_port_mapping(m_listening_port);
|
||||
{
|
||||
add_upnp_port_mapping_v4(m_listening_port);
|
||||
if (m_use_ipv6)
|
||||
{
|
||||
add_upnp_port_mapping_v6(m_listening_port_ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -1997,19 +2031,43 @@ namespace nodetool
|
||||
if(!node_data.my_port)
|
||||
return false;
|
||||
|
||||
CHECK_AND_ASSERT_MES(context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), false,
|
||||
"Only IPv4 addresses are supported here");
|
||||
bool address_ok = (context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id() || context.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id());
|
||||
CHECK_AND_ASSERT_MES(address_ok, false,
|
||||
"Only IPv4 or IPv6 addresses are supported here");
|
||||
|
||||
const epee::net_utils::network_address na = context.m_remote_address;
|
||||
uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip();
|
||||
std::string ip;
|
||||
uint32_t ipv4_addr;
|
||||
boost::asio::ip::address_v6 ipv6_addr;
|
||||
bool is_ipv4;
|
||||
if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
{
|
||||
ipv4_addr = na.as<const epee::net_utils::ipv4_network_address>().ip();
|
||||
ip = epee::string_tools::get_ip_string_from_int32(ipv4_addr);
|
||||
is_ipv4 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ipv6_addr = na.as<const epee::net_utils::ipv6_network_address>().ip();
|
||||
ip = ipv6_addr.to_string();
|
||||
is_ipv4 = false;
|
||||
}
|
||||
network_zone& zone = m_network_zones.at(na.get_zone());
|
||||
|
||||
if(!zone.m_peerlist.is_host_allowed(context.m_remote_address))
|
||||
return false;
|
||||
|
||||
std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip);
|
||||
std::string port = epee::string_tools::num_to_string_fast(node_data.my_port);
|
||||
epee::net_utils::network_address address{epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)};
|
||||
|
||||
epee::net_utils::network_address address;
|
||||
if (is_ipv4)
|
||||
{
|
||||
address = epee::net_utils::network_address{epee::net_utils::ipv4_network_address(ipv4_addr, node_data.my_port)};
|
||||
}
|
||||
else
|
||||
{
|
||||
address = epee::net_utils::network_address{epee::net_utils::ipv6_network_address(ipv6_addr, node_data.my_port)};
|
||||
}
|
||||
peerid_type pr = node_data.peer_id;
|
||||
bool r = zone.m_net_server.connect_async(ip, port, zone.m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this](
|
||||
const typename net_server::t_connection_context& ping_context,
|
||||
@ -2193,12 +2251,19 @@ namespace nodetool
|
||||
//try ping to be sure that we can add this peer to peer_list
|
||||
try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), void(),
|
||||
"Only IPv4 addresses are supported here");
|
||||
CHECK_AND_ASSERT_MES((context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id() || context.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()), void(),
|
||||
"Only IPv4 or IPv6 addresses are supported here");
|
||||
//called only(!) if success pinged, update local peerlist
|
||||
peerlist_entry pe;
|
||||
const epee::net_utils::network_address na = context.m_remote_address;
|
||||
pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l);
|
||||
if (context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
{
|
||||
pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
pe.adr = epee::net_utils::ipv6_network_address(na.as<epee::net_utils::ipv6_network_address>().ip(), port_l);
|
||||
}
|
||||
time_t last_seen;
|
||||
time(&last_seen);
|
||||
pe.last_seen = static_cast<int64_t>(last_seen);
|
||||
@ -2565,16 +2630,19 @@ namespace nodetool
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::add_upnp_port_mapping(uint32_t port)
|
||||
void node_server<t_payload_net_handler>::add_upnp_port_mapping_impl(uint32_t port, bool ipv6) // if ipv6 false, do ipv4
|
||||
{
|
||||
MDEBUG("Attempting to add IGD port mapping.");
|
||||
std::string ipversion = ipv6 ? "(IPv6)" : "(IPv4)";
|
||||
MDEBUG("Attempting to add IGD port mapping " << ipversion << ".");
|
||||
int result;
|
||||
const int ipv6_arg = ipv6 ? 1 : 0;
|
||||
|
||||
#if MINIUPNPC_API_VERSION > 13
|
||||
// default according to miniupnpc.h
|
||||
unsigned char ttl = 2;
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result);
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, ttl, &result);
|
||||
#else
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result);
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, &result);
|
||||
#endif
|
||||
UPNPUrls urls;
|
||||
IGDdatas igdData;
|
||||
@ -2611,16 +2679,38 @@ namespace nodetool
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::delete_upnp_port_mapping(uint32_t port)
|
||||
void node_server<t_payload_net_handler>::add_upnp_port_mapping_v4(uint32_t port)
|
||||
{
|
||||
MDEBUG("Attempting to delete IGD port mapping.");
|
||||
add_upnp_port_mapping_impl(port, false);
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::add_upnp_port_mapping_v6(uint32_t port)
|
||||
{
|
||||
add_upnp_port_mapping_impl(port, true);
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::add_upnp_port_mapping(uint32_t port, bool ipv4, bool ipv6)
|
||||
{
|
||||
if (ipv4) add_upnp_port_mapping_v4(port);
|
||||
if (ipv6) add_upnp_port_mapping_v6(port);
|
||||
}
|
||||
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::delete_upnp_port_mapping_impl(uint32_t port, bool ipv6)
|
||||
{
|
||||
std::string ipversion = ipv6 ? "(IPv6)" : "(IPv4)";
|
||||
MDEBUG("Attempting to delete IGD port mapping " << ipversion << ".");
|
||||
int result;
|
||||
const int ipv6_arg = ipv6 ? 1 : 0;
|
||||
#if MINIUPNPC_API_VERSION > 13
|
||||
// default according to miniupnpc.h
|
||||
unsigned char ttl = 2;
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result);
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, ttl, &result);
|
||||
#else
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result);
|
||||
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, &result);
|
||||
#endif
|
||||
UPNPUrls urls;
|
||||
IGDdatas igdData;
|
||||
@ -2653,6 +2743,25 @@ namespace nodetool
|
||||
}
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::delete_upnp_port_mapping_v4(uint32_t port)
|
||||
{
|
||||
delete_upnp_port_mapping_impl(port, false);
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::delete_upnp_port_mapping_v6(uint32_t port)
|
||||
{
|
||||
delete_upnp_port_mapping_impl(port, true);
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::delete_upnp_port_mapping(uint32_t port)
|
||||
{
|
||||
delete_upnp_port_mapping_v4(port);
|
||||
delete_upnp_port_mapping_v6(port);
|
||||
}
|
||||
|
||||
template<typename t_payload_net_handler>
|
||||
boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>>
|
||||
node_server<t_payload_net_handler>::socks_connect(network_zone& zone, const epee::net_utils::network_address& remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
@ -2671,13 +2780,34 @@ namespace nodetool
|
||||
boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>>
|
||||
node_server<t_payload_net_handler>::public_connect(network_zone& zone, epee::net_utils::network_address const& na, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), boost::none,
|
||||
"Only IPv4 addresses are supported here");
|
||||
const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
|
||||
bool is_ipv4 = na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id();
|
||||
bool is_ipv6 = na.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id();
|
||||
CHECK_AND_ASSERT_MES(is_ipv4 || is_ipv6, boost::none,
|
||||
"Only IPv4 or IPv6 addresses are supported here");
|
||||
|
||||
std::string address;
|
||||
std::string port;
|
||||
|
||||
if (is_ipv4)
|
||||
{
|
||||
const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
|
||||
address = epee::string_tools::get_ip_string_from_int32(ipv4.ip());
|
||||
port = epee::string_tools::num_to_string_fast(ipv4.port());
|
||||
}
|
||||
else if (is_ipv6)
|
||||
{
|
||||
const epee::net_utils::ipv6_network_address &ipv6 = na.as<const epee::net_utils::ipv6_network_address>();
|
||||
address = ipv6.ip().to_string();
|
||||
port = epee::string_tools::num_to_string_fast(ipv6.port());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Only IPv4 or IPv6 addresses are supported here");
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
typename net_server::t_connection_context con{};
|
||||
const bool res = zone.m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()),
|
||||
epee::string_tools::num_to_string_fast(ipv4.port()),
|
||||
const bool res = zone.m_net_server.connect(address, port,
|
||||
zone.m_config.m_net_config.connection_timeout,
|
||||
con, "0.0.0.0", ssl_support);
|
||||
|
||||
|
@ -76,6 +76,9 @@ namespace boost
|
||||
case epee::net_utils::ipv4_network_address::get_type_id():
|
||||
do_serialize<epee::net_utils::ipv4_network_address>(is_saving, a, na);
|
||||
break;
|
||||
case epee::net_utils::ipv6_network_address::get_type_id():
|
||||
do_serialize<epee::net_utils::ipv6_network_address>(is_saving, a, na);
|
||||
break;
|
||||
case net::tor_address::get_type_id():
|
||||
do_serialize<net::tor_address>(is_saving, a, na);
|
||||
break;
|
||||
@ -98,6 +101,34 @@ namespace boost
|
||||
na = epee::net_utils::ipv4_network_address{ip, port};
|
||||
}
|
||||
|
||||
template <class Archive, class ver_type>
|
||||
inline void serialize(Archive &a, boost::asio::ip::address_v6& v6, const ver_type ver)
|
||||
{
|
||||
if (typename Archive::is_saving())
|
||||
{
|
||||
auto bytes = v6.to_bytes();
|
||||
for (auto &e: bytes) a & e;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::ip::address_v6::bytes_type bytes;
|
||||
for (auto &e: bytes) a & e;
|
||||
v6 = boost::asio::ip::address_v6(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class ver_type>
|
||||
inline void serialize(Archive &a, epee::net_utils::ipv6_network_address& na, const ver_type ver)
|
||||
{
|
||||
boost::asio::ip::address_v6 ip{na.ip()};
|
||||
uint16_t port{na.port()};
|
||||
a & ip;
|
||||
a & port;
|
||||
if (!typename Archive::is_saving())
|
||||
na = epee::net_utils::ipv6_network_address{ip, port};
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class ver_type>
|
||||
inline void save(Archive& a, const net::tor_address& na, const ver_type)
|
||||
{
|
||||
|
@ -161,7 +161,9 @@ namespace cryptonote
|
||||
|
||||
auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
|
||||
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
|
||||
rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
|
||||
rng, std::move(port), std::move(rpc_config->bind_ip),
|
||||
std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
|
||||
std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
|
||||
);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -1026,6 +1028,11 @@ namespace cryptonote
|
||||
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
|
||||
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
|
||||
{
|
||||
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(),
|
||||
entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
}
|
||||
else
|
||||
res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
}
|
||||
@ -1036,6 +1043,9 @@ namespace cryptonote
|
||||
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
|
||||
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id())
|
||||
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(),
|
||||
entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
else
|
||||
res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port);
|
||||
}
|
||||
|
@ -1200,6 +1200,9 @@ namespace cryptonote
|
||||
peer(uint64_t id, const std::string &host, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
|
||||
: id(id), host(host), ip(0), port(0), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
|
||||
{}
|
||||
peer(uint64_t id, const std::string &host, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
|
||||
: id(id), host(host), ip(0), port(port), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
|
||||
{}
|
||||
peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen, uint32_t pruning_seed, uint16_t rpc_port)
|
||||
: id(id), host(epee::string_tools::get_ip_string_from_int32(ip)), ip(ip), port(port), rpc_port(rpc_port), last_seen(last_seen), pruning_seed(pruning_seed)
|
||||
{}
|
||||
|
@ -90,6 +90,9 @@ namespace cryptonote
|
||||
|
||||
rpc_args::descriptors::descriptors()
|
||||
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
|
||||
, rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"})
|
||||
, rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false})
|
||||
, rpc_require_ipv4({"rpc-require-ipv4", rpc_args::tr("Require successful IPv4 bind for RPC"), true})
|
||||
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
|
||||
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
|
||||
, rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
|
||||
@ -108,6 +111,9 @@ namespace cryptonote
|
||||
{
|
||||
const descriptors arg{};
|
||||
command_line::add_arg(desc, arg.rpc_bind_ip);
|
||||
command_line::add_arg(desc, arg.rpc_bind_ipv6_address);
|
||||
command_line::add_arg(desc, arg.rpc_use_ipv6);
|
||||
command_line::add_arg(desc, arg.rpc_require_ipv4);
|
||||
command_line::add_arg(desc, arg.rpc_login);
|
||||
command_line::add_arg(desc, arg.confirm_external_bind);
|
||||
command_line::add_arg(desc, arg.rpc_access_control_origins);
|
||||
@ -127,6 +133,9 @@ namespace cryptonote
|
||||
rpc_args config{};
|
||||
|
||||
config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip);
|
||||
config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address);
|
||||
config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6);
|
||||
config.require_ipv4 = command_line::get_arg(vm, arg.rpc_require_ipv4);
|
||||
if (!config.bind_ip.empty())
|
||||
{
|
||||
// always parse IP here for error consistency
|
||||
@ -148,6 +157,34 @@ namespace cryptonote
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
if (!config.bind_ipv6_address.empty())
|
||||
{
|
||||
// allow square braces, but remove them here if present
|
||||
if (config.bind_ipv6_address.find('[') != std::string::npos)
|
||||
{
|
||||
config.bind_ipv6_address = config.bind_ipv6_address.substr(1, config.bind_ipv6_address.size() - 2);
|
||||
}
|
||||
|
||||
|
||||
// always parse IP here for error consistency
|
||||
boost::system::error_code ec{};
|
||||
const auto parsed_ip = boost::asio::ip::address::from_string(config.bind_ipv6_address, ec);
|
||||
if (ec)
|
||||
{
|
||||
LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_bind_ipv6_address.name);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
if (!parsed_ip.is_loopback() && !command_line::get_arg(vm, arg.confirm_external_bind))
|
||||
{
|
||||
LOG_ERROR(
|
||||
"--" << arg.rpc_bind_ipv6_address.name <<
|
||||
tr(" permits inbound unencrypted external connections. Consider SSH tunnel or SSL proxy instead. Override with --") <<
|
||||
arg.confirm_external_bind.name
|
||||
);
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
const char *env_rpc_login = nullptr;
|
||||
const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login);
|
||||
|
@ -52,6 +52,9 @@ namespace cryptonote
|
||||
descriptors& operator=(descriptors&&) = delete;
|
||||
|
||||
const command_line::arg_descriptor<std::string> rpc_bind_ip;
|
||||
const command_line::arg_descriptor<std::string> rpc_bind_ipv6_address;
|
||||
const command_line::arg_descriptor<bool> rpc_use_ipv6;
|
||||
const command_line::arg_descriptor<bool> rpc_require_ipv4;
|
||||
const command_line::arg_descriptor<std::string> rpc_login;
|
||||
const command_line::arg_descriptor<bool> confirm_external_bind;
|
||||
const command_line::arg_descriptor<std::string> rpc_access_control_origins;
|
||||
@ -76,6 +79,9 @@ namespace cryptonote
|
||||
static boost::optional<epee::net_utils::ssl_options_t> process_ssl(const boost::program_options::variables_map& vm, const bool any_cert_option = false);
|
||||
|
||||
std::string bind_ip;
|
||||
std::string bind_ipv6_address;
|
||||
bool use_ipv6;
|
||||
bool require_ipv4;
|
||||
std::vector<std::string> access_control_origins;
|
||||
boost::optional<tools::login> login; // currently `boost::none` if unspecified by user
|
||||
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
|
||||
|
@ -247,7 +247,9 @@ namespace tools
|
||||
m_net_server.set_threads_prefix("RPC");
|
||||
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
|
||||
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
|
||||
rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
|
||||
rng, std::move(bind_port), std::move(rpc_config->bind_ip),
|
||||
std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
|
||||
std::move(rpc_config->access_control_origins), std::move(http_login),
|
||||
std::move(rpc_config->ssl_options)
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user