diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index dc35d97608..de1f84bf82 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -301,6 +301,12 @@ true true + + true + true + true + true + true true @@ -1417,6 +1423,7 @@ + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index 1226f51fe4..91219499c1 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -882,6 +882,9 @@ [1] Ripple\ripple_app\main + + [1] Ripple\ripple_app\network + @@ -1670,6 +1673,9 @@ [2] Build + + [1] Ripple\ripple_app\network + diff --git a/Notes/VFALCO_TODO.txt b/Notes/VFALCO_TODO.txt index 7acb0598a8..331207b8b3 100644 --- a/Notes/VFALCO_TODO.txt +++ b/Notes/VFALCO_TODO.txt @@ -7,6 +7,7 @@ REMINDER: KEEP CHANGE LOG UP TO DATE Vinnie's List: Changes day to day, descending priority (Items marked '*' can be handled by others.) +- Emergency implement PROXY protcol - Get rid of boost::filesystem - Deeply create directories specified in config settings - Finish unit tests and code for Validators diff --git a/SConstruct b/SConstruct index 043423c56d..8dae719925 100644 --- a/SConstruct +++ b/SConstruct @@ -53,9 +53,9 @@ else: env.Replace(CTAGS = CTAGS, CTAGSOPTIONS = '--tag-relative') # Use openssl -env.ParseConfig('pkg-config --cflags --libs openssl') +env.ParseConfig('pkg-config --static --cflags --libs openssl') # Use protobuf -env.ParseConfig('pkg-config --cflags --libs protobuf') +env.ParseConfig('pkg-config --static --cflags --libs protobuf') # Beast uses kvm on FreeBSD if FreeBSD: diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp index 6737f9db08..68d864d509 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.cpp @@ -31,7 +31,11 @@ void FatalError::resetReporter (Reporter& reporter) FatalError::FatalError (char const* message, char const* fileName, int lineNumber) { - LockType::ScopedLockType lock (m_mutex); + typedef CriticalSection LockType; + + static LockType s_mutex; + + LockType::ScopedLockType lock (s_mutex); String const backtraceString = SystemStats::getStackBacktrace (); diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h index 130524ea08..f65a39ad39 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_FatalError.h @@ -87,11 +87,7 @@ public: FatalError (char const* message, char const* fileName, int lineNumber); private: - typedef CriticalSection LockType; - static Static::Storage , FatalError> s_reporter; - - LockType m_mutex; }; #endif diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp index 5e3972347b..5a6c56674a 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp @@ -227,6 +227,7 @@ bool Process::openDocument (const String& fileName, const String& parameters) { const LocalRef t (javaString (fileName)); android.activity.callVoidMethod (BeastAppActivity.launchURL, t.get()); + return true; } void File::revealToUser() const diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp index d2d236a180..275fd6e114 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_android_Misc.cpp @@ -23,5 +23,5 @@ void Logger::outputDebugString (const String& text) { - __android_log_print (ANDROID_LOG_INFO, "BEAST", text.toUTF8()); + __android_log_print (ANDROID_LOG_INFO, "BEAST", "%", text.toUTF8().getAddress()); } diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp index 1dd9a5bc38..fe66fa6df6 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp @@ -262,14 +262,8 @@ String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocale String SystemStats::getDisplayLanguage() { return getUserLanguage(); } //============================================================================== -SystemStats::CPUFlags::CPUFlags() +void CPUInformation::initialise() noexcept { - // TODO - hasMMX = false; - hasSSE = false; - hasSSE2 = false; - has3DNow = false; - numCpus = bmax (1, sysconf (_SC_NPROCESSORS_ONLN)); } diff --git a/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp index 32a6d92e7f..5fce6d211d 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_linux_SystemStats.cpp @@ -127,12 +127,13 @@ String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICA String SystemStats::getDisplayLanguage() { return getUserLanguage(); } //============================================================================== -SystemStats::CPUFlags::CPUFlags() +void CPUInformation::initialise() noexcept { const String flags (LinuxStatsHelpers::getCpuInfo ("flags")); - hasMMX = flags.contains ("mmx"); - hasSSE = flags.contains ("sse"); - hasSSE2 = flags.contains ("sse2"); + hasMMX = flags.contains ("mmx"); + hasSSE = flags.contains ("sse"); + hasSSE2 = flags.contains ("sse2"); + hasSSE3 = flags.contains ("sse3"); has3DNow = flags.contains ("3dnow"); numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1; diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm index 4834c5fb56..9d43f5acf9 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm +++ b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm @@ -64,21 +64,17 @@ namespace SystemStatsHelpers } //============================================================================== -SystemStats::CPUFlags::CPUFlags() +void CPUInformation::initialise() noexcept { #if BEAST_INTEL && ! BEAST_NO_INLINE_ASM - uint32 familyModel = 0, extFeatures = 0, features = 0, dummy = 0; - SystemStatsHelpers::doCPUID (familyModel, extFeatures, dummy, features, 1); + uint32 a = 0, b = 0, d = 0, c = 0; + SystemStatsHelpers::doCPUID (a, b, c, d, 1); - hasMMX = (features & (1u << 23)) != 0; - hasSSE = (features & (1u << 25)) != 0; - hasSSE2 = (features & (1u << 26)) != 0; - has3DNow = (extFeatures & (1u << 31)) != 0; - #else - hasMMX = false; - hasSSE = false; - hasSSE2 = false; - has3DNow = false; + hasMMX = (d & (1u << 23)) != 0; + hasSSE = (d & (1u << 25)) != 0; + hasSSE2 = (d & (1u << 26)) != 0; + has3DNow = (b & (1u << 31)) != 0; + hasSSE3 = (c & (1u << 0)) != 0; #endif #if BEAST_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp index 5ba5a1f3b6..c4f1f8ca4e 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp @@ -99,16 +99,13 @@ String SystemStats::getCpuVendor() //============================================================================== -SystemStats::CPUFlags::CPUFlags() +void CPUInformation::initialise() noexcept { - hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0; - hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0; - hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0; - #ifdef PF_AMD3D_INSTRUCTIONS_AVAILABLE - has3DNow = IsProcessorFeaturePresent (PF_AMD3D_INSTRUCTIONS_AVAILABLE) != 0; - #else - has3DNow = IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0; - #endif + hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0; + hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0; + hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0; + hasSSE3 = IsProcessorFeaturePresent (13 /*PF_SSE3_INSTRUCTIONS_AVAILABLE*/) != 0; + has3DNow = IsProcessorFeaturePresent (7 /*PF_AMD3D_INSTRUCTIONS_AVAILABLE*/) != 0; SYSTEM_INFO systemInfo; GetNativeSystemInfo (&systemInfo); diff --git a/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp b/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp index 2a15c9315d..789cc46f4c 100644 --- a/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp +++ b/Subtrees/beast/modules/beast_core/network/beast_IPAddress.cpp @@ -121,7 +121,7 @@ static void findIPAddresses (int sock, Array& result) cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len; } #else - for (int i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i) + for (size_t i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i) { const ifreq& item = cfg.ifc_req[i]; diff --git a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h index 081a7b037b..2b911bf180 100644 --- a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h +++ b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.h @@ -239,14 +239,19 @@ public: /** Reads a type using a template specialization. The variable is passed as a parameter so that the template type - can be deduced. + can be deduced. The return value indicates whether or not there + was sufficient data in the stream to read the value. - This is useful when doing template meta-programming. */ template - void readTypeInto (T* p) + bool readTypeInto (T* p) { - *p = readType (); + if (getNumBytesRemaining () >= sizeof (T)) + { + *p = readType (); + return true; + } + return false; } /** Reads a type from a big endian stream using a template specialization. @@ -262,14 +267,18 @@ public: /** Reads a type using a template specialization. The variable is passed as a parameter so that the template type - can be deduced. - - This is useful when doing template meta-programming. + can be deduced. The return value indicates whether or not there + was sufficient data in the stream to read the value. */ template - void readTypeBigEndianInto (T* p) + bool readTypeBigEndianInto (T* p) { - *p = readTypeBigEndian (); + if (getNumBytesRemaining () >= sizeof (T)) + { + *p = readTypeBigEndian (); + return true; + } + return false; } //============================================================================== diff --git a/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h b/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h index d3e0d0b8d5..038feab6e9 100644 --- a/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h +++ b/Subtrees/beast/modules/beast_core/streams/beast_MemoryInputStream.h @@ -53,7 +53,7 @@ public: */ MemoryInputStream (const void* sourceData, size_t sourceDataSize, - bool keepInternalCopyOfData); + bool keepInternalCopyOfData = false); /** Creates a MemoryInputStream. diff --git a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp index 1e50c7176d..0098e33d0b 100644 --- a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp @@ -21,12 +21,6 @@ */ //============================================================================== -const SystemStats::CPUFlags& SystemStats::getCPUFlags() -{ - static CPUFlags cpuFlags; - return cpuFlags; -} - String SystemStats::getBeastVersion() { // Some basic tests, to keep an eye on things and make sure these types work ok @@ -62,6 +56,34 @@ String SystemStats::getBeastVersion() static BeastVersionPrinter beastVersionPrinter; #endif +//============================================================================== +struct CPUInformation +{ + CPUInformation() noexcept + : numCpus (0), hasMMX (false), hasSSE (false), + hasSSE2 (false), hasSSE3 (false), has3DNow (false) + { + initialise(); + } + + void initialise() noexcept; + + int numCpus; + bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow; +}; + +static const CPUInformation& getCPUInformation() noexcept +{ + static CPUInformation info; + return info; +} + +int SystemStats::getNumCpus() noexcept { return getCPUInformation().numCpus; } +bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; } +bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; } +bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; } +bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; } +bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; } //============================================================================== String SystemStats::getStackBacktrace() diff --git a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h index 02a76b21ea..1575611976 100644 --- a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h +++ b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.h @@ -121,8 +121,8 @@ public: //============================================================================== // CPU and memory information.. - /** Returns the number of CPUs. */ - static int getNumCpus() noexcept { return getCPUFlags().numCpus; } + /** Returns the number of CPU cores. */ + static int getNumCpus() noexcept; /** Returns the approximate CPU speed. @returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on @@ -135,17 +135,11 @@ public: */ static String getCpuVendor(); - /** Checks whether Intel MMX instructions are available. */ - static bool hasMMX() noexcept { return getCPUFlags().hasMMX; } - - /** Checks whether Intel SSE instructions are available. */ - static bool hasSSE() noexcept { return getCPUFlags().hasSSE; } - - /** Checks whether Intel SSE2 instructions are available. */ - static bool hasSSE2() noexcept { return getCPUFlags().hasSSE2; } - - /** Checks whether AMD 3DNOW instructions are available. */ - static bool has3DNow() noexcept { return getCPUFlags().has3DNow; } + static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */ + static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */ + static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */ + static bool hasSSE3() noexcept; /**< Returns true if Intel SSE2 instructions are available. */ + static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */ //============================================================================== /** Finds out how much RAM is in the machine. @@ -179,19 +173,8 @@ public: private: //============================================================================== - struct CPUFlags - { - CPUFlags(); - - int numCpus; - bool hasMMX : 1; - bool hasSSE : 1; - bool hasSSE2 : 1; - bool has3DNow : 1; - }; SystemStats(); - static const CPUFlags& getCPUFlags(); }; diff --git a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp index a2f7289743..0a5fffae4e 100644 --- a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp +++ b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp @@ -58,10 +58,15 @@ struct CurrentThreadHolder : public SharedObject static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros). +static SpinLock* castToSpinLockWithoutAliasingWarning (void* s) +{ + return static_cast (s); +} + static CurrentThreadHolder::Ptr getCurrentThreadHolder() { static CurrentThreadHolder::Ptr currentThreadHolder; - SpinLock::ScopedLockType lock (*reinterpret_cast (currentThreadHolderLock)); + SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock)); if (currentThreadHolder == nullptr) currentThreadHolder = new CurrentThreadHolder(); diff --git a/modules/ripple_app/basics/ripple_BuildInfo.cpp b/modules/ripple_app/basics/ripple_BuildInfo.cpp index b0054b89b5..c0c440e8ed 100644 --- a/modules/ripple_app/basics/ripple_BuildInfo.cpp +++ b/modules/ripple_app/basics/ripple_BuildInfo.cpp @@ -209,7 +209,7 @@ std::string BuildInfo::Protocol::toStdString () const noexcept { String s; - s << String (vmajor) << "." << "vminor"; + s << String (vmajor) << "." << String (vminor); return s.toStdString (); } diff --git a/modules/ripple_app/network/ripple_ProxyHandshake.cpp b/modules/ripple_app/network/ripple_ProxyHandshake.cpp new file mode 100644 index 0000000000..c3dba646ee --- /dev/null +++ b/modules/ripple_app/network/ripple_ProxyHandshake.cpp @@ -0,0 +1,371 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +ProxyHandshake::ProxyHandshake (bool expectHandshake) + : m_status (expectHandshake ? statusHandshake : statusNone) + , m_gotCR (false) +{ + m_buffer.preallocateBytes (maxVersion1Bytes); +} + +ProxyHandshake::~ProxyHandshake () +{ +} + +std::size_t ProxyHandshake::feed (void const* inputBuffer, size_t inputBytes) +{ + std::size_t bytesConsumed = 0; + + char const* p = static_cast (inputBuffer); + + if (m_status == statusHandshake) + { + if (! m_gotCR) + { + while (inputBytes > 0 && m_buffer.length () < maxVersion1Bytes - 1) + { + beast_wchar c = *p++; + ++bytesConsumed; + --inputBytes; + m_buffer += c; + + if (c == '\r') + { + m_gotCR = true; + break; + } + else if (c == '\n') + { + m_status = statusFailed; + } + } + + if (m_buffer.length () > maxVersion1Bytes - 1) + { + m_status = statusFailed; + } + } + } + + if (m_status == statusHandshake) + { + if (inputBytes > 0 && m_gotCR) + { + bassert (m_buffer.length () < maxVersion1Bytes); + + char const lf ('\n'); + + if (*p == lf) + { + ++bytesConsumed; + --inputBytes; + m_buffer += lf; + + parseLine (); + } + else + { + m_status = statusFailed; + } + } + } + + return bytesConsumed; +} + +void ProxyHandshake::parseLine () +{ + Version1 p; + + bool success = p.parse (m_buffer.getCharPointer (), m_buffer.length ()); + + if (success) + { + m_endpoints = p.endpoints; + m_status = statusOk; + } + else + { + m_status = statusFailed; + } +} + +int ProxyHandshake::indexOfFirstNonNumber (String const& input) +{ + bassert (input.length () > 0); + + int i = 0; + for (; i < input.length (); ++i) + { + if (! CharacterFunctions::isDigit (input [i])) + break; + } + + return i; +} + +bool ProxyHandshake::chop (String const& what, String& input) +{ + if (input.startsWith (what)) + { + input = input.substring (what.length ()); + + return true; + } + + return false; +} + +bool ProxyHandshake::chopUInt (int* value, int limit, String& input) +{ + if (input.length () <= 0) + return false; + + String const s = input.substring (0, indexOfFirstNonNumber (input)); + + if (s.length () <= 0) + return false; + + int const n = s.getIntValue (); + + // Leading zeroes disallowed as per spec, to prevent confusion with octal + if (String (n) != s) + return false; + + if (n < 0 || n > limit) + return false; + + input = input.substring (s.length ()); + + *value = n; + + return true; +} + +//------------------------------------------------------------------------------ + +/* + +steps: + +Proxy protocol lets us filter attackers by learning the source ip and port + +1. Determine if we should use the proxy on a connection + - Port just for proxy protocol connections + - Filter on source IPs + +2. Read a line from the connection to get the proxy information + +3. Parse the line (human or binary?) + +4. Code Interface to retrieve proxy information (ip/port) on connection + +*/ + +ProxyHandshake::Version1::Version1 () +{ +} + +bool ProxyHandshake::IPv4::Addr::chop (String& input) +{ + if (!ProxyHandshake::chopUInt (&a, 255, input)) + return false; + + if (!ProxyHandshake::chop (".", input)) + return false; + + if (!ProxyHandshake::chopUInt (&b, 255, input)) + return false; + + if (!ProxyHandshake::chop (".", input)) + return false; + + if (!ProxyHandshake::chopUInt (&c, 255, input)) + return false; + + if (!ProxyHandshake::chop (".", input)) + return false; + + if (!ProxyHandshake::chopUInt (&d, 255, input)) + return false; + + return true; +} + +bool ProxyHandshake::Version1::parse (void const* headerData, size_t headerBytes) +{ + String input (static_cast (headerData), headerBytes); + + if (input.length () < 2) + return false; + + if (! input.endsWith ("\r\n")) + return false; + + input = input.dropLastCharacters (2); + + if (! ProxyHandshake::chop ("PROXY ", input)) + return false; + + if (ProxyHandshake::chop ("UNKNOWN", input)) + { + endpoints.proto = protoUnknown; + + input = ""; + } + else + { + if (ProxyHandshake::chop ("TCP4 ", input)) + { + endpoints.proto = protoTcp4; + + if (! endpoints.ipv4.sourceAddr.chop (input)) + return false; + + if (! ProxyHandshake::chop (" ", input)) + return false; + + if (! endpoints.ipv4.destAddr.chop (input)) + return false; + + if (! ProxyHandshake::chop (" ", input)) + return false; + + if (! ProxyHandshake::chopUInt (&endpoints.ipv4.sourcePort, 65535, input)) + return false; + + if (! ProxyHandshake::chop (" ", input)) + return false; + + if (! ProxyHandshake::chopUInt (&endpoints.ipv4.destPort, 65535, input)) + return false; + } + else if (ProxyHandshake::chop ("TCP6 ", input)) + { + endpoints.proto = protoTcp6; + + //bassertfalse; + + return false; + } + else + { + return false; + } + } + + // Can't have anything extra between the last port number and the CRLF + if (input.length () > 0) + return false; + + return true; +} + +//------------------------------------------------------------------------------ + +class ProxyHandshakeTests : public UnitTest +{ +public: + ProxyHandshakeTests () : UnitTest ("ProxyHandshake", "ripple", runManual) + { + } + + static std::string goodIpv4 () + { + return "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; // 56 chars + } + + static std::string goodIpv6 () + { + return "PROXY TCP6 fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n"; + //1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 4 (104 chars) + } + + static std::string goodUnknown () + { + return "PROXY UNKNOWN\r\n"; + } + + static std::string goodUnknownBig () + { + return "PROXY UNKNOWN fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n"; + //1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 7 (107 chars) + } + + void testHandshake (std::string const& s, bool shouldSucceed) + { + if (s.size () > 1) + { + ProxyHandshake h (true); + + expect (h.getStatus () == ProxyHandshake::statusHandshake); + + for (int i = 0; i < s.size () && h.getStatus () == ProxyHandshake::statusHandshake ; ++i) + { + std::size_t const bytesConsumed = h.feed (& s[i], 1); + + if (i != s.size () - 1) + expect (h.getStatus () == ProxyHandshake::statusHandshake); + + expect (bytesConsumed == 1); + } + + if (shouldSucceed) + { + expect (h.getStatus () == ProxyHandshake::statusOk); + } + else + { + expect (h.getStatus () == ProxyHandshake::statusFailed); + } + } + else + { + bassertfalse; + } + } + + void testVersion1String (std::string const& s, bool shouldSucceed) + { + ProxyHandshake::Version1 p; + + if (shouldSucceed) + { + expect (p.parse (s.c_str (), s.size ())); + } + else + { + unexpected (p.parse (s.c_str (), s.size ())); + } + + for (int i = 1; i < s.size () - 1; ++i) + { + String const partial = String (s).dropLastCharacters (i); + std::string ss (partial.toStdString ()); + + expect (! p.parse (ss.c_str (), ss.size ())); + } + + testHandshake (s, shouldSucceed); + } + + void testVersion1 () + { + beginTestCase ("version1"); + + testVersion1String (goodIpv4 (), true); + testVersion1String (goodIpv6 (), false); + testVersion1String (goodUnknown (), true); + testVersion1String (goodUnknownBig (), true); + } + + void runTest () + { + testVersion1 (); + } +}; + +static ProxyHandshakeTests proxyHandshakeTests; diff --git a/modules/ripple_app/network/ripple_ProxyHandshake.h b/modules/ripple_app/network/ripple_ProxyHandshake.h new file mode 100644 index 0000000000..d9bd6efa3c --- /dev/null +++ b/modules/ripple_app/network/ripple_ProxyHandshake.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_PROXYYHANDSHAKE_H_INCLUDED +#define RIPPLE_PROXYYHANDSHAKE_H_INCLUDED + +/** PROXY protocol handshake state machine. + + The PROXY Protocol: + http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt +*/ +class ProxyHandshake +{ +public: + /** Status of the handshake state machine. */ + enum Status + { + statusNone, // No handshake expected + statusHandshake, // Handshake in progress + statusFailed, // Handshake failed + statusOk, // Handshake succeeded + }; + + enum Proto + { + protoTcp4, + protoTcp6, + protoUnknown + }; + + /** PROXY information for IPv4 families. */ + struct IPv4 + { + struct Addr + { + int a; + int b; + int c; + int d; + + bool chop (String& input); + }; + + Addr sourceAddr; + Addr destAddr; + int sourcePort; + int destPort; + }; + + /** PROXY information for IPv6 families. */ + struct IPv6 + { + struct Addr + { + int a; + int b; + int c; + int d; + }; + + Addr sourceAddr; + Addr destAddr; + int sourcePort; + int destPort; + }; + + /** Fully decoded PROXY information. */ + struct Endpoints + { + Endpoints () + : proto (protoUnknown) + { + } + + Proto proto; + IPv4 ipv4; // valid if proto == protoTcp4 + IPv6 ipv6; // valid if proto == protoTcp6; + }; + + //-------------------------------------------------------------------------- + + /** Parser for PROXY version 1. */ + struct Version1 + { + enum + { + // Maximum input buffer size needed, including a null + // terminator, as per the PROXY protocol specification. + maxBufferBytes = 108 + }; + + Endpoints endpoints; + + Version1 (); + + /** Parse the header. + @param rawHeader a pointer to the header data + @return `true` If it was parsed successfully. + */ + bool parse (void const* headerData, size_t headerBytes); + }; + + //-------------------------------------------------------------------------- + + /** Create the handshake state. + If a handshake is expected, then it is required. + @param wantHandshake `false` to skip handshaking. + */ + explicit ProxyHandshake (bool expectHandshake = false); + + ~ProxyHandshake (); + + inline Status getStatus () const noexcept + { + return m_status; + } + + inline Endpoints const& getEndpoints () const noexcept + { + return m_endpoints; + }; + + /** Feed the handshaking state engine. + @return The number of bytes consumed in the input buffer. + */ + std::size_t feed (void const* inputBuffer, std::size_t inputBytes); + + // Utility functions used by parsers + static int indexOfFirstNonNumber (String const& input); + static bool chop (String const& what, String& input); + static bool chopUInt (int* value, int limit, String& input); + +private: + void parseLine (); + +private: + enum + { + maxVersion1Bytes = 107 // including crlf, not including null term + }; + + Status m_status; + String m_buffer; + bool m_gotCR; + Endpoints m_endpoints; +}; + +#endif diff --git a/modules/ripple_app/ripple_app.cpp b/modules/ripple_app/ripple_app.cpp index 9e24a0e63b..469bccd3bd 100644 --- a/modules/ripple_app/ripple_app.cpp +++ b/modules/ripple_app/ripple_app.cpp @@ -239,6 +239,8 @@ static const uint64 tenTo17m1 = tenTo17 - 1; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ +#include "network/ripple_ProxyHandshake.h" // private? + //------------------------------------------------------------------------------ #if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1 @@ -326,6 +328,7 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength) #include "tx/Transactor.cpp" #include "network/WSConnection.cpp" #include "network/WSDoor.cpp" +#include "network/ripple_ProxyHandshake.cpp" #endif