diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 845a9b73c..7ebe6f935 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,782 +1,802 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "rpc/server.h" #include "chainparams.h" #include "clientversion.h" #include "config.h" #include "net.h" #include "net_processing.h" #include "netbase.h" #include "policy/policy.h" #include "protocol.h" #include "sync.h" #include "timedata.h" #include "ui_interface.h" #include "util.h" #include "utilstrencodings.h" #include "validation.h" #include "version.h" #include static UniValue getconnectioncount(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "getconnectioncount\n" "\nReturns the number of connections to other nodes.\n" "\nResult:\n" "n (numeric) The connection count\n" "\nExamples:\n" + HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "")); + } - if (!g_connman) + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } - return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL); + return int(g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); } static UniValue ping(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "ping\n" "\nRequests that a ping be sent to all other nodes, to measure " "ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are " "decimal seconds.\n" "Ping command is handled in queue with all other commands, so it " "measures processing backlog, not just network ping.\n" "\nExamples:\n" + HelpExampleCli("ping", "") + HelpExampleRpc("ping", "")); + } - if (!g_connman) + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } // Request that each node send a ping during next message processing pass g_connman->ForEachNode([](CNode *pnode) { pnode->fPingQueued = true; }); return NullUniValue; } static UniValue getpeerinfo(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "getpeerinfo\n" "\nReturns data about each connected network node as a json array " "of objects.\n" "\nResult:\n" "[\n" " {\n" " \"id\": n, (numeric) Peer index\n" " \"addr\":\"host:port\", (string) The ip address and port " "of the peer\n" " \"addrbind\":\"ip:port\", (string) Bind address of the " "connection to the peer\n" " \"addrlocal\":\"ip:port\", (string) Local address as " "reported by the peer\n" " \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services " "offered\n" " \"relaytxes\":true|false, (boolean) Whether peer has asked " "us to relay transactions to it\n" " \"lastsend\": ttt, (numeric) The time in seconds " "since epoch (Jan 1 1970 GMT) of the last send\n" " \"lastrecv\": ttt, (numeric) The time in seconds " "since epoch (Jan 1 1970 GMT) of the last receive\n" " \"bytessent\": n, (numeric) The total bytes sent\n" " \"bytesrecv\": n, (numeric) The total bytes " "received\n" " \"conntime\": ttt, (numeric) The connection time in " "seconds since epoch (Jan 1 1970 GMT)\n" " \"timeoffset\": ttt, (numeric) The time offset in " "seconds\n" " \"pingtime\": n, (numeric) ping time (if " "available)\n" " \"minping\": n, (numeric) minimum observed ping " "time (if any at all)\n" " \"pingwait\": n, (numeric) ping wait (if " "non-zero)\n" " \"version\": v, (numeric) The peer version, such " "as 7001\n" " \"subver\": \"/Satoshi:0.8.5/\", (string) The string " "version\n" " \"inbound\": true|false, (boolean) Inbound (true) or " "Outbound (false)\n" " \"addnode\": true|false, (boolean) Whether connection was " "due to addnode/-connect or if it was an automatic/inbound " "connection\n" " \"startingheight\": n, (numeric) The starting height " "(block) of the peer\n" " \"banscore\": n, (numeric) The ban score\n" " \"synced_headers\": n, (numeric) The last header we " "have in common with this peer\n" " \"synced_blocks\": n, (numeric) The last block we have " "in common with this peer\n" " \"inflight\": [\n" " n, (numeric) The heights of blocks " "we're currently asking from this peer\n" " ...\n" " ],\n" " \"whitelisted\": true|false, (boolean) Whether the peer is " "whitelisted\n" " \"bytessent_per_msg\": {\n" " \"addr\": n, (numeric) The total bytes sent " "aggregated by message type\n" " ...\n" " },\n" " \"bytesrecv_per_msg\": {\n" " \"addr\": n, (numeric) The total bytes " "received aggregated by message type\n" " ...\n" " }\n" " }\n" " ,...\n" "]\n" "\nExamples:\n" + HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "")); } if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } std::vector vstats; g_connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); for (const CNodeStats &stats : vstats) { UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); obj.push_back(Pair("id", stats.nodeid)); obj.push_back(Pair("addr", stats.addrName)); if (!(stats.addrLocal.empty())) { obj.push_back(Pair("addrlocal", stats.addrLocal)); } if (stats.addrBind.IsValid()) { obj.push_back(Pair("addrbind", stats.addrBind.ToString())); } obj.push_back(Pair("services", strprintf("%016x", stats.nServices))); obj.push_back(Pair("relaytxes", stats.fRelayTxes)); obj.push_back(Pair("lastsend", stats.nLastSend)); obj.push_back(Pair("lastrecv", stats.nLastRecv)); obj.push_back(Pair("bytessent", stats.nSendBytes)); obj.push_back(Pair("bytesrecv", stats.nRecvBytes)); obj.push_back(Pair("conntime", stats.nTimeConnected)); obj.push_back(Pair("timeoffset", stats.nTimeOffset)); if (stats.dPingTime > 0.0) { obj.push_back(Pair("pingtime", stats.dPingTime)); } if (stats.dMinPing < std::numeric_limits::max() / 1e6) { obj.push_back(Pair("minping", stats.dMinPing)); } if (stats.dPingWait > 0.0) { obj.push_back(Pair("pingwait", stats.dPingWait)); } obj.push_back(Pair("version", stats.nVersion)); // Use the sanitized form of subver here, to avoid tricksy remote peers // from corrupting or modifying the JSON output by putting special // characters in their ver message. obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); obj.push_back(Pair("addnode", stats.m_manual_connection)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); UniValue heights(UniValue::VARR); for (int height : statestats.vHeightInFlight) { heights.push_back(height); } obj.push_back(Pair("inflight", heights)); } obj.push_back(Pair("whitelisted", stats.fWhitelisted)); UniValue sendPerMsgCmd(UniValue::VOBJ); for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) { if (i.second > 0) { sendPerMsgCmd.push_back(Pair(i.first, i.second)); } } obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd)); UniValue recvPerMsgCmd(UniValue::VOBJ); for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) { if (i.second > 0) { recvPerMsgCmd.push_back(Pair(i.first, i.second)); } } obj.push_back(Pair("bytesrecv_per_msg", recvPerMsgCmd)); ret.push_back(obj); } return ret; } static UniValue addnode(const Config &config, const JSONRPCRequest &request) { std::string strCommand; - if (request.params.size() == 2) strCommand = request.params[1].get_str(); + if (request.params.size() == 2) { + strCommand = request.params[1].get_str(); + } + if (request.fHelp || request.params.size() != 2 || (strCommand != "onetry" && strCommand != "add" && - strCommand != "remove")) + strCommand != "remove")) { throw std::runtime_error( "addnode \"node\" \"add|remove|onetry\"\n" "\nAttempts add or remove a node from the addnode list.\n" "Or try a connection to a node once.\n" "Nodes added using addnode (or -connect) are protected from DoS " "disconnection and are not required to be\n" "full nodes/support SegWit as other outbound peers are (though " "such peers will not be synced from).\n" "\nArguments:\n" "1. \"node\" (string, required) The node (see getpeerinfo for " "nodes)\n" "2. \"command\" (string, required) '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\n" "\nExamples:\n" + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")); + } - if (!g_connman) + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } std::string strNode = request.params[0].get_str(); if (strCommand == "onetry") { CAddress addr; g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true); return NullUniValue; } - if (strCommand == "add") { - if (!g_connman->AddNode(strNode)) - throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, - "Error: Node already added"); - } else if (strCommand == "remove") { - if (!g_connman->RemoveAddedNode(strNode)) - throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, - "Error: Node has not been added."); + if ((strCommand == "add") && (!g_connman->AddNode(strNode))) { + throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, + "Error: Node already added"); + } else if ((strCommand == "remove") && + (!g_connman->RemoveAddedNode(strNode))) { + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, + "Error: Node has not been added."); } return NullUniValue; } static UniValue disconnectnode(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3) { throw std::runtime_error( "disconnectnode \"[address]\" [nodeid]\n" "\nImmediately disconnects from the specified peer node.\n" "\nStrictly one out of 'address' and 'nodeid' can be provided to " "identify the node.\n" "\nTo disconnect by nodeid, either set 'address' to the empty " "string, or call using the named 'nodeid' argument only.\n" "\nArguments:\n" "1. \"address\" (string, optional) The IP address/port of the " "node\n" "2. \"nodeid\" (number, optional) The node ID (see " "getpeerinfo for node IDs)\n" "\nExamples:\n" + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleCli("disconnectnode", "\"\" 1") + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleRpc("disconnectnode", "\"\", 1")); } if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } bool success; const UniValue &address_arg = request.params[0]; const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1]; if (!address_arg.isNull() && id_arg.isNull()) { /* handle disconnect-by-address */ success = g_connman->DisconnectNode(address_arg.get_str()); } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { /* handle disconnect-by-id */ NodeId nodeid = (NodeId)id_arg.get_int64(); success = g_connman->DisconnectNode(nodeid); } else { throw JSONRPCError( RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); } if (!success) { throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); } return NullUniValue; } static UniValue getaddednodeinfo(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() > 1) + if (request.fHelp || request.params.size() > 1) { throw std::runtime_error( "getaddednodeinfo ( \"node\" )\n" "\nReturns information about the given added node, or all added " "nodes\n" "(note that onetry addnodes are not listed here)\n" "\nArguments:\n" "1. \"node\" (string, optional) If provided, return information " "about this specific node, otherwise all nodes are returned.\n" "\nResult:\n" "[\n" " {\n" " \"addednode\" : \"192.168.0.201\", (string) The node ip " "address or name (as provided to addnode)\n" " \"connected\" : true|false, (boolean) If connected\n" " \"addresses\" : [ (list of objects) Only " "when connected = true\n" " {\n" " \"address\" : \"192.168.0.201:8333\", (string) The " "bitcoin server IP and port we're connected to\n" " \"connected\" : \"outbound\" (string) " "connection, inbound or outbound\n" " }\n" " ]\n" " }\n" " ,...\n" "]\n" "\nExamples:\n" + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")); + } - if (!g_connman) + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } std::vector vInfo = g_connman->GetAddedNodeInfo(); if (request.params.size() == 1) { bool found = false; for (const AddedNodeInfo &info : vInfo) { if (info.strAddedNode == request.params[0].get_str()) { vInfo.assign(1, info); found = true; break; } } if (!found) { throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } } UniValue ret(UniValue::VARR); for (const AddedNodeInfo &info : vInfo) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", info.strAddedNode)); obj.push_back(Pair("connected", info.fConnected)); UniValue addresses(UniValue::VARR); if (info.fConnected) { UniValue address(UniValue::VOBJ); address.push_back(Pair("address", info.resolvedAddress.ToString())); address.push_back( Pair("connected", info.fInbound ? "inbound" : "outbound")); addresses.push_back(address); } obj.push_back(Pair("addresses", addresses)); ret.push_back(obj); } return ret; } static UniValue getnettotals(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() > 0) + if (request.fHelp || request.params.size() > 0) { throw std::runtime_error( "getnettotals\n" "\nReturns information about network traffic, including bytes in, " "bytes out,\n" "and current time.\n" "\nResult:\n" "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" " \"timemillis\": t, (numeric) Current UNIX time in " "milliseconds\n" " \"uploadtarget\":\n" " {\n" " \"timeframe\": n, (numeric) Length of " "the measuring timeframe in seconds\n" " \"target\": n, (numeric) Target in " "bytes\n" " \"target_reached\": true|false, (boolean) True if " "target is reached\n" " \"serve_historical_blocks\": true|false, (boolean) True if " "serving historical blocks\n" " \"bytes_left_in_cycle\": t, (numeric) Bytes " "left in current time cycle\n" " \"time_left_in_cycle\": t (numeric) Seconds " "left in current time cycle\n" " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "")); - if (!g_connman) + } + + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } UniValue obj(UniValue::VOBJ); obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); UniValue outboundLimit(UniValue::VOBJ); outboundLimit.push_back( Pair("timeframe", g_connman->GetMaxOutboundTimeframe())); outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget())); outboundLimit.push_back( Pair("target_reached", g_connman->OutboundTargetReached(false))); outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true))); outboundLimit.push_back( Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft())); outboundLimit.push_back( Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle())); obj.push_back(Pair("uploadtarget", outboundLimit)); return obj; } static UniValue GetNetworksInfo() { UniValue networks(UniValue::VARR); for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast(n); if (network == NET_UNROUTABLE || network == NET_INTERNAL) { continue; } proxyType proxy; UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); obj.push_back(Pair("reachable", IsReachable(network))); obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())); obj.push_back( Pair("proxy_randomize_credentials", proxy.randomize_credentials)); networks.push_back(obj); } return networks; } static UniValue getnetworkinfo(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( "getnetworkinfo\n" "Returns an object containing various state info regarding P2P " "networking.\n" "\nResult:\n" "{\n" " \"version\": xxxxx, (numeric) the server " "version\n" " \"subversion\": \"/Satoshi:x.x.x/\", (string) the server " "subversion string\n" " \"protocolversion\": xxxxx, (numeric) the protocol " "version\n" " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services " "we offer to the network\n" " \"localrelay\": true|false, (bool) true if " "transaction relay is requested from peers\n" " \"timeoffset\": xxxxx, (numeric) the time " "offset\n" " \"connections\": xxxxx, (numeric) the number " "of connections\n" " \"networkactive\": true|false, (bool) whether p2p " "networking is enabled\n" " \"networks\": [ (array) information " "per network\n" " {\n" " \"name\": \"xxx\", (string) network " "(ipv4, ipv6 or onion)\n" " \"limited\": true|false, (boolean) is the " "network limited using -onlynet?\n" " \"reachable\": true|false, (boolean) is the " "network reachable?\n" " \"proxy\": \"host:port\" (string) the proxy " "that is used for this network, or empty if none\n" " \"proxy_randomize_credentials\": true|false, (string) " "Whether randomized credentials are used\n" " }\n" " ,...\n" " ],\n" " \"relayfee\": x.xxxxxxxx, (numeric) minimum " "relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n" " \"excessutxocharge\": x.xxxxxxxx, (numeric) minimum " "charge for excess utxos in " + CURRENCY_UNIT + "\n" " \"localaddresses\": [ " "(array) list of local addresses\n" " {\n" " \"address\": \"xxxx\", " "(string) network address\n" " \"port\": xxx, " "(numeric) network port\n" " \"score\": xxx " "(numeric) relative score\n" " }\n" " ,...\n" " ]\n" " \"warnings\": \"...\" " "(string) any network warnings\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "")); + } LOCK(cs_main); UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", userAgent(config))); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); - if (g_connman) + if (g_connman) { obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices()))); + } obj.push_back(Pair("localrelay", fRelayTxes)); obj.push_back(Pair("timeoffset", GetTimeOffset())); if (g_connman) { obj.push_back(Pair("networkactive", g_connman->GetNetworkActive())); - obj.push_back( - Pair("connections", - (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); + obj.push_back(Pair("connections", int(g_connman->GetNodeCount( + CConnman::CONNECTIONS_ALL)))); } obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(config.GetMinFeePerKB().GetFeePerK()))); obj.push_back(Pair("excessutxocharge", ValueFromAmount(config.GetExcessUTXOCharge()))); UniValue localAddresses(UniValue::VARR); { LOCK(cs_mapLocalHost); for (const std::pair &item : mapLocalHost) { UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", item.first.ToString())); rec.push_back(Pair("port", item.second.nPort)); rec.push_back(Pair("score", item.second.nScore)); localAddresses.push_back(rec); } } obj.push_back(Pair("localaddresses", localAddresses)); obj.push_back(Pair("warnings", GetWarnings("statusbar"))); return obj; } static UniValue setban(const Config &config, const JSONRPCRequest &request) { std::string strCommand; if (request.params.size() >= 2) { strCommand = request.params[1].get_str(); } if (request.fHelp || request.params.size() < 2 || (strCommand != "add" && strCommand != "remove")) { throw std::runtime_error( "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n" "\nAttempts add or remove a IP/Subnet from the banned list.\n" "\nArguments:\n" "1. \"subnet\" (string, required) The IP/Subnet (see " "getpeerinfo for nodes ip) with a optional netmask (default is /32 " "= single ip)\n" "2. \"command\" (string, required) 'add' to add a IP/Subnet " "to the list, 'remove' to remove a IP/Subnet from the list\n" "3. \"bantime\" (numeric, optional) 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)\n" "4. \"absolute\" (boolean, optional) If set, the bantime must " "be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n" "\nExamples:\n" + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")); } if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } CSubNet subNet; CNetAddr netAddr; bool isSubnet = false; if (request.params[0].get_str().find("/") != std::string::npos) { isSubnet = true; } if (!isSubnet) { CNetAddr resolved; LookupHost(request.params[0].get_str().c_str(), resolved, false); netAddr = resolved; } else { LookupSubNet(request.params[0].get_str().c_str(), subNet); } if (!(isSubnet ? subNet.IsValid() : netAddr.IsValid())) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet"); } if (strCommand == "add") { if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); } // Use standard bantime if not specified. int64_t banTime = 0; if (request.params.size() >= 3 && !request.params[2].isNull()) { banTime = request.params[2].get_int64(); } bool absolute = false; if (request.params.size() == 4 && request.params[3].isTrue()) { absolute = true; } isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); } else if (strCommand == "remove") { if (!(isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr))) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet " "was not previously banned."); } } return NullUniValue; } static UniValue listbanned(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error("listbanned\n" "\nList all banned IPs/Subnets.\n" "\nExamples:\n" + HelpExampleCli("listbanned", "") + HelpExampleRpc("listbanned", "")); + } - if (!g_connman) + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } banmap_t banMap; g_connman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) { CBanEntry banEntry = (*it).second; UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", (*it).first.ToString())); rec.push_back(Pair("banned_until", banEntry.nBanUntil)); rec.push_back(Pair("ban_created", banEntry.nCreateTime)); rec.push_back(Pair("ban_reason", banEntry.banReasonToString())); bannedAddresses.push_back(rec); } return bannedAddresses; } static UniValue clearbanned(const Config &config, const JSONRPCRequest &request) { - if (request.fHelp || request.params.size() != 0) + if (request.fHelp || request.params.size() != 0) { throw std::runtime_error("clearbanned\n" "\nClear all banned IPs.\n" "\nExamples:\n" + HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "")); - if (!g_connman) + } + + if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } g_connman->ClearBanned(); return NullUniValue; } static UniValue setnetworkactive(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "setnetworkactive true|false\n" "\nDisable/enable all p2p network activity.\n" "\nArguments:\n" "1. \"state\" (boolean, required) true to " "enable networking, false to disable\n"); } if (!g_connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } g_connman->SetNetworkActive(request.params[0].get_bool()); return g_connman->GetNetworkActive(); } // clang-format off static const ContextFreeRPCCommand commands[] = { // category name actor (function) okSafeMode // ------------------- ------------------------ ---------------------- ---------- { "network", "getconnectioncount", getconnectioncount, true, {} }, { "network", "ping", ping, true, {} }, { "network", "getpeerinfo", getpeerinfo, true, {} }, { "network", "addnode", addnode, true, {"node","command"} }, { "network", "disconnectnode", disconnectnode, true, {"address", "nodeid"} }, { "network", "getaddednodeinfo", getaddednodeinfo, true, {"node"} }, { "network", "getnettotals", getnettotals, true, {} }, { "network", "getnetworkinfo", getnetworkinfo, true, {} }, { "network", "setban", setban, true, {"subnet", "command", "bantime", "absolute"} }, { "network", "listbanned", listbanned, true, {} }, { "network", "clearbanned", clearbanned, true, {} }, { "network", "setnetworkactive", setnetworkactive, true, {"state"} }, }; // clang-format on void RegisterNetRPCCommands(CRPCTable &t) { - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { t.appendCommand(commands[vcidx].name, &commands[vcidx]); + } }