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