diff --git a/src/httpserver.cpp b/src/httpserver.cpp --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -306,10 +306,15 @@ 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", defaultPort)); endpoints.push_back(std::make_pair("127.0.0.1", defaultPort)); + 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 " @@ -323,10 +328,6 @@ 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("::", defaultPort)); - endpoints.push_back(std::make_pair("0.0.0.0", defaultPort)); } // Bind addresses @@ -338,6 +339,10 @@ 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, diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -918,12 +918,12 @@ 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)", + "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 " diff --git a/src/netaddress.h b/src/netaddress.h --- a/src/netaddress.h +++ b/src/netaddress.h @@ -56,6 +56,8 @@ // for Tor addresses bool SetSpecial(const std::string &strName); + // INADDR_ANY equivalent + bool IsBindAny() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv4() const; // IPv6 address (not mapped IPv4, not Tor) diff --git a/src/netaddress.cpp b/src/netaddress.cpp --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -82,6 +82,15 @@ 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); }