diff --git a/rippled-example.cfg b/rippled-example.cfg index f744233b26..dff63f24a2 100644 --- a/rippled-example.cfg +++ b/rippled-example.cfg @@ -194,6 +194,12 @@ # If you need a certificate chain, specify the path to the certificate chain # here. The chain may include the end certificate. # +# [ssl_verify_file] +# [ssl_verify_dir] +# Specify the path to a file or directory containing the root certificates +# that the server will accept for verifying HTTP servers. Used only for +# outbound HTTPS client connections. +# # [validation_seed]: # To perform validation, this section should contain either a validation seed # or key. The validation seed is used to generate the validation diff --git a/src/cpp/ripple/AutoSocket.h b/src/cpp/ripple/AutoSocket.h index 904341960e..1de55e021d 100644 --- a/src/cpp/ripple/AutoSocket.h +++ b/src/cpp/ripple/AutoSocket.h @@ -67,6 +67,15 @@ public: std::swap(mSecure, s.mSecure); } + static bool rfc2818_verify(const std::string& domain, bool preverified, boost::asio::ssl::verify_context& ctx) + { + if (boost::asio::ssl::rfc2818_verification(domain)(preverified, ctx)) + return true; + Log(lsWARNING, AutoSocketPartition) << "Outbound SSL connection to " << + domain << " fails certificate verification"; + return false; + } + boost::system::error_code verify(const std::string& strDomain) { boost::system::error_code ec; @@ -74,7 +83,7 @@ public: mSocket->set_verify_mode(boost::asio::ssl::verify_peer); // XXX Verify semantics of RFC 2818 are what we want. - mSocket->set_verify_callback(boost::asio::ssl::rfc2818_verification(strDomain), ec); + mSocket->set_verify_callback(boost::bind(&rfc2818_verify, strDomain, _1, _2), ec); return ec; } diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp index 3d1c9f3ac8..6f9772f849 100644 --- a/src/cpp/ripple/Config.cpp +++ b/src/cpp/ripple/Config.cpp @@ -46,6 +46,8 @@ #define SECTION_RPC_PASSWORD "rpc_password" #define SECTION_RPC_STARTUP "rpc_startup" #define SECTION_SNTP "sntp_servers" +#define SECTION_SSL_VERIFY_FILE "ssl_verify_file" +#define SECTION_SSL_VERIFY_DIR "ssl_verify_dir" #define SECTION_VALIDATORS_FILE "validators_file" #define SECTION_VALIDATION_QUORUM "validation_quorum" #define SECTION_VALIDATION_SEED "validation_seed" @@ -155,10 +157,22 @@ void Config::setup(const std::string& strConf, bool bTestNet, bool bQuiet) } } - SSL_CONTEXT.set_default_verify_paths(ec); - if (ec) - throw std::runtime_error(boost::str(boost::format("Failed to set_default_verify_paths: %s") % ec.message())); + if (SSL_VERIFY_FILE.empty()) + { + SSL_CONTEXT.set_default_verify_paths(ec); + if (ec && SSL_VERIFY_DIR.empty()) + throw std::runtime_error(boost::str(boost::format("Failed to set_default_verify_paths: %s") % ec.message())); + } + else + SSL_CONTEXT.load_verify_file(SSL_VERIFY_FILE); + + if (!SSL_VERIFY_DIR.empty()) + { + SSL_CONTEXT.add_verify_path(SSL_VERIFY_DIR, ec); + if (ec) + throw std::runtime_error(boost::str(boost::format("Failed to add verify path: %s") % ec.message())); + } // Update default values load(); @@ -381,6 +395,9 @@ void Config::load() sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_CHAIN, WEBSOCKET_SSL_CHAIN); sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_KEY, WEBSOCKET_SSL_KEY); + sectionSingleB(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE); + sectionSingleB(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR); + if (sectionSingleB(secConfig, SECTION_VALIDATION_SEED, strTemp)) { VALIDATION_SEED.setSeedGeneric(strTemp); @@ -473,6 +490,8 @@ int Config::getSize(SizedItemName item) { siNodeCacheAge, { 30, 60, 90, 300, 600 } }, { siLedgerSize, { 32, 64, 128, 1024, 0 } }, { siLedgerAge, { 30, 60, 120, 300, 600 } }, + { siLineCacheSize, { 8192, 32768, 131072, 1048576, 0 } }, + { siLineCacheAge, { 500, 600, 1800, 3600, 7200 } } }; for (int i = 0; i < (sizeof(sizeTable) / sizeof(SizedItem)); ++i) diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index bff35fcc29..96e9eebe92 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -63,6 +63,8 @@ enum SizedItemName siLedgerSize, siLedgerAge, siLedgerFetch, + siLineCacheSize, + siLineCacheAge }; struct SizedItem @@ -176,6 +178,8 @@ public: uint32 SIGN_PROPOSAL; boost::asio::ssl::context SSL_CONTEXT; // Generic SSL context. + std::string SSL_VERIFY_FILE; + std::string SSL_VERIFY_DIR; Config(); diff --git a/src/cpp/ripple/Ledger.h b/src/cpp/ripple/Ledger.h index cf09383ac7..20da8705f6 100644 --- a/src/cpp/ripple/Ledger.h +++ b/src/cpp/ripple/Ledger.h @@ -133,6 +133,7 @@ public: bool isClosed() { return mClosed; } bool isAccepted() { return mAccepted; } bool isImmutable() { return mImmutable; } + bool isFixed() { return mClosed || mImmutable; } // ledger signature operations void addRaw(Serializer &s) const; diff --git a/src/cpp/ripple/LedgerMaster.cpp b/src/cpp/ripple/LedgerMaster.cpp index e486cd9d9b..5176d58795 100644 --- a/src/cpp/ripple/LedgerMaster.cpp +++ b/src/cpp/ripple/LedgerMaster.cpp @@ -455,7 +455,7 @@ void LedgerMaster::tryPublish() { for (uint32 seq = mPubLedger->getLedgerSeq() + 1; seq <= mValidLedger->getLedgerSeq(); ++seq) { - cLog(lsDEBUG) << "Trying to publish ledger " << seq; + cLog(lsTRACE) << "Trying to publish ledger " << seq; Ledger::pointer ledger; uint256 hash; diff --git a/src/cpp/ripple/Log.cpp b/src/cpp/ripple/Log.cpp index d2e14c02c5..9bc49eb0b9 100644 --- a/src/cpp/ripple/Log.cpp +++ b/src/cpp/ripple/Log.cpp @@ -199,7 +199,12 @@ namespace websocketpp void websocketLog(websocketpp::log::alevel::value v, const std::string& entry) { - if (websocketPartition.doLog(lsDEBUG)) + if (v == websocketpp::log::alevel::DEVEL) + { + if (websocketPartition.doLog(lsTRACE)) + Log(lsDEBUG, websocketPartition) << entry; + } + else if (websocketPartition.doLog(lsDEBUG)) Log(lsDEBUG, websocketPartition) << entry; } diff --git a/src/cpp/ripple/OrderBookDB.cpp b/src/cpp/ripple/OrderBookDB.cpp index 619ae87b4b..7113abe243 100644 --- a/src/cpp/ripple/OrderBookDB.cpp +++ b/src/cpp/ripple/OrderBookDB.cpp @@ -44,13 +44,13 @@ void OrderBookDB::setup(Ledger::ref ledger) OrderBook::pointer book = OrderBook::newOrderBook(entry); if (book) { - cLog(lsDEBUG) << "OrderBookDB: found book"; + cLog(lsTRACE) << "OrderBookDB: found book"; if (mKnownMap.find(book->getBookBase()) == mKnownMap.end()) { mKnownMap[book->getBookBase()] = true; - cLog(lsDEBUG) << "OrderBookDB: unknown book in: " + cLog(lsTRACE) << "OrderBookDB: unknown book in: " << STAmount::createHumanCurrency(book->getCurrencyIn()) << " -> " << STAmount::createHumanCurrency(book->getCurrencyOut()); diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index aaf895d312..dc73df8972 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -90,7 +90,7 @@ bool Pathfinder::bDefaultPath(const STPath& spPath) { if (2 == spPath.mPath.size()) { // Empty path is a default. Don't need to add it to return set. - cLog(lsDEBUG) << "findPaths: empty path: direct"; + cLog(lsTRACE) << "findPaths: empty path: direct"; return true; } @@ -285,8 +285,8 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax continue; } - cLog(lsDEBUG) << "findPaths: finish? account: " << (speEnd.mAccountID == mDstAccountID); - cLog(lsDEBUG) << "findPaths: finish? currency: " << (speEnd.mCurrencyID == mDstAmount.getCurrency()); + cLog(lsTRACE) << "findPaths: finish? account: " << (speEnd.mAccountID == mDstAccountID); + cLog(lsTRACE) << "findPaths: finish? currency: " << (speEnd.mCurrencyID == mDstAmount.getCurrency()); cLog(lsTRACE) << "findPaths: finish? issuer: " << RippleAddress::createHumanAccountID(speEnd.mIssuerID) << " / " diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index 028dc0df84..0d6068a47f 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -1394,7 +1394,7 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet) logMe += "LedgerHash:"; logMe += ledgerhash.GetHex(); ledger = theApp->getLedgerMaster().getLedgerByHash(ledgerhash); - tLog(!ledger, lsDEBUG) << "Don't have ledger " << ledgerhash; + tLog(!ledger, lsTRACE) << "Don't have ledger " << ledgerhash; if (!ledger && (packet.has_querytype() && !packet.has_requestcookie())) { std::vector peerList = theApp->getConnectionPool().getPeerVector(); diff --git a/src/cpp/ripple/RPCErr.cpp b/src/cpp/ripple/RPCErr.cpp index a7073bf085..9e06a5d9d7 100644 --- a/src/cpp/ripple/RPCErr.cpp +++ b/src/cpp/ripple/RPCErr.cpp @@ -59,7 +59,8 @@ Json::Value rpcError(int iError, Json::Value jvResult) { rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, { rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." }, - { rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source amount not found." }, + { rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." }, + { rpcBAD_SECRET, "badSecret", "Secret does not match account." }, { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." }, { rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." }, { rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." }, diff --git a/src/cpp/ripple/RPCErr.h b/src/cpp/ripple/RPCErr.h index 611cc5eea1..8aa371328a 100644 --- a/src/cpp/ripple/RPCErr.h +++ b/src/cpp/ripple/RPCErr.h @@ -67,6 +67,7 @@ enum { rpcSRC_AMT_MALFORMED, rpcSRC_CUR_MALFORMED, rpcSRC_ISR_MALFORMED, + rpcBAD_SECRET, // Internal error (should never happen) rpcINTERNAL, // Generic internal error. diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index d74cfa013f..038de7c672 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -251,7 +251,7 @@ Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit) if (!bFound) { - return rpcError(rpcSRC_ACT_NOT_FOUND); + return rpcError(rpcBAD_SECRET); } // Use the generator to determine the associated public and private keys. @@ -899,6 +899,8 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest) if (!lpLedger) return jvResult; + ScopedUnlock su(theApp->getMasterLock(), lpLedger->isFixed()); + if (!jvRequest.isMember("account")) return rpcError(rpcINVALID_PARAMS); @@ -926,6 +928,7 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest) jvResult["account"] = raAccount.humanAccountID(); + // XXX This is wrong, we do access the current ledger and do need to worry about changes. // We access a committed ledger and need not worry about changes. @@ -977,6 +980,8 @@ Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest) if (!lpLedger) return jvResult; + ScopedUnlock su(theApp->getMasterLock(), lpLedger->isClosed() || lpLedger->isImmutable()); + if (!jvRequest.isMember("account")) return rpcError(rpcINVALID_PARAMS); @@ -2139,13 +2144,20 @@ Json::Value RPCHandler::lookupLedger(Json::Value jvRequest, Ledger::pointer& lpL lpLedger = mNetOps->getCurrentLedger(); iLedgerIndex = lpLedger->getLedgerSeq(); } - else if (iLedgerIndex <= 0) + if (-3 == iLedgerIndex) + { // Last fully-validated ledger + lpLedger = mNetOps->getValidatedLedger(); + iLedgerIndex = lpLedger->getLedgerSeq(); + } + + if (iLedgerIndex <= 0) { jvResult["error"] = "ledgerNotFound"; return jvResult; } - else if (iLedgerIndex) + + if (!lpLedger) { lpLedger = mNetOps->getLedgerBySeq(iLedgerIndex); diff --git a/src/cpp/ripple/ScopedLock.h b/src/cpp/ripple/ScopedLock.h index e0859fd774..e1a1fe9225 100644 --- a/src/cpp/ripple/ScopedLock.h +++ b/src/cpp/ripple/ScopedLock.h @@ -29,11 +29,39 @@ public: class ScopedUnlock { protected: + bool mUnlocked; boost::recursive_mutex& mMutex; public: - ScopedUnlock(boost::recursive_mutex& mutex) : mMutex(mutex) { mMutex.unlock(); } - ~ScopedUnlock() { mMutex.lock(); } + ScopedUnlock(boost::recursive_mutex& mutex, bool unlock = true) : mUnlocked(unlock), mMutex(mutex) + { + if (unlock) + mMutex.unlock(); + } + + ~ScopedUnlock() + { + if (mUnlocked) + mMutex.lock(); + } + + void lock() + { + if (mUnlocked) + { + mMutex.lock(); + mUnlocked = false; + } + } + + void unlock() + { + if (!mUnlocked) + { + mUnlocked = true; + mMutex.unlock(); + } + } private: ScopedUnlock(const ScopedUnlock&); // no implementation diff --git a/src/cpp/ripple/ValidationCollection.cpp b/src/cpp/ripple/ValidationCollection.cpp index e24f3512b4..5fff5a1202 100644 --- a/src/cpp/ripple/ValidationCollection.cpp +++ b/src/cpp/ripple/ValidationCollection.cpp @@ -79,7 +79,7 @@ bool ValidationCollection::addValidation(SerializedValidation::ref val) } } - cLog(lsINFO) << "Val for " << hash << " from " << signer.humanNodePublic() + cLog(lsDEBUG) << "Val for " << hash << " from " << signer.humanNodePublic() << " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale"); if (val->isTrusted()) theApp->getLedgerMaster().checkAccept(hash);