Electroneum
net_node.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2019, The Monero Project
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification, are
6 // permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice, this list of
9 // conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 // of conditions and the following disclaimer in the documentation and/or other
13 // materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be
16 // used to endorse or promote products derived from this software without specific
17 // prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
30 
31 #include <boost/algorithm/string/find_iterator.hpp>
32 #include <boost/algorithm/string/finder.hpp>
33 #include <boost/chrono/duration.hpp>
34 #include <boost/endian/conversion.hpp>
35 #include <boost/optional/optional.hpp>
36 #include <boost/thread/future.hpp>
37 #include <boost/utility/string_ref.hpp>
38 #include <chrono>
39 #include <utility>
40 
41 #include "common/command_line.h"
44 #include "net_node.h"
45 #include "net/net_utils_base.h"
46 #include "net/socks.h"
47 #include "net/parse.h"
48 #include "net/tor_address.h"
49 #include "net/i2p_address.h"
50 #include "p2p/p2p_protocol_defs.h"
51 #include "string_tools.h"
52 
53 namespace
54 {
55  constexpr const boost::chrono::milliseconds future_poll_interval{500};
56  constexpr const std::chrono::seconds socks_connect_timeout{P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT};
57 
58  std::int64_t get_max_connections(const boost::iterator_range<boost::string_ref::const_iterator> value) noexcept
59  {
60  // -1 is default, 0 is error
61  if (value.empty())
62  return -1;
63 
64  std::uint32_t out = 0;
66  return out;
67  return 0;
68  }
69 
70  template<typename T>
71  epee::net_utils::network_address get_address(const boost::string_ref value)
72  {
73  expect<T> address = T::make(value);
74  if (!address)
75  {
76  MERROR(
77  "Failed to parse " << epee::net_utils::zone_to_string(T::get_zone()) << " address \"" << value << "\": " << address.error().message()
78  );
79  return {};
80  }
81  return {std::move(*address)};
82  }
83 
84  bool start_socks(std::shared_ptr<net::socks::client> client, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote)
85  {
86  CHECK_AND_ASSERT_MES(client != nullptr, false, "Unexpected null client");
87 
88  bool set = false;
89  switch (remote.get_type_id())
90  {
92  set = client->set_connect_command(remote.as<net::tor_address>());
93  break;
95  set = client->set_connect_command(remote.as<net::i2p_address>());
96  break;
97  default:
98  MERROR("Unsupported network address in socks_connect");
99  return false;
100  }
101 
102  const bool sent =
103  set && net::socks::client::connect_and_send(std::move(client), proxy);
104  CHECK_AND_ASSERT_MES(sent, false, "Unexpected failure to init socks client");
105  return true;
106  }
107 }
108 
109 namespace nodetool
110 {
111  const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
113  "p2p-bind-port"
114  , "Port for p2p network protocol"
117  , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
118  if (testnet_stagenet[0] && defaulted)
120  else if (testnet_stagenet[1] && defaulted)
122  return val;
123  }
124  };
125  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};
126  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"};
127  const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"};
128  const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"};
129  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."
130  " If this option is given the options add-priority-node and seed-node are ignored"};
131  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"};
132  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\""};
133  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\""};
134  const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
135  const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
136 
137  const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
138  const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1};
139  const command_line::arg_descriptor<int64_t> arg_in_peers = {"in-peers", "set max number of in peers", -1};
140  const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1};
141 
142  const command_line::arg_descriptor<int64_t> arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", P2P_DEFAULT_LIMIT_RATE_UP};
143  const command_line::arg_descriptor<int64_t> arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", P2P_DEFAULT_LIMIT_RATE_DOWN};
144  const command_line::arg_descriptor<int64_t> arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", -1};
145 
146  const command_line::arg_descriptor<bool> arg_save_graph = {"save-graph", "Save data for dr electroneum", false};
147 
148  boost::optional<std::vector<proxy>> get_proxies(boost::program_options::variables_map const& vm)
149  {
150  namespace ip = boost::asio::ip;
151 
152  std::vector<proxy> proxies{};
153 
154  const std::vector<std::string> args = command_line::get_arg(vm, arg_proxy);
155  proxies.reserve(args.size());
156 
157  for (const boost::string_ref arg : args)
158  {
159  proxies.emplace_back();
160 
161  auto next = boost::algorithm::make_split_iterator(arg, boost::algorithm::first_finder(","));
162  CHECK_AND_ASSERT_MES(!next.eof() && !next->empty(), boost::none, "No network type for --" << arg_proxy.name);
163  const boost::string_ref zone{next->begin(), next->size()};
164 
165  ++next;
166  CHECK_AND_ASSERT_MES(!next.eof() && !next->empty(), boost::none, "No ipv4:port given for --" << arg_proxy.name);
167  const boost::string_ref proxy{next->begin(), next->size()};
168 
169  ++next;
170  if (!next.eof())
171  {
172  proxies.back().max_connections = get_max_connections(*next);
173  if (proxies.back().max_connections == 0)
174  {
175  MERROR("Invalid max connections given to --" << arg_proxy.name);
176  return boost::none;
177  }
178  }
179 
181  {
183  proxies.back().zone = epee::net_utils::zone::tor;
184  break;
186  proxies.back().zone = epee::net_utils::zone::i2p;
187  break;
188  default:
189  MERROR("Invalid network for --" << arg_proxy.name);
190  return boost::none;
191  }
192 
193  std::uint32_t ip = 0;
194  std::uint16_t port = 0;
196  {
197  MERROR("Invalid ipv4:port given for --" << arg_proxy.name);
198  return boost::none;
199  }
200  proxies.back().address = ip::tcp::endpoint{ip::address_v4{boost::endian::native_to_big(ip)}, port};
201  }
202 
203  return proxies;
204  }
205 
206  boost::optional<std::vector<anonymous_inbound>> get_anonymous_inbounds(boost::program_options::variables_map const& vm)
207  {
208  std::vector<anonymous_inbound> inbounds{};
209 
210  const std::vector<std::string> args = command_line::get_arg(vm, arg_anonymous_inbound);
211  inbounds.reserve(args.size());
212 
213  for (const boost::string_ref arg : args)
214  {
215  inbounds.emplace_back();
216 
217  auto next = boost::algorithm::make_split_iterator(arg, boost::algorithm::first_finder(","));
218  CHECK_AND_ASSERT_MES(!next.eof() && !next->empty(), boost::none, "No inbound address for --" << arg_anonymous_inbound.name);
219  const boost::string_ref address{next->begin(), next->size()};
220 
221  ++next;
222  CHECK_AND_ASSERT_MES(!next.eof() && !next->empty(), boost::none, "No local ipv4:port given for --" << arg_anonymous_inbound.name);
223  const boost::string_ref bind{next->begin(), next->size()};
224 
225  const std::size_t colon = bind.find_first_of(':');
226  CHECK_AND_ASSERT_MES(colon < bind.size(), boost::none, "No local port given for --" << arg_anonymous_inbound.name);
227 
228  ++next;
229  if (!next.eof())
230  {
231  inbounds.back().max_connections = get_max_connections(*next);
232  if (inbounds.back().max_connections == 0)
233  {
234  MERROR("Invalid max connections given to --" << arg_proxy.name);
235  return boost::none;
236  }
237  }
238 
240  switch (our_address ? our_address->get_type_id() : epee::net_utils::address_type::invalid)
241  {
243  inbounds.back().our_address = std::move(*our_address);
244  inbounds.back().default_remote = net::tor_address::unknown();
245  break;
247  inbounds.back().our_address = std::move(*our_address);
248  inbounds.back().default_remote = net::i2p_address::unknown();
249  break;
250  default:
251  MERROR("Invalid inbound address (" << address << ") for --" << arg_anonymous_inbound.name << ": " << (our_address ? "invalid type" : our_address.error().message()));
252  return boost::none;
253  }
254 
255  // get_address returns default constructed address on error
256  if (inbounds.back().our_address == epee::net_utils::network_address{})
257  return boost::none;
258 
259  std::uint32_t ip = 0;
260  std::uint16_t port = 0;
262  {
263  MERROR("Invalid ipv4:port given for --" << arg_anonymous_inbound.name);
264  return boost::none;
265  }
266  inbounds.back().local_ip = std::string{bind.substr(0, colon)};
267  inbounds.back().local_port = std::string{bind.substr(colon + 1)};
268  }
269 
270  return inbounds;
271  }
272 
274  {
275  switch (command)
276  {
280  return false;
281  default:
282  break;
283  }
284 
285  if (address.get_zone() == epee::net_utils::zone::public_)
286  return false;
287 
288  MWARNING("Filtered command (#" << command << ") to/from " << address.str());
289  return true;
290  }
291 
292  boost::optional<boost::asio::ip::tcp::socket>
293  socks_connect_internal(const std::atomic<bool>& stop_signal, boost::asio::io_service& service, const boost::asio::ip::tcp::endpoint& proxy, const epee::net_utils::network_address& remote)
294  {
295  using socket_type = net::socks::client::stream_type::socket;
296  using client_result = std::pair<boost::system::error_code, socket_type>;
297 
298  struct notify
299  {
300  boost::promise<client_result> socks_promise;
301 
302  void operator()(boost::system::error_code error, socket_type&& sock)
303  {
304  socks_promise.set_value(std::make_pair(error, std::move(sock)));
305  }
306  };
307 
308  boost::unique_future<client_result> socks_result{};
309  {
310  boost::promise<client_result> socks_promise{};
311  socks_result = socks_promise.get_future();
312 
313  auto client = net::socks::make_connect_client(
314  boost::asio::ip::tcp::socket{service}, net::socks::version::v4a, notify{std::move(socks_promise)}
315  );
316  if (!start_socks(std::move(client), proxy, remote))
317  return boost::none;
318  }
319 
320  const auto start = std::chrono::steady_clock::now();
321  while (socks_result.wait_for(future_poll_interval) == boost::future_status::timeout)
322  {
323  if (socks_connect_timeout < std::chrono::steady_clock::now() - start)
324  {
325  MERROR("Timeout on socks connect (" << proxy << " to " << remote.str() << ")");
326  return boost::none;
327  }
328 
329  if (stop_signal)
330  return boost::none;
331  }
332 
333  try
334  {
335  auto result = socks_result.get();
336  if (!result.first)
337  return {std::move(result.second)};
338 
339  MERROR("Failed to make socks connection to " << remote.str() << " (via " << proxy << "): " << result.first.message());
340  }
341  catch (boost::broken_promise const&)
342  {}
343 
344  return boost::none;
345  }
346 }
#define MERROR(x)
Definition: misc_log_ex.h:73
static bool connect_and_send(std::shared_ptr< client > self, const stream_type::endpoint &proxy_address)
Definition: socks.cpp:294
uint16_t const P2P_DEFAULT_PORT
uint16_t const P2P_DEFAULT_PORT
const command_line::arg_descriptor< std::vector< std::string > > arg_anonymous_inbound
Definition: net_node.cpp:133
zone zone_from_string(boost::string_ref value) noexcept
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
#define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT
static i2p_address unknown() noexcept
Definition: i2p_address.h:70
const command_line::arg_descriptor< int > arg_tos_flag
Definition: net_node.cpp:140
boost::optional< std::vector< anonymous_inbound > > get_anonymous_inbounds(boost::program_options::variables_map const &vm)
Definition: net_node.cpp:206
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition: zmq.h:101
unsigned short uint16_t
Definition: stdint.h:125
const command_line::arg_descriptor< bool > arg_no_sync
Definition: net_node.cpp:135
const command_line::arg_descriptor< bool, false > arg_stagenet_on
static tor_address unknown() noexcept
Definition: tor_address.h:70
const command_line::arg_descriptor< int64_t > arg_out_peers
Definition: net_node.cpp:138
uint16_t const P2P_DEFAULT_PORT
std::shared_ptr< client > make_connect_client(client::stream_type::socket &&proxy, socks::version ver, Handler handler)
Definition: socks.h:226
const command_line::arg_descriptor< std::string, false, true, 2 > arg_p2p_bind_port
Definition: net_node.cpp:112
std::error_code error() const noexcept
Definition: expect.h:276
const command_line::arg_descriptor< std::string > arg_p2p_bind_ip
Definition: net_node.cpp:111
const command_line::arg_descriptor< std::vector< std::string > > arg_proxy
Definition: net_node.cpp:132
#define P2P_DEFAULT_LIMIT_RATE_DOWN
const command_line::arg_descriptor< int64_t > arg_limit_rate_down
Definition: net_node.cpp:143
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_peer
Definition: net_node.cpp:127
address_type get_type_id() const
bool is_filtered_command(const epee::net_utils::network_address &address, int command)
Definition: net_node.cpp:273
const command_line::arg_descriptor< bool, false > arg_testnet_on
unsigned int uint32_t
Definition: stdint.h:126
expect< epee::net_utils::network_address > get_network_address(const boost::string_ref address, const std::uint16_t default_port)
Definition: parse.cpp:38
Definition: expect.h:70
const command_line::arg_descriptor< int64_t > arg_limit_rate_up
Definition: net_node.cpp:142
const char * zone_to_string(zone value) noexcept
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_priority_node
Definition: net_node.cpp:128
std::int64_t max_connections
Definition: net_node.h:73
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_exclusive_node
Definition: net_node.cpp:129
cryptonote::account_public_address get_address(const var_addr_t &inp)
Definition: chaingen.cpp:665
#define MWARNING(x)
Definition: misc_log_ex.h:74
static constexpr epee::net_utils::address_type get_type_id() noexcept
Definition: tor_address.h:112
boost::endian::big_uint32_t ip
Definition: socks.cpp:61
boost::endian::big_uint16_t port
Definition: socks.cpp:60
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_seed_node
Definition: net_node.cpp:131
const command_line::arg_descriptor< bool > arg_save_graph
Definition: net_node.cpp:146
const T & move(const T &t)
Definition: gtest-port.h:1317
boost::optional< std::vector< proxy > > get_proxies(boost::program_options::variables_map const &vm)
Definition: net_node.cpp:148
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
const command_line::arg_descriptor< bool > arg_p2p_hide_my_port
Definition: net_node.cpp:134
const command_line::arg_descriptor< bool > arg_no_igd
Definition: net_node.cpp:137
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Definition: command_line.h:271
signed __int64 int64_t
Definition: stdint.h:135
boost::optional< boost::asio::ip::tcp::socket > socks_connect_internal(const std::atomic< bool > &stop_signal, boost::asio::io_service &service, const boost::asio::ip::tcp::endpoint &proxy, const epee::net_utils::network_address &remote)
Definition: net_node.cpp:293
const char * address
Definition: multisig.cpp:37
std::string to_string(t_connection_type type)
static constexpr epee::net_utils::address_type get_type_id() noexcept
Definition: i2p_address.h:112
#define P2P_DEFAULT_LIMIT_RATE_UP
const command_line::arg_descriptor< int64_t > arg_limit_rate
Definition: net_node.cpp:144
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition: string_tools.h:125
const command_line::arg_descriptor< uint32_t > arg_p2p_external_port
Definition: net_node.cpp:125
error
Tracks LMDB error codes.
Definition: error.h:44
const command_line::arg_descriptor< bool > arg_p2p_allow_local_ip
Definition: net_node.cpp:126
const command_line::arg_descriptor< int64_t > arg_in_peers
Definition: net_node.cpp:139
bool parse_peer_from_string(uint32_t &ip, uint16_t &port, const std::string &addres)
Definition: string_tools.h:174