@@ -38,6 +38,7 @@ static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
38
38
static ssl::context* rpc_ssl_context = NULL ;
39
39
static boost::thread_group* rpc_worker_group = NULL ;
40
40
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
41
42
42
43
void RPCTypeCheck (const Array& params,
43
44
const list<Value_type>& typesExpected,
@@ -358,25 +359,34 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
358
359
stream << HTTPReply (nStatus, strReply, false ) << std::flush;
359
360
}
360
361
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)
362
364
{
365
+ CNetAddr netaddr;
363
366
// Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
364
367
if (address.is_v6 ()
365
368
&& (address.to_v6 ().is_v4_compatible ()
366
369
|| 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))
380
390
return true ;
381
391
return false ;
382
392
}
@@ -502,6 +512,31 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
502
512
503
513
void StartRPCThreads ()
504
514
{
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
+
505
540
strRPCUserColonPass = mapArgs[" -rpcuser" ] + " :" + mapArgs[" -rpcpassword" ];
506
541
if (((mapArgs[" -rpcpassword" ] == " " ) ||
507
542
(mapArgs[" -rpcuser" ] == mapArgs[" -rpcpassword" ])) && Params ().RequireRPCPassword ())
0 commit comments