aboutsummaryrefslogtreecommitdiff
path: root/src/p2p
diff options
context:
space:
mode:
authorLee Clagett <code@leeclagett.com>2019-05-16 16:34:22 -0400
committerLee Clagett <code@leeclagett.com>2019-07-17 14:22:37 +0000
commit3b24b1d082da28da15dc5e3aeaa0ebebe7758f2f (patch)
tree04c19819bc99545f0472be8812c850ed1a433bfa /src/p2p
parentAdd ref-counted buffer byte_slice. Currently used for sending TCP data. (diff)
downloadmonero-3b24b1d082da28da15dc5e3aeaa0ebebe7758f2f.tar.xz
Added support for "noise" over I1P/Tor to mask Tx transmission.
Diffstat (limited to 'src/p2p')
-rw-r--r--src/p2p/net_node.cpp25
-rw-r--r--src/p2p/net_node.h10
-rw-r--r--src/p2p/net_node.inl83
-rw-r--r--src/p2p/net_node_common.h13
4 files changed, 115 insertions, 16 deletions
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index bb51be242..c7fc058ca 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -144,7 +144,7 @@ namespace nodetool
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_exclusive_node = {"add-exclusive-node", "Specify list of peers to connect to only."
" If this option is given the options add-priority-node and seed-node are ignored"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
- const command_line::arg_descriptor<std::vector<std::string> > arg_proxy = {"proxy", "<network-type>,<socks-ip:port>[,max_connections] i.e. \"tor,127.0.0.1:9050,100\""};
+ const command_line::arg_descriptor<std::vector<std::string> > arg_proxy = {"proxy", "<network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""};
const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
@@ -163,7 +163,7 @@ namespace nodetool
boost::optional<std::vector<proxy>> get_proxies(boost::program_options::variables_map const& vm)
{
- namespace ip = boost::asio::ip;
+ namespace ip = boost::asio::ip;
std::vector<proxy> proxies{};
@@ -183,14 +183,25 @@ namespace nodetool
const boost::string_ref proxy{next->begin(), next->size()};
++next;
- if (!next.eof())
+ for (unsigned count = 0; !next.eof(); ++count, ++next)
{
- proxies.back().max_connections = get_max_connections(*next);
- if (proxies.back().max_connections == 0)
+ if (2 <= count)
{
- MERROR("Invalid max connections given to --" << arg_proxy.name);
+ MERROR("Too many ',' characters given to --" << arg_proxy.name);
return boost::none;
}
+
+ if (boost::string_ref{next->begin(), next->size()} == "disable_noise")
+ proxies.back().noise = false;
+ else
+ {
+ proxies.back().max_connections = get_max_connections(*next);
+ if (proxies.back().max_connections == 0)
+ {
+ MERROR("Invalid max connections given to --" << arg_proxy.name);
+ return boost::none;
+ }
+ }
}
switch (epee::net_utils::zone_from_string(zone))
@@ -214,7 +225,7 @@ namespace nodetool
return boost::none;
}
proxies.back().address = ip::tcp::endpoint{ip::address_v4{boost::endian::native_to_big(ip)}, port};
- }
+ }
return proxies;
}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 6d2ae878f..231175dd2 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -43,6 +43,7 @@
#include <vector>
#include "cryptonote_config.h"
+#include "cryptonote_protocol/levin_notify.h"
#include "warnings.h"
#include "net/abstract_tcp_server2.h"
#include "net/levin_protocol_handler.h"
@@ -66,12 +67,14 @@ namespace nodetool
proxy()
: max_connections(-1),
address(),
- zone(epee::net_utils::zone::invalid)
+ zone(epee::net_utils::zone::invalid),
+ noise(true)
{}
std::int64_t max_connections;
boost::asio::ip::tcp::endpoint address;
epee::net_utils::zone zone;
+ bool noise;
};
struct anonymous_inbound
@@ -154,6 +157,7 @@ namespace nodetool
m_bind_ipv6_address(),
m_port(),
m_port_ipv6(),
+ m_notifier(),
m_our_address(),
m_peerlist(),
m_config{},
@@ -172,6 +176,7 @@ namespace nodetool
m_bind_ipv6_address(),
m_port(),
m_port_ipv6(),
+ m_notifier(),
m_our_address(),
m_peerlist(),
m_config{},
@@ -189,6 +194,7 @@ namespace nodetool
std::string m_bind_ipv6_address;
std::string m_port;
std::string m_port_ipv6;
+ cryptonote::levin::notify m_notifier;
epee::net_utils::network_address m_our_address; // in anonymity networks
peerlist_manager m_peerlist;
config m_config;
@@ -255,7 +261,6 @@ namespace nodetool
size_t get_public_gray_peers_count();
void get_public_peerlist(std::vector<peerlist_entry>& gray, std::vector<peerlist_entry>& white);
void get_peerlist(std::vector<peerlist_entry>& gray, std::vector<peerlist_entry>& white);
- size_t get_zone_count() const { return m_network_zones.size(); }
void change_max_out_public_peers(size_t count);
uint32_t get_max_out_public_peers() const;
@@ -330,6 +335,7 @@ namespace nodetool
virtual void callback(p2p_connection_context& context);
//----------------- i_p2p_endpoint -------------------------------------------------------------
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections);
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs);
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 8c0cff7e2..41ca19917 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -383,6 +383,9 @@ namespace nodetool
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);
+ public_zone.m_notifier = cryptonote::levin::notify{
+ public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr
+ };
if (command_line::has_arg(vm, arg_p2p_add_peer))
{
@@ -462,6 +465,7 @@ namespace nodetool
return false;
+ epee::byte_slice noise = nullptr;
auto proxies = get_proxies(vm);
if (!proxies)
return false;
@@ -479,6 +483,20 @@ namespace nodetool
if (!set_max_out_peers(zone, proxy.max_connections))
return false;
+
+ epee::byte_slice this_noise = nullptr;
+ if (proxy.noise)
+ {
+ static_assert(sizeof(epee::levin::bucket_head2) < CRYPTONOTE_NOISE_BYTES, "noise bytes too small");
+ if (noise.empty())
+ noise = epee::levin::make_noise_notify(CRYPTONOTE_NOISE_BYTES);
+
+ this_noise = noise.clone();
+ }
+
+ zone.m_notifier = cryptonote::levin::notify{
+ zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise)
+ };
}
for (const auto& zone : m_network_zones)
@@ -494,6 +512,7 @@ namespace nodetool
if (!inbounds)
return false;
+ const std::size_t tx_relay_zones = m_network_zones.size();
for (auto& inbound : *inbounds)
{
network_zone& zone = add_zone(inbound.our_address.get_zone());
@@ -504,6 +523,12 @@ namespace nodetool
return false;
}
+ if (zone.m_connect == nullptr && tx_relay_zones <= 1)
+ {
+ MERROR("Listed --" << arg_anonymous_inbound.name << " without listing any --" << arg_proxy.name << ". The latter is necessary for sending origin txes over anonymity networks");
+ return false;
+ }
+
zone.m_bind_ip = std::move(inbound.local_ip);
zone.m_port = std::move(inbound.local_port);
zone.m_net_server.set_default_remote(std::move(inbound.default_remote));
@@ -1266,6 +1291,7 @@ namespace nodetool
ape.first_seen = first_seen_stamp ? first_seen_stamp : time(nullptr);
zone.m_peerlist.append_with_peer_anchor(ape);
+ zone.m_notifier.new_out_connection();
LOG_DEBUG_CC(*con, "CONNECTION HANDSHAKED OK.");
return true;
@@ -1990,7 +2016,7 @@ namespace nodetool
}
if (c_id.first <= zone->first)
break;
-
+
++zone;
}
if (zone->first == c_id.first)
@@ -2000,6 +2026,61 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
+ {
+ namespace enet = epee::net_utils;
+
+ const auto send = [&txs, &source, pad_txs] (std::pair<const enet::zone, network_zone>& network)
+ {
+ if (network.second.m_notifier.send_txs(std::move(txs), source, (pad_txs || network.first != enet::zone::public_)))
+ return network.first;
+ return enet::zone::invalid;
+ };
+
+ if (m_network_zones.empty())
+ return enet::zone::invalid;
+
+ if (origin != enet::zone::invalid)
+ return send(*m_network_zones.begin()); // send all txs received via p2p over public network
+
+ if (m_network_zones.size() <= 2)
+ return send(*m_network_zones.rbegin()); // see static asserts below; sends over anonymity network iff enabled
+
+ /* These checks are to ensure that i2p is highest priority if multiple
+ zones are selected. Make sure to update logic if the values cannot be
+ in the same relative order. `m_network_zones` must be sorted map too. */
+ static_assert(std::is_same<std::underlying_type<enet::zone>::type, std::uint8_t>{}, "expected uint8_t zone");
+ static_assert(unsigned(enet::zone::invalid) == 0, "invalid expected to be 0");
+ static_assert(unsigned(enet::zone::public_) == 1, "public_ expected to be 1");
+ static_assert(unsigned(enet::zone::i2p) == 2, "i2p expected to be 2");
+ static_assert(unsigned(enet::zone::tor) == 3, "tor expected to be 3");
+
+ // check for anonymity networks with noise and connections
+ for (auto network = ++m_network_zones.begin(); network != m_network_zones.end(); ++network)
+ {
+ if (enet::zone::tor < network->first)
+ break; // unknown network
+
+ const auto status = network->second.m_notifier.get_status();
+ if (status.has_noise && status.connections_filled)
+ return send(*network);
+ }
+
+ // use the anonymity network with outbound support
+ for (auto network = ++m_network_zones.begin(); network != m_network_zones.end(); ++network)
+ {
+ if (enet::zone::tor < network->first)
+ break; // unknown network
+
+ if (network->second.m_connect)
+ return send(*network);
+ }
+
+ // configuration should not allow this scenario
+ return enet::zone::invalid;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::callback(p2p_connection_context& context)
{
m_payload_handler.on_callback(context);
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 34d151f5f..239814c2c 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -33,6 +33,8 @@
#include <boost/uuid/uuid.hpp>
#include <utility>
#include <vector>
+#include "cryptonote_basic/blobdatatype.h"
+#include "net/enums.h"
#include "net/net_utils_base.h"
#include "p2p_protocol_defs.h"
@@ -46,12 +48,12 @@ namespace nodetool
struct i_p2p_endpoint
{
virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0;
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)=0;
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_public_connections_count()=0;
- virtual size_t get_zone_count() const=0;
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool block_host(const epee::net_utils::network_address &address, time_t seconds = 0)=0;
@@ -71,6 +73,10 @@ namespace nodetool
{
return false;
}
+ virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const bool pad_txs)
+ {
+ return epee::net_utils::zone::invalid;
+ }
virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
{
return false;
@@ -96,11 +102,6 @@ namespace nodetool
return false;
}
- virtual size_t get_zone_count() const
- {
- return 0;
- }
-
virtual uint64_t get_public_connections_count()
{
return false;