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