aboutsummaryrefslogtreecommitdiff
path: root/src/rpcserver.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-04-28 13:48:26 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-05-09 16:45:57 +0200
commitee21912510275c7a0ebeafd2ff553c1db4a4f460 (patch)
treed9144f4ca37cac29da5e957e6fae647729396df1 /src/rpcserver.cpp
parente16be73753d870c5ce77094d3a402bbe8e3bf542 (diff)
downloadbitcoin-ee21912510275c7a0ebeafd2ff553c1db4a4f460.tar.xz
rpc: Use netmasks instead of wildcards for IP address matching
`-rpcallowip` currently has a wacky wildcard-based format. After this commit it will accept the more standard format, for example: - Ranges with netmask 127.0.0.0/255.255.255.0, ::/0 - Ranges with cidr 12.3.4.5/24, 12:34:56:78:9a:bc:de:00/112 - Loose IPs ::1, 127.0.0.1 Trying to use the old *?-based format will result in an error message at launch.
Diffstat (limited to 'src/rpcserver.cpp')
-rw-r--r--src/rpcserver.cpp63
1 files changed, 49 insertions, 14 deletions
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index f78cb420f4..5740cca13a 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -38,6 +38,7 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
static ssl::context* rpc_ssl_context = NULL;
static boost::thread_group* rpc_worker_group = NULL;
static boost::asio::io_service::work *rpc_dummy_work = NULL;
+static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected,
@@ -358,25 +359,34 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
stream << HTTPReply(nStatus, strReply, false) << std::flush;
}
-bool ClientAllowed(const boost::asio::ip::address& address)
+// Convert boost::asio address to CNetAddr
+static CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address)
{
+ CNetAddr netaddr;
// Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
if (address.is_v6()
&& (address.to_v6().is_v4_compatible()
|| address.to_v6().is_v4_mapped()))
- return ClientAllowed(address.to_v6().to_v4());
-
- if (address == asio::ip::address_v4::loopback()
- || address == asio::ip::address_v6::loopback()
- || (address.is_v4()
- // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet)
- && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000))
- return true;
-
- const string strAddress = address.to_string();
- const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
- BOOST_FOREACH(string strAllow, vAllow)
- if (WildcardMatch(strAddress, strAllow))
+ address = address.to_v6().to_v4();
+
+ if(address.is_v4())
+ {
+ boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
+ netaddr.SetRaw(NET_IPV4, &bytes[0]);
+ }
+ else
+ {
+ boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
+ netaddr.SetRaw(NET_IPV6, &bytes[0]);
+ }
+ return netaddr;
+}
+
+bool ClientAllowed(const boost::asio::ip::address& address)
+{
+ CNetAddr netaddr = BoostAsioToCNetAddr(address);
+ BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
+ if (subnet.Match(netaddr))
return true;
return false;
}
@@ -502,6 +512,31 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
void StartRPCThreads()
{
+ rpc_allow_subnets.clear();
+ rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
+ rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
+ if (mapMultiArgs.count("-rpcallowip"))
+ {
+ const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
+ BOOST_FOREACH(string strAllow, vAllow)
+ {
+ CSubNet subnet(strAllow);
+ if(!subnet.IsValid())
+ {
+ uiInterface.ThreadSafeMessageBox(
+ strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
+ "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return;
+ }
+ rpc_allow_subnets.push_back(subnet);
+ }
+ }
+ std::string strAllowed;
+ BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
+ strAllowed += subnet.ToString() + " ";
+ LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
+
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
if (((mapArgs["-rpcpassword"] == "") ||
(mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())