Skip to content

Commit ee21912

Browse files
committed
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.
1 parent e16be73 commit ee21912

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

src/rpcserver.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
3838
static ssl::context* rpc_ssl_context = NULL;
3939
static boost::thread_group* rpc_worker_group = NULL;
4040
static boost::asio::io_service::work *rpc_dummy_work = NULL;
41+
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
4142

4243
void RPCTypeCheck(const Array& params,
4344
const list<Value_type>& typesExpected,
@@ -358,25 +359,34 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
358359
stream << HTTPReply(nStatus, strReply, false) << std::flush;
359360
}
360361

361-
bool ClientAllowed(const boost::asio::ip::address& address)
362+
// Convert boost::asio address to CNetAddr
363+
static CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address)
362364
{
365+
CNetAddr netaddr;
363366
// Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
364367
if (address.is_v6()
365368
&& (address.to_v6().is_v4_compatible()
366369
|| address.to_v6().is_v4_mapped()))
367-
return ClientAllowed(address.to_v6().to_v4());
368-
369-
if (address == asio::ip::address_v4::loopback()
370-
|| address == asio::ip::address_v6::loopback()
371-
|| (address.is_v4()
372-
// Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet)
373-
&& (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000))
374-
return true;
375-
376-
const string strAddress = address.to_string();
377-
const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
378-
BOOST_FOREACH(string strAllow, vAllow)
379-
if (WildcardMatch(strAddress, strAllow))
370+
address = address.to_v6().to_v4();
371+
372+
if(address.is_v4())
373+
{
374+
boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
375+
netaddr.SetRaw(NET_IPV4, &bytes[0]);
376+
}
377+
else
378+
{
379+
boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
380+
netaddr.SetRaw(NET_IPV6, &bytes[0]);
381+
}
382+
return netaddr;
383+
}
384+
385+
bool ClientAllowed(const boost::asio::ip::address& address)
386+
{
387+
CNetAddr netaddr = BoostAsioToCNetAddr(address);
388+
BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
389+
if (subnet.Match(netaddr))
380390
return true;
381391
return false;
382392
}
@@ -502,6 +512,31 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
502512

503513
void StartRPCThreads()
504514
{
515+
rpc_allow_subnets.clear();
516+
rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
517+
rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
518+
if (mapMultiArgs.count("-rpcallowip"))
519+
{
520+
const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
521+
BOOST_FOREACH(string strAllow, vAllow)
522+
{
523+
CSubNet subnet(strAllow);
524+
if(!subnet.IsValid())
525+
{
526+
uiInterface.ThreadSafeMessageBox(
527+
strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
528+
"", CClientUIInterface::MSG_ERROR);
529+
StartShutdown();
530+
return;
531+
}
532+
rpc_allow_subnets.push_back(subnet);
533+
}
534+
}
535+
std::string strAllowed;
536+
BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
537+
strAllowed += subnet.ToString() + " ";
538+
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
539+
505540
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
506541
if (((mapArgs["-rpcpassword"] == "") ||
507542
(mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())

0 commit comments

Comments
 (0)