From efae3da41d821b12d1481de8b8e0b2e105d36ae3 Mon Sep 17 00:00:00 2001
From: s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
Date: Wed, 15 Sep 2010 22:10:13 +0000
Subject: [PATCH] config option -rpcallowip= to accept json-rpc connections
 from another machine

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@155 1a98c847-1fd6-4fd8-948a-caf3550aa51b
---
 main.cpp    |  5 -----
 rpc.cpp     | 24 ++++++++++++++++++------
 serialize.h |  2 +-
 util.cpp    | 48 +++++++++++++++++++++++++++++++++++++++---------
 util.h      | 19 ++++++++++++++++++-
 5 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/main.cpp b/main.cpp
index c26755f72..5b7829e88 100644
--- a/main.cpp
+++ b/main.cpp
@@ -3170,11 +3170,6 @@ int64 GetBalance()
 }
 
 
-int GetRandInt(int nMax)
-{
-    return GetRand(nMax);
-}
-
 bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
 {
     setCoinsRet.clear();
diff --git a/rpc.cpp b/rpc.cpp
index 0970c87b2..9a4757390 100644
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -783,8 +783,9 @@ int ReadHTTPStatus(tcp::iostream& stream)
     getline(stream, str);
     vector<string> vWords;
     boost::split(vWords, str, boost::is_any_of(" "));
-    int nStatus = atoi(vWords[1].c_str());
-    return nStatus;
+    if (vWords.size() < 2)
+        return 500;
+    return atoi(vWords[1].c_str());
 }
 
 int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)
@@ -918,6 +919,17 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
     return write_string(Value(reply), false) + "\n";
 }
 
+bool ClientAllowed(const string& strAddress)
+{
+    if (strAddress == asio::ip::address_v4::loopback().to_string())
+        return true;
+    const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
+    foreach(string strAllow, vAllow)
+        if (WildcardMatch(strAddress, strAllow))
+            return true;
+    return false;
+}
+
 
 
 
@@ -962,7 +974,7 @@ void ThreadRPCServer2(void* parg)
 
     // Bind to loopback 127.0.0.1 so the socket can only be accessed locally
     boost::asio::io_service io_service;
-    tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 8332);
+    tcp::endpoint endpoint(mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback(), 8332);
     tcp::acceptor acceptor(io_service, endpoint);
 
     loop
@@ -976,8 +988,8 @@ void ThreadRPCServer2(void* parg)
         if (fShutdown)
             return;
 
-        // Shouldn't be possible for anyone else to connect, but just in case
-        if (peer.address().to_string() != "127.0.0.1")
+        // Restrict callers by IP
+        if (!ClientAllowed(peer.address().to_string()))
             continue;
 
         // Receive request
@@ -1090,7 +1102,7 @@ Object CallRPC(const string& strMethod, const Array& params)
                 GetConfigFile().c_str()));
 
     // Connect to localhost
-    tcp::iostream stream("127.0.0.1", "8332");
+    tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), "8332");
     if (stream.fail())
         throw runtime_error("couldn't connect to server");
 
diff --git a/serialize.h b/serialize.h
index e9f7e2db7..b3ab9b5e2 100644
--- a/serialize.h
+++ b/serialize.h
@@ -23,7 +23,7 @@ class CAutoFile;
 static const unsigned int MAX_SIZE = 0x02000000;
 
 static const int VERSION = 312;
-static const char* pszSubVer = ".5";
+static const char* pszSubVer = ".6";
 
 
 
diff --git a/util.cpp b/util.cpp
index 9efa20ede..b63b795b8 100644
--- a/util.cpp
+++ b/util.cpp
@@ -127,6 +127,11 @@ uint64 GetRand(uint64 nMax)
     return (nRand % nMax);
 }
 
+int GetRandInt(int nMax)
+{
+    return GetRand(nMax);
+}
+
 
 
 
@@ -405,7 +410,7 @@ vector<unsigned char> ParseHex(const char* psz)
     return vch;
 }
 
