From 3615003952ffbc814bdb53d9d0e45790f152bd2f Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 20 Oct 2018 14:37:18 +0000 Subject: [PATCH 1/3] net: Always default rpcbind to localhost, never "all interfaces" We don't support binding to untrusted networks, so avoid a default where that is typical --- src/httpserver.cpp | 8 ++++---- src/init.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 91ebc4680c5..cf365f4638c 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -300,9 +300,12 @@ static bool HTTPBindAddresses(struct evhttp* http) std::vector > endpoints; // Determine what addresses to bind to - if (!gArgs.IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs + if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs endpoints.push_back(std::make_pair("::1", http_port)); endpoints.push_back(std::make_pair("127.0.0.1", http_port)); + if (gArgs.IsArgSet("-rpcallowip")) { + LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n"); + } if (gArgs.IsArgSet("-rpcbind")) { LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); } @@ -313,9 +316,6 @@ static bool HTTPBindAddresses(struct evhttp* http) SplitHostPort(strRPCBind, port, host); endpoints.push_back(std::make_pair(host, port)); } - } else { // No specific bind address specified, bind to any - endpoints.push_back(std::make_pair("::", http_port)); - endpoints.push_back(std::make_pair("0.0.0.0", http_port)); } // Bind addresses diff --git a/src/init.cpp b/src/init.cpp index d6f04bea14d..0ff7f7fcc12 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -500,7 +500,7 @@ void SetupServerArgs() gArgs.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), false, OptionsCategory::RPC); gArgs.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", false, OptionsCategory::RPC); gArgs.AddArg("-rpcauth=", "Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC); - gArgs.AddArg("-rpcbind=[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC); + gArgs.AddArg("-rpcbind=[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", false, OptionsCategory::RPC); gArgs.AddArg("-rpccookiefile=", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC); gArgs.AddArg("-rpcpassword=", "Password for JSON-RPC connections", false, OptionsCategory::RPC); gArgs.AddArg("-rpcport=", strprintf("Listen for JSON-RPC connections on (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC); From d6a1287481428d982dc03be3a6d9aeef8398f468 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 20 Oct 2018 14:48:29 +0000 Subject: [PATCH 2/3] CNetAddr: Add IsBindAny method to check for INADDR_ANY --- src/netaddress.cpp | 10 ++++++++++ src/netaddress.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/netaddress.cpp b/src/netaddress.cpp index e1af4eff626..72be77dfd9c 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -83,6 +83,16 @@ unsigned int CNetAddr::GetByte(int n) const return ip[15-n]; } +bool CNetAddr::IsBindAny() const +{ + const int cmplen = IsIPv4() ? 4 : 16; + for (int i = 0; i < cmplen; ++i) { + if (GetByte(i)) return false; + } + + return true; +} + bool CNetAddr::IsIPv4() const { return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); diff --git a/src/netaddress.h b/src/netaddress.h index cc0e4d4f122..86c13b34658 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -55,6 +55,7 @@ class CNetAddr bool SetInternal(const std::string& name); bool SetSpecial(const std::string &strName); // for Tor addresses + bool IsBindAny() const; // INADDR_ANY equivalent bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) From 27c44ef9c61f64d941ab82ec232a68141a2fde90 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 20 Oct 2018 14:56:58 +0000 Subject: [PATCH 3/3] rpcbind: Warn about exposing RPC to untrusted networks --- src/httpserver.cpp | 4 ++++ src/init.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index cf365f4638c..00434169cd2 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -323,6 +323,10 @@ static bool HTTPBindAddresses(struct evhttp* http) LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second); evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second); if (bind_handle) { + CNetAddr addr; + if (i->first.empty() || (LookupHost(i->first.c_str(), addr, false) && addr.IsBindAny())) { + LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n"); + } boundSockets.push_back(bind_handle); } else { LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second); diff --git a/src/init.cpp b/src/init.cpp index 0ff7f7fcc12..31212a355b5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -500,7 +500,7 @@ void SetupServerArgs() gArgs.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), false, OptionsCategory::RPC); gArgs.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", false, OptionsCategory::RPC); gArgs.AddArg("-rpcauth=", "Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC); - gArgs.AddArg("-rpcbind=[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", false, OptionsCategory::RPC); + gArgs.AddArg("-rpcbind=[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", false, OptionsCategory::RPC); gArgs.AddArg("-rpccookiefile=", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC); gArgs.AddArg("-rpcpassword=", "Password for JSON-RPC connections", false, OptionsCategory::RPC); gArgs.AddArg("-rpcport=", strprintf("Listen for JSON-RPC connections on (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC);