Electroneum
Loading...
Searching...
No Matches
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"
51#include "string_tools.h"
52
53namespace
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;
65 if (epee::string_tools::get_xtype_from_string(out, std::string{value.begin(), value.end()}))
66 return out;
67 return 0;
68 }
69
70 template<typename T>
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
109namespace 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"
115 , std::to_string(config::P2P_DEFAULT_PORT)
117 , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
118 if (testnet_stagenet[0] && defaulted)
119 return std::to_string(config::testnet::P2P_DEFAULT_PORT);
120 else if (testnet_stagenet[1] && defaulted)
121 return std::to_string(config::stagenet::P2P_DEFAULT_PORT);
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;
195 if (!epee::string_tools::parse_peer_from_string(ip, port, std::string{proxy}) || 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;
261 if (!epee::string_tools::parse_peer_from_string(ip, port, std::string{bind}))
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
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}
cryptonote::account_public_address get_address(const var_addr_t &inp)
Definition chaingen.cpp:665
*return False if otherwise error()
static i2p_address unknown() noexcept
Definition i2p_address.h:70
static constexpr epee::net_utils::address_type get_type_id() noexcept
static bool connect_and_send(std::shared_ptr< client > self, const stream_type::endpoint &proxy_address)
Definition socks.cpp:294
static constexpr epee::net_utils::address_type get_type_id() noexcept
static tor_address unknown() noexcept
Definition tor_address.h:70
#define P2P_DEFAULT_LIMIT_RATE_DOWN
#define P2P_DEFAULT_SOCKS_CONNECT_TIMEOUT
#define P2P_DEFAULT_LIMIT_RATE_UP
#define MERROR(x)
Definition misc_log_ex.h:73
#define MWARNING(x)
Definition misc_log_ex.h:74
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
uint16_t const P2P_DEFAULT_PORT
uint16_t const P2P_DEFAULT_PORT
uint16_t const P2P_DEFAULT_PORT
const command_line::arg_descriptor< bool, false > arg_testnet_on
const command_line::arg_descriptor< bool, false > arg_stagenet_on
zone zone_from_string(boost::string_ref value) noexcept
const char * zone_to_string(zone value) noexcept
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
bool parse_peer_from_string(uint32_t &ip, uint16_t &port, const std::string &addres)
std::shared_ptr< client > make_connect_client(client::stream_type::socket &&proxy, socks::version ver, Handler handler)
Definition socks.h:226
expect< epee::net_utils::network_address > get_network_address(const boost::string_ref address, const std::uint16_t default_port)
Definition parse.cpp:38
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_priority_node
Definition net_node.cpp:128
bool is_filtered_command(const epee::net_utils::network_address &address, int command)
Definition net_node.cpp:273
const command_line::arg_descriptor< int > arg_tos_flag
Definition net_node.cpp:140
const command_line::arg_descriptor< uint32_t > arg_p2p_external_port
Definition net_node.cpp:125
const command_line::arg_descriptor< bool > arg_no_igd
Definition net_node.cpp:137
const command_line::arg_descriptor< int64_t > arg_limit_rate
Definition net_node.cpp:144
const command_line::arg_descriptor< std::string, false, true, 2 > arg_p2p_bind_port
Definition net_node.cpp:112
const command_line::arg_descriptor< bool > arg_no_sync
Definition net_node.cpp:135
boost::optional< std::vector< anonymous_inbound > > get_anonymous_inbounds(boost::program_options::variables_map const &vm)
Definition net_node.cpp:206
const command_line::arg_descriptor< bool > arg_p2p_allow_local_ip
Definition net_node.cpp:126
const command_line::arg_descriptor< int64_t > arg_limit_rate_down
Definition net_node.cpp:143
const command_line::arg_descriptor< std::string > arg_p2p_bind_ip
Definition net_node.cpp:111
const command_line::arg_descriptor< int64_t > arg_limit_rate_up
Definition net_node.cpp:142
boost::optional< std::vector< proxy > > get_proxies(boost::program_options::variables_map const &vm)
Definition net_node.cpp:148
const command_line::arg_descriptor< std::vector< std::string > > arg_anonymous_inbound
Definition net_node.cpp:133
const command_line::arg_descriptor< int64_t > arg_out_peers
Definition net_node.cpp:138
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 command_line::arg_descriptor< bool > arg_p2p_hide_my_port
Definition net_node.cpp:134
const command_line::arg_descriptor< bool > arg_save_graph
Definition net_node.cpp:146
const command_line::arg_descriptor< int64_t > arg_in_peers
Definition net_node.cpp:139
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_seed_node
Definition net_node.cpp:131
const command_line::arg_descriptor< std::vector< std::string > > arg_proxy
Definition net_node.cpp:132
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_peer
Definition net_node.cpp:127
const command_line::arg_descriptor< std::vector< std::string > > arg_p2p_add_exclusive_node
Definition net_node.cpp:129
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1225
const char * address
Definition multisig.cpp:37