-vector<unsigned char> ParseHex(const std::string& str)
+vector<unsigned char> ParseHex(const string& str)
 {
     return ParseHex(str.c_str());
 }
@@ -473,6 +478,34 @@ const char* wxGetTranslation(const char* pszEnglish)
 }
 
 
+bool WildcardMatch(const char* psz, const char* mask)
+{
+    loop
+    {
+        switch (*mask)
+        {
+        case '\0':
+            return (*psz == '\0');
+        case '*':
+            return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
+        case '?':
+            if (*psz == '\0')
+                return false;
+            break;
+        default:
+            if (*psz != *mask)
+                return false;
+            break;
+        }
+        psz++;
+        mask++;
+    }
+}
+
+bool WildcardMatch(const string& str, const string& mask)
+{
+    return WildcardMatch(str.c_str(), mask.c_str());
+}
 
 
 
@@ -650,7 +683,7 @@ string GetDataDir()
 string GetConfigFile()
 {
     namespace fs = boost::filesystem;
-    fs::path pathConfig(mapArgs.count("-conf") ? mapArgs["-conf"] : string("bitcoin.conf"));
+    fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
     if (!pathConfig.is_complete())
         pathConfig = fs::path(GetDataDir()) / pathConfig;
     return pathConfig.string();
@@ -718,13 +751,10 @@ void ShrinkDebugFile()
 
 //
 // "Never go to sea with two chronometers; take one or three."
-// Our three chronometers are:
+// Our three time sources are:
 //  - System clock
-//  - Median of other server's clocks
-//  - NTP servers
-//
-// note: NTP isn't implemented yet, so until then we just use the median
-//  of other nodes clocks to correct ours.
+//  - Median of other nodes's clocks
+//  - The user (asking the user to fix the system clock if the first two disagree)
 //
 int64 GetTime()
 {
@@ -768,7 +798,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
             // If nobody else has the same time as us, give a warning
             bool fMatch = false;
             foreach(int64 nOffset, vTimeOffsets)
-                if (nOffset != 0 && abs64(nOffset) < 10 * 60)
+                if (nOffset != 0 && abs64(nOffset) < 5 * 60)
                     fMatch = true;
             static bool fDone;
             if (!fMatch && !fDone)
diff --git a/util.h b/util.h
index 42d1fe460..2e6bf2a60 100644
--- a/util.h
+++ b/util.h
@@ -160,9 +160,11 @@ string FormatMoney(int64 n, bool fPlus=false);
 bool ParseMoney(const string& str, int64& nRet);
 bool ParseMoney(const char* pszIn, int64& nRet);
 vector<unsigned char> ParseHex(const char* psz);
-vector<unsigned char> ParseHex(const std::string& str);
+vector<unsigned char> ParseHex(const string& str);
 void ParseParameters(int argc, char* argv[]);
 const char* wxGetTranslation(const char* psz);
+bool WildcardMatch(const char* psz, const char* mask);
+bool WildcardMatch(const string& str, const string& mask);
 int GetFilesize(FILE* file);
 void GetDataDir(char* pszDirRet);
 string GetConfigFile();
@@ -173,6 +175,7 @@ string MyGetSpecialFolderPath(int nFolder, bool fCreate);
 string GetDefaultDataDir();
 string GetDataDir();
 void ShrinkDebugFile();
+int GetRandInt(int nMax);
 uint64 GetRand(uint64 nMax);
 int64 GetTime();
 int64 GetAdjustedTime();
@@ -399,6 +402,20 @@ inline bool IsSwitchChar(char c)
 #endif
 }
 
+inline string GetArg(const string& strArg, const string& strDefault)
+{
+    if (mapArgs.count(strArg))
+        return mapArgs[strArg];
+    return strDefault;
+}
+
+inline int64 GetArg(const string& strArg, int64 nDefault)
+{
+    if (mapArgs.count(strArg))
+        return atoi64(mapArgs[strArg]);
+    return nDefault;
+}
+