1 // Copyright (c) 2009-2019 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 <chainparams.h>
9 #include <clientversion.h>
10 #include <core_io.h>
11 #include <net.h>
12 #include <net_processing.h>
13 #include <netbase.h>
14 #include <policy/policy.h>
15 #include <rpc/protocol.h>
16 #include <rpc/util.h>
17 #include <sync.h>
18 #include <timedata.h>
19 #include <ui_interface.h>
20 #include <util/strencodings.h>
21 #include <util/system.h>
22 #include <validation.h>
23 #include <version.h>
24 #include <warnings.h>
25 
26 #include <univalue.h>
27 
getconnectioncount(const JSONRPCRequest & request)28 static UniValue getconnectioncount(const JSONRPCRequest& request)
29 {
30     if (request.fHelp || request.params.size() != 0)
31         throw std::runtime_error(
32             RPCHelpMan{"getconnectioncount",
33                 "\nReturns the number of connections to other nodes.\n",
34                 {},
35                 RPCResult{
36             "n          (numeric) The connection count\n"
37                 },
38                 RPCExamples{
39                     HelpExampleCli("getconnectioncount", "")
40             + HelpExampleRpc("getconnectioncount", "")
41                 },
42             }.ToString());
43 
44     if(!g_connman)
45         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
46 
47     return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
48 }
49 
ping(const JSONRPCRequest & request)50 static UniValue ping(const JSONRPCRequest& request)
51 {
52     if (request.fHelp || request.params.size() != 0)
53         throw std::runtime_error(
54             RPCHelpMan{"ping",
55                 "\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
56                 "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
57                 "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n",
58                 {},
59                 RPCResults{},
60                 RPCExamples{
61                     HelpExampleCli("ping", "")
62             + HelpExampleRpc("ping", "")
63                 },
64             }.ToString());
65 
66     if(!g_connman)
67         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
68 
69     // Request that each node send a ping during next message processing pass
70     g_connman->ForEachNode([](CNode* pnode) {
71         pnode->fPingQueued = true;
72     });
73     return NullUniValue;
74 }
75 
getpeerinfo(const JSONRPCRequest & request)76 static UniValue getpeerinfo(const JSONRPCRequest& request)
77 {
78     if (request.fHelp || request.params.size() != 0)
79         throw std::runtime_error(
80             RPCHelpMan{"getpeerinfo",
81                 "\nReturns data about each connected network node as a json array of objects.\n",
82                 {},
83                 RPCResult{
84             "[\n"
85             "  {\n"
86             "    \"id\": n,                   (numeric) Peer index\n"
87             "    \"addr\":\"host:port\",      (string) The IP address and port of the peer\n"
88             "    \"addrbind\":\"ip:port\",    (string) Bind address of the connection to the peer\n"
89             "    \"addrlocal\":\"ip:port\",   (string) Local address as reported by the peer\n"
90             "    \"services\":\"xxxxxxxxxxxxxxxx\",   (string) The services offered\n"
91             "    \"relaytxes\":true|false,    (boolean) Whether peer has asked us to relay transactions to it\n"
92             "    \"lastsend\": ttt,           (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
93             "    \"lastrecv\": ttt,           (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
94             "    \"bytessent\": n,            (numeric) The total bytes sent\n"
95             "    \"bytesrecv\": n,            (numeric) The total bytes received\n"
96             "    \"conntime\": ttt,           (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
97             "    \"timeoffset\": ttt,         (numeric) The time offset in seconds\n"
98             "    \"pingtime\": n,             (numeric) ping time (if available)\n"
99             "    \"minping\": n,              (numeric) minimum observed ping time (if any at all)\n"
100             "    \"pingwait\": n,             (numeric) ping wait (if non-zero)\n"
101             "    \"version\": v,              (numeric) The peer version, such as 70001\n"
102             "    \"subver\": \"/Satoshi:0.8.5/\",  (string) The string version\n"
103             "    \"inbound\": true|false,     (boolean) Inbound (true) or Outbound (false)\n"
104             "    \"addnode\": true|false,     (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
105             "    \"startingheight\": n,       (numeric) The starting height (block) of the peer\n"
106             "    \"banscore\": n,             (numeric) The ban score\n"
107             "    \"synced_headers\": n,       (numeric) The last header we have in common with this peer\n"
108             "    \"synced_blocks\": n,        (numeric) The last block we have in common with this peer\n"
109             "    \"inflight\": [\n"
110             "       n,                        (numeric) The heights of blocks we're currently asking from this peer\n"
111             "       ...\n"
112             "    ],\n"
113             "    \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
114             "    \"minfeefilter\": n,         (numeric) The minimum fee rate for transactions this peer accepts\n"
115             "    \"bytessent_per_msg\": {\n"
116             "       \"msg\": n,               (numeric) The total bytes sent aggregated by message type\n"
117             "                               When a message type is not listed in this json object, the bytes sent are 0.\n"
118             "                               Only known message types can appear as keys in the object.\n"
119             "       ...\n"
120             "    },\n"
121             "    \"bytesrecv_per_msg\": {\n"
122             "       \"msg\": n,               (numeric) The total bytes received aggregated by message type\n"
123             "                               When a message type is not listed in this json object, the bytes received are 0.\n"
124             "                               Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'.\n"
125             "       ...\n"
126             "    }\n"
127             "  }\n"
128             "  ,...\n"
129             "]\n"
130                 },
131                 RPCExamples{
132                     HelpExampleCli("getpeerinfo", "")
133             + HelpExampleRpc("getpeerinfo", "")
134                 },
135             }.ToString());
136 
137     if(!g_connman)
138         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
139 
140     std::vector<CNodeStats> vstats;
141     g_connman->GetNodeStats(vstats);
142 
143     UniValue ret(UniValue::VARR);
144 
145     for (const CNodeStats& stats : vstats) {
146         UniValue obj(UniValue::VOBJ);
147         CNodeStateStats statestats;
148         bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
149         obj.pushKV("id", stats.nodeid);
150         obj.pushKV("addr", stats.addrName);
151         if (!(stats.addrLocal.empty()))
152             obj.pushKV("addrlocal", stats.addrLocal);
153         if (stats.addrBind.IsValid())
154             obj.pushKV("addrbind", stats.addrBind.ToString());
155         obj.pushKV("services", strprintf("%016x", stats.nServices));
156         obj.pushKV("relaytxes", stats.fRelayTxes);
157         obj.pushKV("lastsend", stats.nLastSend);
158         obj.pushKV("lastrecv", stats.nLastRecv);
159         obj.pushKV("bytessent", stats.nSendBytes);
160         obj.pushKV("bytesrecv", stats.nRecvBytes);
161         obj.pushKV("conntime", stats.nTimeConnected);
162         obj.pushKV("timeoffset", stats.nTimeOffset);
163         if (stats.dPingTime > 0.0)
164             obj.pushKV("pingtime", stats.dPingTime);
165         if (stats.dMinPing < static_cast<double>(std::numeric_limits<int64_t>::max())/1e6)
166             obj.pushKV("minping", stats.dMinPing);
167         if (stats.dPingWait > 0.0)
168             obj.pushKV("pingwait", stats.dPingWait);
169         obj.pushKV("version", stats.nVersion);
170         // Use the sanitized form of subver here, to avoid tricksy remote peers from
171         // corrupting or modifying the JSON output by putting special characters in
172         // their ver message.
173         obj.pushKV("subver", stats.cleanSubVer);
174         obj.pushKV("inbound", stats.fInbound);
175         obj.pushKV("addnode", stats.m_manual_connection);
176         obj.pushKV("startingheight", stats.nStartingHeight);
177         if (fStateStats) {
178             obj.pushKV("banscore", statestats.nMisbehavior);
179             obj.pushKV("synced_headers", statestats.nSyncHeight);
180             obj.pushKV("synced_blocks", statestats.nCommonHeight);
181             UniValue heights(UniValue::VARR);
182             for (const int height : statestats.vHeightInFlight) {
183                 heights.push_back(height);
184             }
185             obj.pushKV("inflight", heights);
186         }
187         obj.pushKV("whitelisted", stats.fWhitelisted);
188         obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
189 
190         UniValue sendPerMsgCmd(UniValue::VOBJ);
191         for (const auto& i : stats.mapSendBytesPerMsgCmd) {
192             if (i.second > 0)
193                 sendPerMsgCmd.pushKV(i.first, i.second);
194         }
195         obj.pushKV("bytessent_per_msg", sendPerMsgCmd);
196 
197         UniValue recvPerMsgCmd(UniValue::VOBJ);
198         for (const auto& i : stats.mapRecvBytesPerMsgCmd) {
199             if (i.second > 0)
200                 recvPerMsgCmd.pushKV(i.first, i.second);
201         }
202         obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
203 
204         ret.push_back(obj);
205     }
206 
207     return ret;
208 }
209 
addnode(const JSONRPCRequest & request)210 static UniValue addnode(const JSONRPCRequest& request)
211 {
212     std::string strCommand;
213     if (!request.params[1].isNull())
214         strCommand = request.params[1].get_str();
215     if (request.fHelp || request.params.size() != 2 ||
216         (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
217         throw std::runtime_error(
218             RPCHelpMan{"addnode",
219                 "\nAttempts to add or remove a node from the addnode list.\n"
220                 "Or try a connection to a node once.\n"
221                 "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"
222                 "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n",
223                 {
224                     {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The node (see getpeerinfo for nodes)"},
225                     {"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"},
226                 },
227                 RPCResults{},
228                 RPCExamples{
229                     HelpExampleCli("addnode", "\"192.168.0.6:9333\" \"onetry\"")
230             + HelpExampleRpc("addnode", "\"192.168.0.6:9333\", \"onetry\"")
231                 },
232             }.ToString());
233 
234     if(!g_connman)
235         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
236 
237     std::string strNode = request.params[0].get_str();
238 
239     if (strCommand == "onetry")
240     {
241         CAddress addr;
242         g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true);
243         return NullUniValue;
244     }
245 
246     if (strCommand == "add")
247     {
248         if(!g_connman->AddNode(strNode))
249             throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
250     }
251     else if(strCommand == "remove")
252     {
253         if(!g_connman->RemoveAddedNode(strNode))
254             throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
255     }
256 
257     return NullUniValue;
258 }
259 
disconnectnode(const JSONRPCRequest & request)260 static UniValue disconnectnode(const JSONRPCRequest& request)
261 {
262     if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3)
263         throw std::runtime_error(
264             RPCHelpMan{"disconnectnode",
265                 "\nImmediately disconnects from the specified peer node.\n"
266                 "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
267                 "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
268                 {
269                     {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"},
270                     {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
271                 },
272                 RPCResults{},
273                 RPCExamples{
274                     HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
275             + HelpExampleCli("disconnectnode", "\"\" 1")
276             + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
277             + HelpExampleRpc("disconnectnode", "\"\", 1")
278                 },
279             }.ToString());
280 
281     if(!g_connman)
282         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
283 
284     bool success;
285     const UniValue &address_arg = request.params[0];
286     const UniValue &id_arg = request.params[1];
287 
288     if (!address_arg.isNull() && id_arg.isNull()) {
289         /* handle disconnect-by-address */
290         success = g_connman->DisconnectNode(address_arg.get_str());
291     } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {
292         /* handle disconnect-by-id */
293         NodeId nodeid = (NodeId) id_arg.get_int64();
294         success = g_connman->DisconnectNode(nodeid);
295     } else {
296         throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided.");
297     }
298 
299     if (!success) {
300         throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
301     }
302 
303     return NullUniValue;
304 }
305 
getaddednodeinfo(const JSONRPCRequest & request)306 static UniValue getaddednodeinfo(const JSONRPCRequest& request)
307 {
308     if (request.fHelp || request.params.size() > 1)
309         throw std::runtime_error(
310             RPCHelpMan{"getaddednodeinfo",
311                 "\nReturns information about the given added node, or all added nodes\n"
312                 "(note that onetry addnodes are not listed here)\n",
313                 {
314                     {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
315                 },
316                 RPCResult{
317             "[\n"
318             "  {\n"
319             "    \"addednode\" : \"192.168.0.201\",   (string) The node IP address or name (as provided to addnode)\n"
320             "    \"connected\" : true|false,          (boolean) If connected\n"
321             "    \"addresses\" : [                    (list of objects) Only when connected = true\n"
322             "       {\n"
323             "         \"address\" : \"192.168.0.201:9333\",  (string) The litecoin server IP and port we're connected to\n"
324             "         \"connected\" : \"outbound\"           (string) connection, inbound or outbound\n"
325             "       }\n"
326             "     ]\n"
327             "  }\n"
328             "  ,...\n"
329             "]\n"
330                 },
331                 RPCExamples{
332                     HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
333             + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
334                 },
335             }.ToString());
336 
337     if(!g_connman)
338         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
339 
340     std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
341 
342     if (!request.params[0].isNull()) {
343         bool found = false;
344         for (const AddedNodeInfo& info : vInfo) {
345             if (info.strAddedNode == request.params[0].get_str()) {
346                 vInfo.assign(1, info);
347                 found = true;
348                 break;
349             }
350         }
351         if (!found) {
352             throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
353         }
354     }
355 
356     UniValue ret(UniValue::VARR);
357 
358     for (const AddedNodeInfo& info : vInfo) {
359         UniValue obj(UniValue::VOBJ);
360         obj.pushKV("addednode", info.strAddedNode);
361         obj.pushKV("connected", info.fConnected);
362         UniValue addresses(UniValue::VARR);
363         if (info.fConnected) {
364             UniValue address(UniValue::VOBJ);
365             address.pushKV("address", info.resolvedAddress.ToString());
366             address.pushKV("connected", info.fInbound ? "inbound" : "outbound");
367             addresses.push_back(address);
368         }
369         obj.pushKV("addresses", addresses);
370         ret.push_back(obj);
371     }
372 
373     return ret;
374 }
375 
getnettotals(const JSONRPCRequest & request)376 static UniValue getnettotals(const JSONRPCRequest& request)
377 {
378     if (request.fHelp || request.params.size() > 0)
379         throw std::runtime_error(
380             RPCHelpMan{"getnettotals",
381                 "\nReturns information about network traffic, including bytes in, bytes out,\n"
382                 "and current time.\n",
383                 {},
384                 RPCResult{
385             "{\n"
386             "  \"totalbytesrecv\": n,   (numeric) Total bytes received\n"
387             "  \"totalbytessent\": n,   (numeric) Total bytes sent\n"
388             "  \"timemillis\": t,       (numeric) Current UNIX time in milliseconds\n"
389             "  \"uploadtarget\":\n"
390             "  {\n"
391             "    \"timeframe\": n,                         (numeric) Length of the measuring timeframe in seconds\n"
392             "    \"target\": n,                            (numeric) Target in bytes\n"
393             "    \"target_reached\": true|false,           (boolean) True if target is reached\n"
394             "    \"serve_historical_blocks\": true|false,  (boolean) True if serving historical blocks\n"
395             "    \"bytes_left_in_cycle\": t,               (numeric) Bytes left in current time cycle\n"
396             "    \"time_left_in_cycle\": t                 (numeric) Seconds left in current time cycle\n"
397             "  }\n"
398             "}\n"
399                 },
400                 RPCExamples{
401                     HelpExampleCli("getnettotals", "")
402             + HelpExampleRpc("getnettotals", "")
403                 },
404             }.ToString());
405     if(!g_connman)
406         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
407 
408     UniValue obj(UniValue::VOBJ);
409     obj.pushKV("totalbytesrecv", g_connman->GetTotalBytesRecv());
410     obj.pushKV("totalbytessent", g_connman->GetTotalBytesSent());
411     obj.pushKV("timemillis", GetTimeMillis());
412 
413     UniValue outboundLimit(UniValue::VOBJ);
414     outboundLimit.pushKV("timeframe", g_connman->GetMaxOutboundTimeframe());
415     outboundLimit.pushKV("target", g_connman->GetMaxOutboundTarget());
416     outboundLimit.pushKV("target_reached", g_connman->OutboundTargetReached(false));
417     outboundLimit.pushKV("serve_historical_blocks", !g_connman->OutboundTargetReached(true));
418     outboundLimit.pushKV("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft());
419     outboundLimit.pushKV("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle());
420     obj.pushKV("uploadtarget", outboundLimit);
421     return obj;
422 }
423 
GetNetworksInfo()424 static UniValue GetNetworksInfo()
425 {
426     UniValue networks(UniValue::VARR);
427     for(int n=0; n<NET_MAX; ++n)
428     {
429         enum Network network = static_cast<enum Network>(n);
430         if(network == NET_UNROUTABLE || network == NET_INTERNAL)
431             continue;
432         proxyType proxy;
433         UniValue obj(UniValue::VOBJ);
434         GetProxy(network, proxy);
435         obj.pushKV("name", GetNetworkName(network));
436         obj.pushKV("limited", !IsReachable(network));
437         obj.pushKV("reachable", IsReachable(network));
438         obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string());
439         obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials);
440         networks.push_back(obj);
441     }
442     return networks;
443 }
444 
getnetworkinfo(const JSONRPCRequest & request)445 static UniValue getnetworkinfo(const JSONRPCRequest& request)
446 {
447     if (request.fHelp || request.params.size() != 0)
448         throw std::runtime_error(
449             RPCHelpMan{"getnetworkinfo",
450                 "Returns an object containing various state info regarding P2P networking.\n",
451                 {},
452                 RPCResult{
453             "{\n"
454             "  \"version\": xxxxx,                      (numeric) the server version\n"
455             "  \"subversion\": \"/Satoshi:x.x.x/\",     (string) the server subversion string\n"
456             "  \"protocolversion\": xxxxx,              (numeric) the protocol version\n"
457             "  \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
458             "  \"localrelay\": true|false,              (bool) true if transaction relay is requested from peers\n"
459             "  \"timeoffset\": xxxxx,                   (numeric) the time offset\n"
460             "  \"connections\": xxxxx,                  (numeric) the number of connections\n"
461             "  \"networkactive\": true|false,           (bool) whether p2p networking is enabled\n"
462             "  \"networks\": [                          (array) information per network\n"
463             "  {\n"
464             "    \"name\": \"xxx\",                     (string) network (ipv4, ipv6 or onion)\n"
465             "    \"limited\": true|false,               (boolean) is the network limited using -onlynet?\n"
466             "    \"reachable\": true|false,             (boolean) is the network reachable?\n"
467             "    \"proxy\": \"host:port\"               (string) the proxy that is used for this network, or empty if none\n"
468             "    \"proxy_randomize_credentials\": true|false,  (string) Whether randomized credentials are used\n"
469             "  }\n"
470             "  ,...\n"
471             "  ],\n"
472             "  \"relayfee\": x.xxxxxxxx,                (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
473             "  \"incrementalfee\": x.xxxxxxxx,          (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n"
474             "  \"localaddresses\": [                    (array) list of local addresses\n"
475             "  {\n"
476             "    \"address\": \"xxxx\",                 (string) network address\n"
477             "    \"port\": xxx,                         (numeric) network port\n"
478             "    \"score\": xxx                         (numeric) relative score\n"
479             "  }\n"
480             "  ,...\n"
481             "  ]\n"
482             "  \"warnings\": \"...\"                    (string) any network and blockchain warnings\n"
483             "}\n"
484                 },
485                 RPCExamples{
486                     HelpExampleCli("getnetworkinfo", "")
487             + HelpExampleRpc("getnetworkinfo", "")
488                 },
489             }.ToString());
490 
491     LOCK(cs_main);
492     UniValue obj(UniValue::VOBJ);
493     obj.pushKV("version",       CLIENT_VERSION);
494     obj.pushKV("subversion",    strSubVersion);
495     obj.pushKV("protocolversion",PROTOCOL_VERSION);
496     if(g_connman)
497         obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices()));
498     obj.pushKV("localrelay", g_relay_txes);
499     obj.pushKV("timeoffset",    GetTimeOffset());
500     if (g_connman) {
501         obj.pushKV("networkactive", g_connman->GetNetworkActive());
502         obj.pushKV("connections",   (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
503     }
504     obj.pushKV("networks",      GetNetworksInfo());
505     obj.pushKV("relayfee",      ValueFromAmount(::minRelayTxFee.GetFeePerK()));
506     obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
507     UniValue localAddresses(UniValue::VARR);
508     {
509         LOCK(cs_mapLocalHost);
510         for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
511         {
512             UniValue rec(UniValue::VOBJ);
513             rec.pushKV("address", item.first.ToString());
514             rec.pushKV("port", item.second.nPort);
515             rec.pushKV("score", item.second.nScore);
516             localAddresses.push_back(rec);
517         }
518     }
519     obj.pushKV("localaddresses", localAddresses);
520     obj.pushKV("warnings",       GetWarnings("statusbar"));
521     return obj;
522 }
523 
setban(const JSONRPCRequest & request)524 static UniValue setban(const JSONRPCRequest& request)
525 {
526     const RPCHelpMan help{"setban",
527                 "\nAttempts to add or remove an IP/Subnet from the banned list.\n",
528                 {
529                     {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
530                     {"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"},
531                     {"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)"},
532                     {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"},
533                 },
534                 RPCResults{},
535                 RPCExamples{
536                     HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
537                             + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
538                             + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
539                 },
540     };
541     std::string strCommand;
542     if (!request.params[1].isNull())
543         strCommand = request.params[1].get_str();
544     if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) {
545         throw std::runtime_error(help.ToString());
546     }
547     if (!g_banman) {
548         throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
549     }
550 
551     CSubNet subNet;
552     CNetAddr netAddr;
553     bool isSubnet = false;
554 
555     if (request.params[0].get_str().find('/') != std::string::npos)
556         isSubnet = true;
557 
558     if (!isSubnet) {
559         CNetAddr resolved;
560         LookupHost(request.params[0].get_str().c_str(), resolved, false);
561         netAddr = resolved;
562     }
563     else
564         LookupSubNet(request.params[0].get_str().c_str(), subNet);
565 
566     if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
567         throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
568 
569     if (strCommand == "add")
570     {
571         if (isSubnet ? g_banman->IsBanned(subNet) : g_banman->IsBanned(netAddr)) {
572             throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
573         }
574 
575         int64_t banTime = 0; //use standard bantime if not specified
576         if (!request.params[2].isNull())
577             banTime = request.params[2].get_int64();
578 
579         bool absolute = false;
580         if (request.params[3].isTrue())
581             absolute = true;
582 
583         if (isSubnet) {
584             g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute);
585             if (g_connman) {
586                 g_connman->DisconnectNode(subNet);
587             }
588         } else {
589             g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
590             if (g_connman) {
591                 g_connman->DisconnectNode(netAddr);
592             }
593         }
594     }
595     else if(strCommand == "remove")
596     {
597         if (!( isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr) )) {
598             throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
599         }
600     }
601     return NullUniValue;
602 }
603 
listbanned(const JSONRPCRequest & request)604 static UniValue listbanned(const JSONRPCRequest& request)
605 {
606     if (request.fHelp || request.params.size() != 0)
607         throw std::runtime_error(
608             RPCHelpMan{"listbanned",
609                 "\nList all banned IPs/Subnets.\n",
610                 {},
611                 RPCResults{},
612                 RPCExamples{
613                     HelpExampleCli("listbanned", "")
614                             + HelpExampleRpc("listbanned", "")
615                 },
616             }.ToString());
617 
618     if(!g_banman) {
619         throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
620     }
621 
622     banmap_t banMap;
623     g_banman->GetBanned(banMap);
624 
625     UniValue bannedAddresses(UniValue::VARR);
626     for (const auto& entry : banMap)
627     {
628         const CBanEntry& banEntry = entry.second;
629         UniValue rec(UniValue::VOBJ);
630         rec.pushKV("address", entry.first.ToString());
631         rec.pushKV("banned_until", banEntry.nBanUntil);
632         rec.pushKV("ban_created", banEntry.nCreateTime);
633         rec.pushKV("ban_reason", banEntry.banReasonToString());
634 
635         bannedAddresses.push_back(rec);
636     }
637 
638     return bannedAddresses;
639 }
640 
clearbanned(const JSONRPCRequest & request)641 static UniValue clearbanned(const JSONRPCRequest& request)
642 {
643     if (request.fHelp || request.params.size() != 0)
644         throw std::runtime_error(
645             RPCHelpMan{"clearbanned",
646                 "\nClear all banned IPs.\n",
647                 {},
648                 RPCResults{},
649                 RPCExamples{
650                     HelpExampleCli("clearbanned", "")
651                             + HelpExampleRpc("clearbanned", "")
652                 },
653             }.ToString());
654     if (!g_banman) {
655         throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
656     }
657 
658     g_banman->ClearBanned();
659 
660     return NullUniValue;
661 }
662 
setnetworkactive(const JSONRPCRequest & request)663 static UniValue setnetworkactive(const JSONRPCRequest& request)
664 {
665     if (request.fHelp || request.params.size() != 1) {
666         throw std::runtime_error(
667             RPCHelpMan{"setnetworkactive",
668                 "\nDisable/enable all p2p network activity.\n",
669                 {
670                     {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"},
671                 },
672                 RPCResults{},
673                 RPCExamples{""},
674             }.ToString()
675         );
676     }
677 
678     if (!g_connman) {
679         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
680     }
681 
682     g_connman->SetNetworkActive(request.params[0].get_bool());
683 
684     return g_connman->GetNetworkActive();
685 }
686 
getnodeaddresses(const JSONRPCRequest & request)687 static UniValue getnodeaddresses(const JSONRPCRequest& request)
688 {
689     if (request.fHelp || request.params.size() > 1) {
690         throw std::runtime_error(
691             RPCHelpMan{"getnodeaddresses",
692                 "\nReturn known addresses which can potentially be used to find new nodes in the network\n",
693                 {
694                     {"count", RPCArg::Type::NUM, /* default */ "1", "How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."},
695                 },
696                 RPCResult{
697             "[\n"
698             "  {\n"
699             "    \"time\": ttt,                (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n"
700             "    \"services\": n,              (numeric) The services offered\n"
701             "    \"address\": \"host\",          (string) The address of the node\n"
702             "    \"port\": n                   (numeric) The port of the node\n"
703             "  }\n"
704             "  ,....\n"
705             "]\n"
706                 },
707                 RPCExamples{
708                     HelpExampleCli("getnodeaddresses", "8")
709             + HelpExampleRpc("getnodeaddresses", "8")
710                 },
711             }.ToString());
712     }
713     if (!g_connman) {
714         throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
715     }
716 
717     int count = 1;
718     if (!request.params[0].isNull()) {
719         count = request.params[0].get_int();
720         if (count <= 0) {
721             throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
722         }
723     }
724     // returns a shuffled list of CAddress
725     std::vector<CAddress> vAddr = g_connman->GetAddresses();
726     UniValue ret(UniValue::VARR);
727 
728     int address_return_count = std::min<int>(count, vAddr.size());
729     for (int i = 0; i < address_return_count; ++i) {
730         UniValue obj(UniValue::VOBJ);
731         const CAddress& addr = vAddr[i];
732         obj.pushKV("time", (int)addr.nTime);
733         obj.pushKV("services", (uint64_t)addr.nServices);
734         obj.pushKV("address", addr.ToStringIP());
735         obj.pushKV("port", addr.GetPort());
736         ret.push_back(obj);
737     }
738     return ret;
739 }
740 
741 // clang-format off
742 static const CRPCCommand commands[] =
743 { //  category              name                      actor (function)         argNames
744   //  --------------------- ------------------------  -----------------------  ----------
745     { "network",            "getconnectioncount",     &getconnectioncount,     {} },
746     { "network",            "ping",                   &ping,                   {} },
747     { "network",            "getpeerinfo",            &getpeerinfo,            {} },
748     { "network",            "addnode",                &addnode,                {"node","command"} },
749     { "network",            "disconnectnode",         &disconnectnode,         {"address", "nodeid"} },
750     { "network",            "getaddednodeinfo",       &getaddednodeinfo,       {"node"} },
751     { "network",            "getnettotals",           &getnettotals,           {} },
752     { "network",            "getnetworkinfo",         &getnetworkinfo,         {} },
753     { "network",            "setban",                 &setban,                 {"subnet", "command", "bantime", "absolute"} },
754     { "network",            "listbanned",             &listbanned,             {} },
755     { "network",            "clearbanned",            &clearbanned,            {} },
756     { "network",            "setnetworkactive",       &setnetworkactive,       {"state"} },
757     { "network",            "getnodeaddresses",       &getnodeaddresses,       {"count"} },
758 };
759 // clang-format on
760 
RegisterNetRPCCommands(CRPCTable & t)761 void RegisterNetRPCCommands(CRPCTable &t)
762 {
763     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
764         t.appendCommand(commands[vcidx].name, &commands[vcidx]);
765 }
766