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