1 // Copyright (c) 2009-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <rpc/server.h>
6
7 #include <banman.h>
8 #include <clientversion.h>
9 #include <core_io.h>
10 #include <net.h>
11 #include <net_permissions.h>
12 #include <net_processing.h>
13 #include <net_types.h> // For banmap_t
14 #include <netbase.h>
15 #include <node/context.h>
16 #include <policy/settings.h>
17 #include <rpc/blockchain.h>
18 #include <rpc/protocol.h>
19 #include <rpc/util.h>
20 #include <sync.h>
21 #include <timedata.h>
22 #include <util/strencodings.h>
23 #include <util/string.h>
24 #include <util/system.h>
25 #include <util/translation.h>
26 #include <validation.h>
27 #include <version.h>
28 #include <warnings.h>
29
30 #include <univalue.h>
31
32 const std::vector<std::string> CONNECTION_TYPE_DOC{
33 "outbound-full-relay (default automatic connections)",
34 "block-relay-only (does not relay transactions or addresses)",
35 "inbound (initiated by the peer)",
36 "manual (added via addnode RPC or -addnode/-connect configuration options)",
37 "addr-fetch (short-lived automatic connection for soliciting addresses)",
38 "feeler (short-lived automatic connection for testing addresses)"
39 };
40
getconnectioncount()41 static RPCHelpMan getconnectioncount()
42 {
43 return RPCHelpMan{"getconnectioncount",
44 "\nReturns the number of connections to other nodes.\n",
45 {},
46 RPCResult{
47 RPCResult::Type::NUM, "", "The connection count"
48 },
49 RPCExamples{
50 HelpExampleCli("getconnectioncount", "")
51 + HelpExampleRpc("getconnectioncount", "")
52 },
53 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
54 {
55 NodeContext& node = EnsureNodeContext(request.context);
56 if(!node.connman)
57 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
58
59 return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
60 },
61 };
62 }
63
ping()64 static RPCHelpMan ping()
65 {
66 return RPCHelpMan{"ping",
67 "\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
68 "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
69 "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n",
70 {},
71 RPCResult{RPCResult::Type::NONE, "", ""},
72 RPCExamples{
73 HelpExampleCli("ping", "")
74 + HelpExampleRpc("ping", "")
75 },
76 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
77 {
78 NodeContext& node = EnsureNodeContext(request.context);
79 if(!node.connman)
80 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
81
82 // Request that each node send a ping during next message processing pass
83 node.connman->ForEachNode([](CNode* pnode) {
84 pnode->fPingQueued = true;
85 });
86 return NullUniValue;
87 },
88 };
89 }
90
getpeerinfo()91 static RPCHelpMan getpeerinfo()
92 {
93 return RPCHelpMan{"getpeerinfo",
94 "\nReturns data about each connected network node as a json array of objects.\n",
95 {},
96 RPCResult{
97 RPCResult::Type::ARR, "", "",
98 {
99 {RPCResult::Type::OBJ, "", "",
100 {
101 {
102 {RPCResult::Type::NUM, "id", "Peer index"},
103 {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
104 {RPCResult::Type::STR, "addrbind", "(ip:port) Bind address of the connection to the peer"},
105 {RPCResult::Type::STR, "addrlocal", "(ip:port) Local address as reported by the peer"},
106 {RPCResult::Type::STR, "network", "Network (ipv4, ipv6, or onion) the peer connected through"},
107 {RPCResult::Type::NUM, "mapped_as", "The AS in the BGP route to the peer used for diversifying\n"
108 "peer selection (only available if the asmap config flag is set)"},
109 {RPCResult::Type::STR_HEX, "services", "The services offered"},
110 {RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form",
111 {
112 {RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
113 }},
114 {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"},
115 {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
116 {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
117 {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
118 {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"},
119 {RPCResult::Type::NUM, "bytessent", "The total bytes sent"},
120 {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
121 {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
122 {RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"},
123 {RPCResult::Type::NUM, "pingtime", "ping time (if available)"},
124 {RPCResult::Type::NUM, "minping", "minimum observed ping time (if any at all)"},
125 {RPCResult::Type::NUM, "pingwait", "ping wait (if non-zero)"},
126 {RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
127 {RPCResult::Type::STR, "subver", "The string version"},
128 {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
129 {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
130 "(DEPRECATED, returned only if the config option -deprecatedrpc=getpeerinfo_addnode is passed)"},
131 {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
132 "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
133 "best capture connection behaviors."},
134 {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
135 {RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"},
136 {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
137 {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"},
138 {RPCResult::Type::ARR, "inflight", "",
139 {
140 {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
141 }},
142 {RPCResult::Type::BOOL, "whitelisted", /* optional */ true, "Whether the peer is whitelisted with default permissions\n"
143 "(DEPRECATED, returned only if config option -deprecatedrpc=whitelisted is passed)"},
144 {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer",
145 {
146 {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"},
147 }},
148 {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
149 {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
150 {
151 {RPCResult::Type::NUM, "msg", "The total bytes sent aggregated by message type\n"
152 "When a message type is not listed in this json object, the bytes sent are 0.\n"
153 "Only known message types can appear as keys in the object."}
154 }},
155 {RPCResult::Type::OBJ, "bytesrecv_per_msg", "",
156 {
157 {RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n"
158 "When a message type is not listed in this json object, the bytes received are 0.\n"
159 "Only known message types can appear as keys in the object and all bytes received\n"
160 "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
161 }},
162 }},
163 }},
164 },
165 RPCExamples{
166 HelpExampleCli("getpeerinfo", "")
167 + HelpExampleRpc("getpeerinfo", "")
168 },
169 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
170 {
171 NodeContext& node = EnsureNodeContext(request.context);
172 if(!node.connman)
173 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
174
175 std::vector<CNodeStats> vstats;
176 node.connman->GetNodeStats(vstats);
177
178 UniValue ret(UniValue::VARR);
179
180 for (const CNodeStats& stats : vstats) {
181 UniValue obj(UniValue::VOBJ);
182 CNodeStateStats statestats;
183 bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
184 obj.pushKV("id", stats.nodeid);
185 obj.pushKV("addr", stats.addrName);
186 if (stats.addrBind.IsValid()) {
187 obj.pushKV("addrbind", stats.addrBind.ToString());
188 }
189 if (!(stats.addrLocal.empty())) {
190 obj.pushKV("addrlocal", stats.addrLocal);
191 }
192 obj.pushKV("network", stats.m_network);
193 if (stats.m_mapped_as != 0) {
194 obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
195 }
196 obj.pushKV("services", strprintf("%016x", stats.nServices));
197 obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
198 obj.pushKV("relaytxes", stats.fRelayTxes);
199 obj.pushKV("lastsend", stats.nLastSend);
200 obj.pushKV("lastrecv", stats.nLastRecv);
201 obj.pushKV("last_transaction", stats.nLastTXTime);
202 obj.pushKV("last_block", stats.nLastBlockTime);
203 obj.pushKV("bytessent", stats.nSendBytes);
204 obj.pushKV("bytesrecv", stats.nRecvBytes);
205 obj.pushKV("conntime", stats.nTimeConnected);
206 obj.pushKV("timeoffset", stats.nTimeOffset);
207 if (stats.m_ping_usec > 0) {
208 obj.pushKV("pingtime", ((double)stats.m_ping_usec) / 1e6);
209 }
210 if (stats.m_min_ping_usec < std::numeric_limits<int64_t>::max()) {
211 obj.pushKV("minping", ((double)stats.m_min_ping_usec) / 1e6);
212 }
213 if (stats.m_ping_wait_usec > 0) {
214 obj.pushKV("pingwait", ((double)stats.m_ping_wait_usec) / 1e6);
215 }
216 obj.pushKV("version", stats.nVersion);
217 // Use the sanitized form of subver here, to avoid tricksy remote peers from
218 // corrupting or modifying the JSON output by putting special characters in
219 // their ver message.
220 obj.pushKV("subver", stats.cleanSubVer);
221 obj.pushKV("inbound", stats.fInbound);
222 if (IsDeprecatedRPCEnabled("getpeerinfo_addnode")) {
223 // addnode is deprecated in v0.21 for removal in v0.22
224 obj.pushKV("addnode", stats.m_manual_connection);
225 }
226 obj.pushKV("startingheight", stats.nStartingHeight);
227 if (fStateStats) {
228 if (IsDeprecatedRPCEnabled("banscore")) {
229 // banscore is deprecated in v0.21 for removal in v0.22
230 obj.pushKV("banscore", statestats.m_misbehavior_score);
231 }
232 obj.pushKV("synced_headers", statestats.nSyncHeight);
233 obj.pushKV("synced_blocks", statestats.nCommonHeight);
234 UniValue heights(UniValue::VARR);
235 for (const int height : statestats.vHeightInFlight) {
236 heights.push_back(height);
237 }
238 obj.pushKV("inflight", heights);
239 }
240 if (IsDeprecatedRPCEnabled("whitelisted")) {
241 // whitelisted is deprecated in v0.21 for removal in v0.22
242 obj.pushKV("whitelisted", stats.m_legacyWhitelisted);
243 }
244 UniValue permissions(UniValue::VARR);
245 for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
246 permissions.push_back(permission);
247 }
248 obj.pushKV("permissions", permissions);
249 obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
250
251 UniValue sendPerMsgCmd(UniValue::VOBJ);
252 for (const auto& i : stats.mapSendBytesPerMsgCmd) {
253 if (i.second > 0)
254 sendPerMsgCmd.pushKV(i.first, i.second);
255 }
256 obj.pushKV("bytessent_per_msg", sendPerMsgCmd);
257
258 UniValue recvPerMsgCmd(UniValue::VOBJ);
259 for (const auto& i : stats.mapRecvBytesPerMsgCmd) {
260 if (i.second > 0)
261 recvPerMsgCmd.pushKV(i.first, i.second);
262 }
263 obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
264 obj.pushKV("connection_type", stats.m_conn_type_string);
265
266 ret.push_back(obj);
267 }
268
269 return ret;
270 },
271 };
272 }
273
addnode()274 static RPCHelpMan addnode()
275 {
276 return RPCHelpMan{"addnode",
277 "\nAttempts to add or remove a node from the addnode list.\n"
278 "Or try a connection to a node once.\n"
279 "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"
280 "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n",
281 {
282 {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The node (see getpeerinfo for nodes)"},
283 {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},
284 },
285 RPCResult{RPCResult::Type::NONE, "", ""},
286 RPCExamples{
287 HelpExampleCli("addnode", "\"192.168.0.6:8334\" \"onetry\"")
288 + HelpExampleRpc("addnode", "\"192.168.0.6:8334\", \"onetry\"")
289 },
290 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
291 {
292 std::string strCommand;
293 if (!request.params[1].isNull())
294 strCommand = request.params[1].get_str();
295 if (request.fHelp || request.params.size() != 2 ||
296 (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
297 throw std::runtime_error(
298 self.ToString());
299
300 NodeContext& node = EnsureNodeContext(request.context);
301 if(!node.connman)
302 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
303
304 std::string strNode = request.params[0].get_str();
305
306 if (strCommand == "onetry")
307 {
308 CAddress addr;
309 node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
310 return NullUniValue;
311 }
312
313 if (strCommand == "add")
314 {
315 if(!node.connman->AddNode(strNode))
316 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
317 }
318 else if(strCommand == "remove")
319 {
320 if(!node.connman->RemoveAddedNode(strNode))
321 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously.");
322 }
323
324 return NullUniValue;
325 },
326 };
327 }
328
disconnectnode()329 static RPCHelpMan disconnectnode()
330 {
331 return RPCHelpMan{"disconnectnode",
332 "\nImmediately disconnects from the specified peer node.\n"
333 "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
334 "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
335 {
336 {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"},
337 {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
338 },
339 RPCResult{RPCResult::Type::NONE, "", ""},
340 RPCExamples{
341 HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
342 + HelpExampleCli("disconnectnode", "\"\" 1")
343 + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
344 + HelpExampleRpc("disconnectnode", "\"\", 1")
345 },
346 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
347 {
348 NodeContext& node = EnsureNodeContext(request.context);
349 if(!node.connman)
350 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
351
352 bool success;
353 const UniValue &address_arg = request.params[0];
354 const UniValue &id_arg = request.params[1];
355
356 if (!address_arg.isNull() && id_arg.isNull()) {
357 /* handle disconnect-by-address */
358 success = node.connman->DisconnectNode(address_arg.get_str());
359 } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {
360 /* handle disconnect-by-id */
361 NodeId nodeid = (NodeId) id_arg.get_int64();
362 success = node.connman->DisconnectNode(nodeid);
363 } else {
364 throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided.");
365 }
366
367 if (!success) {
368 throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
369 }
370
371 return NullUniValue;
372 },
373 };
374 }
375
getaddednodeinfo()376 static RPCHelpMan getaddednodeinfo()
377 {
378 return RPCHelpMan{"getaddednodeinfo",
379 "\nReturns information about the given added node, or all added nodes\n"
380 "(note that onetry addnodes are not listed here)\n",
381 {
382 {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
383 },
384 RPCResult{
385 RPCResult::Type::ARR, "", "",
386 {
387 {RPCResult::Type::OBJ, "", "",
388 {
389 {RPCResult::Type::STR, "addednode", "The node IP address or name (as provided to addnode)"},
390 {RPCResult::Type::BOOL, "connected", "If connected"},
391 {RPCResult::Type::ARR, "addresses", "Only when connected = true",
392 {
393 {RPCResult::Type::OBJ, "", "",
394 {
395 {RPCResult::Type::STR, "address", "The server IP and port we're connected to"},
396 {RPCResult::Type::STR, "connected", "connection, inbound or outbound"},
397 }},
398 }},
399 }},
400 }
401 },
402 RPCExamples{
403 HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
404 + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
405 },
406 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
407 {
408 NodeContext& node = EnsureNodeContext(request.context);
409 if(!node.connman)
410 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
411
412 std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo();
413
414 if (!request.params[0].isNull()) {
415 bool found = false;
416 for (const AddedNodeInfo& info : vInfo) {
417 if (info.strAddedNode == request.params[0].get_str()) {
418 vInfo.assign(1, info);
419 found = true;
420 break;
421 }
422 }
423 if (!found) {
424 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
425 }
426 }
427
428 UniValue ret(UniValue::VARR);
429
430 for (const AddedNodeInfo& info : vInfo) {
431 UniValue obj(UniValue::VOBJ);
432 obj.pushKV("addednode", info.strAddedNode);
433 obj.pushKV("connected", info.fConnected);
434 UniValue addresses(UniValue::VARR);
435 if (info.fConnected) {
436 UniValue address(UniValue::VOBJ);
437 address.pushKV("address", info.resolvedAddress.ToString());
438 address.pushKV("connected", info.fInbound ? "inbound" : "outbound");
439 addresses.push_back(address);
440 }
441 obj.pushKV("addresses", addresses);
442 ret.push_back(obj);
443 }
444
445 return ret;
446 },
447 };
448 }
449
getnettotals()450 static RPCHelpMan getnettotals()
451 {
452 return RPCHelpMan{"getnettotals",
453 "\nReturns information about network traffic, including bytes in, bytes out,\n"
454 "and current time.\n",
455 {},
456 RPCResult{
457 RPCResult::Type::OBJ, "", "",
458 {
459 {RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
460 {RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
461 {RPCResult::Type::NUM_TIME, "timemillis", "Current " + UNIX_EPOCH_TIME + " in milliseconds"},
462 {RPCResult::Type::OBJ, "uploadtarget", "",
463 {
464 {RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
465 {RPCResult::Type::NUM, "target", "Target in bytes"},
466 {RPCResult::Type::BOOL, "target_reached", "True if target is reached"},
467 {RPCResult::Type::BOOL, "serve_historical_blocks", "True if serving historical blocks"},
468 {RPCResult::Type::NUM, "bytes_left_in_cycle", "Bytes left in current time cycle"},
469 {RPCResult::Type::NUM, "time_left_in_cycle", "Seconds left in current time cycle"},
470 }},
471 }
472 },
473 RPCExamples{
474 HelpExampleCli("getnettotals", "")
475 + HelpExampleRpc("getnettotals", "")
476 },
477 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
478 {
479 NodeContext& node = EnsureNodeContext(request.context);
480 if(!node.connman)
481 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
482
483 UniValue obj(UniValue::VOBJ);
484 obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv());
485 obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent());
486 obj.pushKV("timemillis", GetTimeMillis());
487
488 UniValue outboundLimit(UniValue::VOBJ);
489 outboundLimit.pushKV("timeframe", node.connman->GetMaxOutboundTimeframe());
490 outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget());
491 outboundLimit.pushKV("target_reached", node.connman->OutboundTargetReached(false));
492 outboundLimit.pushKV("serve_historical_blocks", !node.connman->OutboundTargetReached(true));
493 outboundLimit.pushKV("bytes_left_in_cycle", node.connman->GetOutboundTargetBytesLeft());
494 outboundLimit.pushKV("time_left_in_cycle", node.connman->GetMaxOutboundTimeLeftInCycle());
495 obj.pushKV("uploadtarget", outboundLimit);
496 return obj;
497 },
498 };
499 }
500
GetNetworksInfo()501 static UniValue GetNetworksInfo()
502 {
503 UniValue networks(UniValue::VARR);
504 for (int n = 0; n < NET_MAX; ++n) {
505 enum Network network = static_cast<enum Network>(n);
506 if (network == NET_UNROUTABLE || network == NET_I2P || network == NET_CJDNS || network == NET_INTERNAL) continue;
507 proxyType proxy;
508 UniValue obj(UniValue::VOBJ);
509 GetProxy(network, proxy);
510 obj.pushKV("name", GetNetworkName(network));
511 obj.pushKV("limited", !IsReachable(network));
512 obj.pushKV("reachable", IsReachable(network));
513 obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string());
514 obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials);
515 networks.push_back(obj);
516 }
517 return networks;
518 }
519
getnetworkinfo()520 static RPCHelpMan getnetworkinfo()
521 {
522 return RPCHelpMan{"getnetworkinfo",
523 "Returns an object containing various state info regarding P2P networking.\n",
524 {},
525 RPCResult{
526 RPCResult::Type::OBJ, "", "",
527 {
528 {RPCResult::Type::NUM, "version", "the server version"},
529 {RPCResult::Type::STR, "subversion", "the server subversion string"},
530 {RPCResult::Type::NUM, "protocolversion", "the protocol version"},
531 {RPCResult::Type::STR_HEX, "localservices", "the services we offer to the network"},
532 {RPCResult::Type::ARR, "localservicesnames", "the services we offer to the network, in human-readable form",
533 {
534 {RPCResult::Type::STR, "SERVICE_NAME", "the service name"},
535 }},
536 {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
537 {RPCResult::Type::NUM, "timeoffset", "the time offset"},
538 {RPCResult::Type::NUM, "connections", "the total number of connections"},
539 {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"},
540 {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"},
541 {RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"},
542 {RPCResult::Type::ARR, "networks", "information per network",
543 {
544 {RPCResult::Type::OBJ, "", "",
545 {
546 {RPCResult::Type::STR, "name", "network (ipv4, ipv6 or onion)"},
547 {RPCResult::Type::BOOL, "limited", "is the network limited using -onlynet?"},
548 {RPCResult::Type::BOOL, "reachable", "is the network reachable?"},
549 {RPCResult::Type::STR, "proxy", "(\"host:port\") the proxy that is used for this network, or empty if none"},
550 {RPCResult::Type::BOOL, "proxy_randomize_credentials", "Whether randomized credentials are used"},
551 }},
552 }},
553 {RPCResult::Type::NUM, "relayfee", "minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB"},
554 {RPCResult::Type::NUM, "incrementalfee", "minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB"},
555 {RPCResult::Type::ARR, "localaddresses", "list of local addresses",
556 {
557 {RPCResult::Type::OBJ, "", "",
558 {
559 {RPCResult::Type::STR, "address", "network address"},
560 {RPCResult::Type::NUM, "port", "network port"},
561 {RPCResult::Type::NUM, "score", "relative score"},
562 }},
563 }},
564 {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
565 }
566 },
567 RPCExamples{
568 HelpExampleCli("getnetworkinfo", "")
569 + HelpExampleRpc("getnetworkinfo", "")
570 },
571 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
572 {
573 LOCK(cs_main);
574 UniValue obj(UniValue::VOBJ);
575 obj.pushKV("version", CLIENT_VERSION);
576 obj.pushKV("subversion", strSubVersion);
577 obj.pushKV("protocolversion",PROTOCOL_VERSION);
578 NodeContext& node = EnsureNodeContext(request.context);
579 if (node.connman) {
580 ServiceFlags services = node.connman->GetLocalServices();
581 obj.pushKV("localservices", strprintf("%016x", services));
582 obj.pushKV("localservicesnames", GetServicesNames(services));
583 }
584 obj.pushKV("localrelay", g_relay_txes);
585 obj.pushKV("timeoffset", GetTimeOffset());
586 if (node.connman) {
587 obj.pushKV("networkactive", node.connman->GetNetworkActive());
588 obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
589 obj.pushKV("connections_in", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_IN));
590 obj.pushKV("connections_out", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT));
591 }
592 obj.pushKV("networks", GetNetworksInfo());
593 obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
594 obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
595 UniValue localAddresses(UniValue::VARR);
596 {
597 LOCK(cs_mapLocalHost);
598 for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
599 {
600 UniValue rec(UniValue::VOBJ);
601 rec.pushKV("address", item.first.ToString());
602 rec.pushKV("port", item.second.nPort);
603 rec.pushKV("score", item.second.nScore);
604 localAddresses.push_back(rec);
605 }
606 }
607 obj.pushKV("localaddresses", localAddresses);
608 obj.pushKV("warnings", GetWarnings(false).original);
609 return obj;
610 },
611 };
612 }
613
setban()614 static RPCHelpMan setban()
615 {
616 return RPCHelpMan{"setban",
617 "\nAttempts to add or remove an IP/Subnet from the banned list.\n",
618 {
619 {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
620 {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"},
621 {"bantime", RPCArg::Type::NUM, /* default */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
622 {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME},
623 },
624 RPCResult{RPCResult::Type::NONE, "", ""},
625 RPCExamples{
626 HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
627 + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
628 + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
629 },
630 [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue
631 {
632 std::string strCommand;
633 if (!request.params[1].isNull())
634 strCommand = request.params[1].get_str();
635 if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) {
636 throw std::runtime_error(help.ToString());
637 }
638 NodeContext& node = EnsureNodeContext(request.context);
639 if (!node.banman) {
640 throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
641 }
642
643 CSubNet subNet;
644 CNetAddr netAddr;
645 bool isSubnet = false;
646
647 if (request.params[0].get_str().find('/') != std::string::npos)
648 isSubnet = true;
649
650 if (!isSubnet) {
651 CNetAddr resolved;
652 LookupHost(request.params[0].get_str(), resolved, false);
653 netAddr = resolved;
654 }
655 else
656 LookupSubNet(request.params[0].get_str(), subNet);
657
658 if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
659 throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
660
661 if (strCommand == "add")
662 {
663 if (isSubnet ? node.banman->IsBanned(subNet) : node.banman->IsBanned(netAddr)) {
664 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
665 }
666
667 int64_t banTime = 0; //use standard bantime if not specified
668 if (!request.params[2].isNull())
669 banTime = request.params[2].get_int64();
670
671 bool absolute = false;
672 if (request.params[3].isTrue())
673 absolute = true;
674
675 if (isSubnet) {
676 node.banman->Ban(subNet, banTime, absolute);
677 if (node.connman) {
678 node.connman->DisconnectNode(subNet);
679 }
680 } else {
681 node.banman->Ban(netAddr, banTime, absolute);
682 if (node.connman) {
683 node.connman->DisconnectNode(netAddr);
684 }
685 }
686 }
687 else if(strCommand == "remove")
688 {
689 if (!( isSubnet ? node.banman->Unban(subNet) : node.banman->Unban(netAddr) )) {
690 throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned.");
691 }
692 }
693 return NullUniValue;
694 },
695 };
696 }
697
listbanned()698 static RPCHelpMan listbanned()
699 {
700 return RPCHelpMan{"listbanned",
701 "\nList all manually banned IPs/Subnets.\n",
702 {},
703 RPCResult{RPCResult::Type::ARR, "", "",
704 {
705 {RPCResult::Type::OBJ, "", "",
706 {
707 {RPCResult::Type::STR, "address", ""},
708 {RPCResult::Type::NUM_TIME, "banned_until", ""},
709 {RPCResult::Type::NUM_TIME, "ban_created", ""},
710 }},
711 }},
712 RPCExamples{
713 HelpExampleCli("listbanned", "")
714 + HelpExampleRpc("listbanned", "")
715 },
716 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
717 {
718 NodeContext& node = EnsureNodeContext(request.context);
719 if(!node.banman) {
720 throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
721 }
722
723 banmap_t banMap;
724 node.banman->GetBanned(banMap);
725
726 UniValue bannedAddresses(UniValue::VARR);
727 for (const auto& entry : banMap)
728 {
729 const CBanEntry& banEntry = entry.second;
730 UniValue rec(UniValue::VOBJ);
731 rec.pushKV("address", entry.first.ToString());
732 rec.pushKV("banned_until", banEntry.nBanUntil);
733 rec.pushKV("ban_created", banEntry.nCreateTime);
734
735 bannedAddresses.push_back(rec);
736 }
737
738 return bannedAddresses;
739 },
740 };
741 }
742
clearbanned()743 static RPCHelpMan clearbanned()
744 {
745 return RPCHelpMan{"clearbanned",
746 "\nClear all banned IPs.\n",
747 {},
748 RPCResult{RPCResult::Type::NONE, "", ""},
749 RPCExamples{
750 HelpExampleCli("clearbanned", "")
751 + HelpExampleRpc("clearbanned", "")
752 },
753 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
754 {
755 NodeContext& node = EnsureNodeContext(request.context);
756 if (!node.banman) {
757 throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
758 }
759
760 node.banman->ClearBanned();
761
762 return NullUniValue;
763 },
764 };
765 }
766
setnetworkactive()767 static RPCHelpMan setnetworkactive()
768 {
769 return RPCHelpMan{"setnetworkactive",
770 "\nDisable/enable all p2p network activity.\n",
771 {
772 {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"},
773 },
774 RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"},
775 RPCExamples{""},
776 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
777 {
778 NodeContext& node = EnsureNodeContext(request.context);
779 if (!node.connman) {
780 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
781 }
782
783 node.connman->SetNetworkActive(request.params[0].get_bool());
784
785 return node.connman->GetNetworkActive();
786 },
787 };
788 }
789
getnodeaddresses()790 static RPCHelpMan getnodeaddresses()
791 {
792 return RPCHelpMan{"getnodeaddresses",
793 "\nReturn known addresses which can potentially be used to find new nodes in the network\n",
794 {
795 {"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."},
796 },
797 RPCResult{
798 RPCResult::Type::ARR, "", "",
799 {
800 {RPCResult::Type::OBJ, "", "",
801 {
802 {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " of when the node was last seen"},
803 {RPCResult::Type::NUM, "services", "The services offered"},
804 {RPCResult::Type::STR, "address", "The address of the node"},
805 {RPCResult::Type::NUM, "port", "The port of the node"},
806 }},
807 }
808 },
809 RPCExamples{
810 HelpExampleCli("getnodeaddresses", "8")
811 + HelpExampleRpc("getnodeaddresses", "8")
812 },
813 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
814 {
815 NodeContext& node = EnsureNodeContext(request.context);
816 if (!node.connman) {
817 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
818 }
819
820 int count = 1;
821 if (!request.params[0].isNull()) {
822 count = request.params[0].get_int();
823 if (count < 0) {
824 throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
825 }
826 }
827 // returns a shuffled list of CAddress
828 std::vector<CAddress> vAddr = node.connman->GetAddresses(count, /* max_pct */ 0);
829 UniValue ret(UniValue::VARR);
830
831 for (const CAddress& addr : vAddr) {
832 UniValue obj(UniValue::VOBJ);
833 obj.pushKV("time", (int)addr.nTime);
834 obj.pushKV("services", (uint64_t)addr.nServices);
835 obj.pushKV("address", addr.ToStringIP());
836 obj.pushKV("port", addr.GetPort());
837 ret.push_back(obj);
838 }
839 return ret;
840 },
841 };
842 }
843
addpeeraddress()844 static RPCHelpMan addpeeraddress()
845 {
846 return RPCHelpMan{"addpeeraddress",
847 "\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n",
848 {
849 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},
850 {"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"},
851 },
852 RPCResult{
853 RPCResult::Type::OBJ, "", "",
854 {
855 {RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager"},
856 },
857 },
858 RPCExamples{
859 HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333")
860 + HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333")
861 },
862 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
863 {
864 NodeContext& node = EnsureNodeContext(request.context);
865 if (!node.connman) {
866 throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
867 }
868
869 UniValue obj(UniValue::VOBJ);
870
871 std::string addr_string = request.params[0].get_str();
872 uint16_t port = request.params[1].get_int();
873
874 CNetAddr net_addr;
875 if (!LookupHost(addr_string, net_addr, false)) {
876 obj.pushKV("success", false);
877 return obj;
878 }
879 CAddress address = CAddress({net_addr, port}, ServiceFlags(NODE_NETWORK|NODE_WITNESS));
880 address.nTime = GetAdjustedTime();
881 // The source address is set equal to the address. This is equivalent to the peer
882 // announcing itself.
883 if (!node.connman->AddNewAddresses({address}, address)) {
884 obj.pushKV("success", false);
885 return obj;
886 }
887
888 obj.pushKV("success", true);
889 return obj;
890 },
891 };
892 }
893
RegisterNetRPCCommands(CRPCTable & t)894 void RegisterNetRPCCommands(CRPCTable &t)
895 {
896 // clang-format off
897 static const CRPCCommand commands[] =
898 { // category name actor (function) argNames
899 // --------------------- ------------------------ ----------------------- ----------
900 { "network", "getconnectioncount", &getconnectioncount, {} },
901 { "network", "ping", &ping, {} },
902 { "network", "getpeerinfo", &getpeerinfo, {} },
903 { "network", "addnode", &addnode, {"node","command"} },
904 { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
905 { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
906 { "network", "getnettotals", &getnettotals, {} },
907 { "network", "getnetworkinfo", &getnetworkinfo, {} },
908 { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
909 { "network", "listbanned", &listbanned, {} },
910 { "network", "clearbanned", &clearbanned, {} },
911 { "network", "setnetworkactive", &setnetworkactive, {"state"} },
912 { "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
913 { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
914 };
915 // clang-format on
916 for (const auto& c : commands) {
917 t.appendCommand(c.name, &c);
918 }
919 }
920