diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 56c69c285..7ad220ebf 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -216,12 +216,15 @@ public: } }; +namespace test{ extern std::atomic envUseIPv4; } + static int runUnitTests( std::string const& pattern, std::string const& argument, bool quiet, bool log, bool child, + bool ipv4, std::size_t num_jobs, int argc, char** argv) @@ -229,6 +232,9 @@ static int runUnitTests( using namespace beast::unit_test; using namespace ripple::test; + if (ipv4) + ripple::test::envUseIPv4 = true; + #if HAS_BOOST_PROCESS if (!child && num_jobs == 1) #endif @@ -365,6 +371,7 @@ int run (int argc, char** argv) "Specify the IP address for RPC command. " "Format: [':']") ("rpc_port", po::value (), + "DEPRECATED: include with rpc_ip instead. " "Specify the port number for RPC command.") ; @@ -384,6 +391,7 @@ int run (int argc, char** argv) "argument is handled individually by any suite that accesses it -- " "as such, it typically only make sense to provide this when running " "a single suite.") + ("unittest-ipv4", "Use IPv4 localhost when running unittests (default is IPv6).") ("unittest-log", "Force unit test log message output. Only useful in combination with " "--quiet, in which case log messages will print but suite/case names " @@ -468,6 +476,7 @@ int run (int argc, char** argv) bool (vm.count ("quiet")), bool (vm.count ("unittest-log")), unittestChild, + bool (vm.count ("unittest-ipv4")), numJobs, argc, argv); @@ -553,37 +562,38 @@ int run (int argc, char** argv) // happen after the config file is loaded. if (vm.count ("rpc_ip")) { - try - { - config->rpc_ip.emplace ( - boost::asio::ip::address_v4::from_string( - vm["rpc_ip"].as())); - } - catch(std::exception const&) + auto res = beast::IP::Endpoint::from_string_checked( + vm["rpc_ip"].as()); + if (! res.second) { std::cerr << "Invalid rpc_ip = " << - vm["rpc_ip"].as() << std::endl; + vm["rpc_ip"].as() << "\n"; return -1; } - } - // Override the RPC destination port number - // - if (vm.count ("rpc_port")) - { - try + if (res.first.port() == 0) { - config->rpc_port.emplace ( - vm["rpc_port"].as()); + std::cerr << "No port specified in rpc_ip.\n"; + if (vm.count ("rpc_port")) + { + std::cerr << "WARNING: using deprecated rpc_port param.\n"; + try + { + res.first.at_port(vm["rpc_port"].as()); + if (res.first.port() == 0) + throw std::domain_error("0"); + } + catch(std::exception const& e) + { + std::cerr << "Invalid rpc_port = " << e.what() << "\n"; + return -1; + } + } + else + return -1; + } - if (*config->rpc_port == 0) - throw std::domain_error("0"); - } - catch(std::exception const& e) - { - std::cerr << "Invalid rpc_port = " << e.what() << "\n"; - return -1; - } + config->rpc_ip = std::move(res.first); } if (vm.count ("quorum")) diff --git a/src/ripple/basics/impl/ResolverAsio.cpp b/src/ripple/basics/impl/ResolverAsio.cpp index 4f187642e..4b85af785 100644 --- a/src/ripple/basics/impl/ResolverAsio.cpp +++ b/src/ripple/basics/impl/ResolverAsio.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -259,6 +260,21 @@ public: HostAndPort parseName(std::string const& str) { + // first attempt to parse as an endpoint (IP addr + port). + // If that doesn't succeed, fall back to generic name + port parsing + + auto result {beast::IP::Endpoint::from_string_checked (str)}; + if (result.second) + { + return make_pair ( + result.first.address().to_string(), + std::to_string(result.first.port())); + } + + // generic name/port parsing, which doesn't work for + // IPv6 addresses in particular because it considers a colon + // a port separator + // Attempt to find the first and last non-whitespace auto const find_whitespace = std::bind ( &std::isspace , diff --git a/src/ripple/basics/impl/StringUtilities.cpp b/src/ripple/basics/impl/StringUtilities.cpp index 6d8358663..503177fe6 100644 --- a/src/ripple/basics/impl/StringUtilities.cpp +++ b/src/ripple/basics/impl/StringUtilities.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -93,24 +93,38 @@ uint64_t uintFromHex (std::string const& strSrc) bool parseUrl (parsedURL& pUrl, std::string const& strUrl) { // scheme://username:password@hostname:port/rest - static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^:/]+)(?::(\\d+))?(/.*)?\\s*?\\'"); + static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^/]+)(/.*)?\\s*?\\'"); boost::smatch smMatch; bool bMatch = boost::regex_match (strUrl, smMatch, reUrl); // Match status code. if (bMatch) { - std::string strPort; - pUrl.scheme = smMatch[1]; boost::algorithm::to_lower (pUrl.scheme); + pUrl.path = smMatch[3]; pUrl.domain = smMatch[2]; - if (smMatch[3].length ()) + + // now consider the domain/port fragment + auto colonPos = pUrl.domain.find_last_of(':'); + if (colonPos != std::string::npos) { - pUrl.port = beast::lexicalCast ( - std::string (smMatch[3])); + // use Endpoint class to see if this thing looks + // like an IP addr... + auto result {beast::IP::Endpoint::from_string_checked (pUrl.domain)}; + if (result.second) + { + pUrl.domain = result.first.address().to_string(); + pUrl.port = result.first.port(); + } + else // otherwise we are DNS name + port + { + pUrl.port = beast::lexicalCast ( + pUrl.domain.substr(colonPos+1)); + pUrl.domain = pUrl.domain.substr(0, colonPos); + } } - pUrl.path = smMatch[4]; + //else, the whole thing is domain, not port } return bMatch; diff --git a/src/ripple/beast/insight/impl/StatsDCollector.cpp b/src/ripple/beast/insight/impl/StatsDCollector.cpp index c2a30cbf0..52646bb7d 100644 --- a/src/ripple/beast/insight/impl/StatsDCollector.cpp +++ b/src/ripple/beast/insight/impl/StatsDCollector.cpp @@ -217,19 +217,9 @@ private: std::thread m_thread; static boost::asio::ip::udp::endpoint to_endpoint ( - IP::Endpoint const &address) + IP::Endpoint const &ep) { - if (address.is_v4 ()) - { - return boost::asio::ip::udp::endpoint ( - boost::asio::ip::address_v4 ( - address.to_v4().value), address.port ()); - } - - // VFALCO TODO IPv6 support - assert(false); - return boost::asio::ip::udp::endpoint ( - boost::asio::ip::address_v6 (), 0); + return boost::asio::ip::udp::endpoint (ep.address(), ep.port()); } public: diff --git a/src/ripple/beast/net/IPAddress.h b/src/ripple/beast/net/IPAddress.h index 1139ee87e..ee473ba1a 100644 --- a/src/ripple/beast/net/IPAddress.h +++ b/src/ripple/beast/net/IPAddress.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -37,213 +38,22 @@ namespace beast { namespace IP { -/** A version-independent IP address. - This object can represent either an IPv4 or IPv6 address. -*/ -class Address +using Address = boost::asio::ip::address; + +/** Returns the address represented as a string. */ +inline +std::string +to_string (Address const& addr) { -public: - /** Create an unspecified IPv4 address. */ - Address () - : m_type (ipv4) - { - } - - /** Create an IPv4 address. */ - Address (AddressV4 const& addr) - : m_type (ipv4) - , m_v4 (addr) - { - } - - /** Create an IPv6 address. */ - Address (AddressV6 const& addr) - : m_type (ipv6) - , m_v6 (addr) - { - } - - /** Assign a copy from another address in any format. */ - /** @{ */ - Address& - operator= (AddressV4 const& addr) - { - m_type = ipv4; - m_v6 = AddressV6(); - m_v4 = addr; - return *this; - } - - Address& - operator= (AddressV6 const& addr) - { - m_type = ipv6; - m_v4 = AddressV4(); - m_v6 = addr; - return *this; - } - /** @} */ - - /** Create an Address from a string. - @return A pair with the address, and bool set to `true` on success. - */ - static - std::pair - from_string (std::string const& s); - - /** Returns a string representing the address. */ - std::string - to_string () const - { - return (is_v4 ()) - ? IP::to_string (to_v4()) - : IP::to_string (to_v6()); - } - - /** Returns `true` if this address represents an IPv4 address. */ - bool - is_v4 () const noexcept - { - return m_type == ipv4; - } - - /** Returns `true` if this address represents an IPv6 address. */ - bool - is_v6() const noexcept - { - return m_type == ipv6; - } - - /** Returns the IPv4 address. - Precondition: - is_v4() == `true` - */ - AddressV4 const& - to_v4 () const - { - if (!is_v4 ()) - throw std::bad_cast(); - return m_v4; - } - - /** Returns the IPv6 address. - Precondition: - is_v6() == `true` - */ - AddressV6 const& - to_v6 () const - { - if (!is_v6 ()) - throw std::bad_cast(); - return m_v6; - } - - /** Returns `true` if this address represents 0.0.0.0 */ - bool - is_any () const - { - return is_v4 () ? m_v4 == IP::AddressV4::any () - : false; // m_v6 == IP::AddressV6::any(); - } - - template - friend - void - hash_append(Hasher& h, Address const& addr) noexcept - { - using beast::hash_append; - if (addr.is_v4 ()) - hash_append(h, addr.to_v4 ()); - else if (addr.is_v6 ()) - hash_append(h, addr.to_v6 ()); - else - assert (false); - } - - /** Arithmetic comparison. */ - /** @{ */ - friend - bool - operator== (Address const& lhs, Address const& rhs) - { - if (lhs.is_v4 ()) - { - if (rhs.is_v4 ()) - return lhs.to_v4() == rhs.to_v4(); - } - else - { - if (rhs.is_v6 ()) - return lhs.to_v6() == rhs.to_v6(); - } - - return false; - } - - friend - bool - operator< (Address const& lhs, Address const& rhs) - { - if (lhs.m_type < rhs.m_type) - return true; - if (lhs.is_v4 ()) - return lhs.to_v4() < rhs.to_v4(); - return lhs.to_v6() < rhs.to_v6(); - } - - friend - bool - operator!= (Address const& lhs, Address const& rhs) - { - return ! (lhs == rhs); - } - - friend - bool - operator> (Address const& lhs, Address const& rhs) - { - return rhs < lhs; - } - - friend - bool - operator<= (Address const& lhs, Address const& rhs) - { - return ! (lhs > rhs); - } - - friend - bool - operator>= (Address const& lhs, Address const& rhs) - { - return ! (rhs > lhs); - } - /** @} */ - -private: - enum Type - { - ipv4, - ipv6 - }; - - Type m_type; - AddressV4 m_v4; - AddressV6 m_v6; -}; - -//------------------------------------------------------------------------------ - -// Properties + return addr.to_string (); +} /** Returns `true` if this is a loopback address. */ inline bool is_loopback (Address const& addr) { - return (addr.is_v4 ()) - ? is_loopback (addr.to_v4 ()) - : is_loopback (addr.to_v6 ()); + return addr.is_loopback(); } /** Returns `true` if the address is unspecified. */ @@ -251,9 +61,7 @@ inline bool is_unspecified (Address const& addr) { - return (addr.is_v4 ()) - ? is_unspecified (addr.to_v4 ()) - : is_unspecified (addr.to_v6 ()); + return addr.is_unspecified(); } /** Returns `true` if the address is a multicast address. */ @@ -261,9 +69,7 @@ inline bool is_multicast (Address const& addr) { - return (addr.is_v4 ()) - ? is_multicast (addr.to_v4 ()) - : is_multicast (addr.to_v6 ()); + return addr.is_multicast(); } /** Returns `true` if the address is a private unroutable address. */ @@ -286,51 +92,24 @@ is_public (Address const& addr) : is_public (addr.to_v6 ()); } -//------------------------------------------------------------------------------ - -/** Returns the address represented as a string. */ -inline std::string to_string (Address const& addr) -{ - return addr.to_string (); -} - -/** Output stream conversion. */ -template -OutputStream& -operator<< (OutputStream& os, Address const& addr) -{ - return os << to_string (addr); -} - -/** Input stream conversion. */ -inline -std::istream& -operator>> (std::istream& is, Address& addr) -{ - // VFALCO TODO Support ipv6! - AddressV4 addrv4; - is >> addrv4; - addr = Address (addrv4); - return is; -} - -inline -std::pair -Address::from_string (std::string const& s) -{ - std::stringstream is (s); - Address addr; - is >> addr; - if (! is.fail() && is.rdbuf()->in_avail() == 0) - return std::make_pair (addr, true); - return std::make_pair (Address (), false); -} - -} } //------------------------------------------------------------------------------ +template +void +hash_append(Hasher& h, beast::IP::Address const& addr) noexcept +{ + using beast::hash_append; + if (addr.is_v4 ()) + hash_append(h, addr.to_v4().to_bytes()); + else if (addr.is_v6 ()) + hash_append(h, addr.to_v6().to_bytes()); + else + assert (false); +} +} + namespace std { template <> struct hash diff --git a/src/ripple/beast/net/IPAddressV4.h b/src/ripple/beast/net/IPAddressV4.h index 2e5532ac3..428d10036 100644 --- a/src/ripple/beast/net/IPAddressV4.h +++ b/src/ripple/beast/net/IPAddressV4.h @@ -21,141 +21,17 @@ #define BEAST_NET_IPADDRESSV4_H_INCLUDED #include - #include #include #include #include #include +#include namespace beast { namespace IP { -/** Represents a version 4 IP address. */ -struct AddressV4 -{ - /** Default constructor represents the 'any' address. */ - AddressV4 (); - - /** Construct from a 32-bit unsigned. - @note Octets are formed in order from the MSB to the LSB. - */ - explicit AddressV4 (std::uint32_t value_); - - /** Construct from four individual octets.. - @note The resulting address is a.b.c.d - */ - AddressV4 (std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d); - - /** Create an address from an IPv4 address string in dotted decimal form. - @return A pair with the address, and bool set to `true` on success. - */ - static std::pair from_string (std::string const& s); - - /** Returns an address that represents 'any' address. */ - static AddressV4 any () - { return AddressV4(); } - - /** Returns an address that represents the loopback address. */ - static AddressV4 loopback () - { return AddressV4 (0x7f000001); } - - /** Returns an address that represents the broadcast address. */ - static AddressV4 broadcast () - { return AddressV4 (0xffffffff); } - - /** Returns the broadcast address for the specified address. */ - static AddressV4 broadcast (AddressV4 const& address); - - /** Returns the broadcast address corresponding to the address and mask. */ - static AddressV4 broadcast ( - AddressV4 const& address, AddressV4 const& mask); - - /** Returns `true` if this is a broadcast address. */ - bool is_broadcast () const - { return *this == broadcast (*this); } - - /** Returns the address class for the given address. - @note Class 'D' represents multicast addresses (224.*.*.*). - */ - static char get_class (AddressV4 const& address); - - /** Returns the netmask for the address class or address. */ - /** @{ */ - static AddressV4 netmask (char address_class); - static AddressV4 netmask (AddressV4 const& v); - /** @} */ - - /** Arithmetic comparison. */ - /** @{ */ - friend bool operator== (AddressV4 const& lhs, AddressV4 const& rhs) - { return lhs.value == rhs.value; } - friend bool operator< (AddressV4 const& lhs, AddressV4 const& rhs) - { return lhs.value < rhs.value; } - - friend bool operator!= (AddressV4 const& lhs, AddressV4 const& rhs) - { return ! (lhs == rhs); } - friend bool operator> (AddressV4 const& lhs, AddressV4 const& rhs) - { return rhs < lhs; } - friend bool operator<= (AddressV4 const& lhs, AddressV4 const& rhs) - { return ! (lhs > rhs); } - friend bool operator>= (AddressV4 const& lhs, AddressV4 const& rhs) - { return ! (rhs > lhs); } - /** @} */ - - /** Array indexing for reading and writing indiviual octets. */ - /** @{ */ - template - class Proxy - { - public: - using Pointer = typename std::conditional < - IsConst, std::uint32_t const*, std::uint32_t*>::type; - - Proxy (int shift, Pointer value) - : m_shift (shift) - , m_value (value) - { - } - - operator std::uint8_t() const - { - return ((*m_value)>>m_shift) & 0xff; - } - - template - Proxy& operator= (IntegralType v) - { - (*m_value) = - ( (*m_value) & (~((0xff)< operator[] (std::size_t index) const; - Proxy operator[] (std::size_t index); - /** @} */ - - /** The value as a 32 bit unsigned. */ - std::uint32_t value; -}; - -//------------------------------------------------------------------------------ - -/** Returns `true` if this is a loopback address. */ -bool is_loopback (AddressV4 const& addr); - -/** Returns `true` if the address is unspecified. */ -bool is_unspecified (AddressV4 const& addr); - -/** Returns `true` if the address is a multicast address. */ -bool is_multicast (AddressV4 const& addr); +using AddressV4 = boost::asio::ip::address_v4; /** Returns `true` if the address is a private unroutable address. */ bool is_private (AddressV4 const& addr); @@ -163,42 +39,12 @@ bool is_private (AddressV4 const& addr); /** Returns `true` if the address is a public routable address. */ bool is_public (AddressV4 const& addr); -//------------------------------------------------------------------------------ - -/** Returns the address represented as a string. */ -std::string to_string (AddressV4 const& addr); - -/** Output stream conversion. */ -template -OutputStream& operator<< (OutputStream& os, AddressV4 const& addr) - { return os << to_string (addr); } - -/** Input stream conversion. */ -std::istream& operator>> (std::istream& is, AddressV4& addr); +/** Returns the address class for the given address. + @note Class 'D' represents multicast addresses (224.*.*.*). +*/ +char get_class (AddressV4 const& address); } - -template -struct is_contiguously_hashable - : public std::integral_constant -{ - explicit is_contiguously_hashable() = default; -}; - -} - -//------------------------------------------------------------------------------ - -namespace std { -/** std::hash support. */ -template <> -struct hash -{ - explicit hash() = default; - - std::size_t operator() (beast::IP::AddressV4 const& addr) const - { return addr.value; } -}; } #endif diff --git a/src/ripple/beast/net/IPAddressV6.h b/src/ripple/beast/net/IPAddressV6.h index c655d1088..9e541a500 100644 --- a/src/ripple/beast/net/IPAddressV6.h +++ b/src/ripple/beast/net/IPAddressV6.h @@ -26,45 +26,12 @@ #include #include #include +#include namespace beast { namespace IP { -/** Represents a version 4 IP address. */ -struct AddressV6 -{ - explicit AddressV6() = default; - - // VFALCO TODO - - /** Arithmetic comparison. */ - /** @{ */ - friend bool operator== (AddressV6 const&, AddressV6 const&) - { assert(false); return false; } - friend bool operator< (AddressV6 const&, AddressV6 const&) - { assert(false); return false; } - - friend bool operator!= (AddressV6 const& lhs, AddressV6 const& rhs) - { return ! (lhs == rhs); } - friend bool operator> (AddressV6 const& lhs, AddressV6 const& rhs) - { return rhs < lhs; } - friend bool operator<= (AddressV6 const& lhs, AddressV6 const& rhs) - { return ! (lhs > rhs); } - friend bool operator>= (AddressV6 const& lhs, AddressV6 const& rhs) - { return ! (rhs > lhs); } - /** @} */ -}; - -//------------------------------------------------------------------------------ - -/** Returns `true` if this is a loopback address. */ -bool is_loopback (AddressV6 const& addr); - -/** Returns `true` if the address is unspecified. */ -bool is_unspecified (AddressV6 const& addr); - -/** Returns `true` if the address is a multicast address. */ -bool is_multicast (AddressV6 const& addr); +using AddressV6 = boost::asio::ip::address_v6; /** Returns `true` if the address is a private unroutable address. */ bool is_private (AddressV6 const& addr); @@ -72,41 +39,7 @@ bool is_private (AddressV6 const& addr); /** Returns `true` if the address is a public routable address. */ bool is_public (AddressV6 const& addr); -//------------------------------------------------------------------------------ - -template -void -hash_append(Hasher&, AddressV6 const&) -{ - assert(false); } - -/** Returns the address represented as a string. */ -std::string to_string (AddressV6 const& addr); - -/** Output stream conversion. */ -template -OutputStream& operator<< (OutputStream& os, AddressV6 const& addr) - { return os << to_string (addr); } - -/** Input stream conversion. */ -std::istream& operator>> (std::istream& is, AddressV6& addr); - -} -} - -//------------------------------------------------------------------------------ - -namespace std { -/** std::hash support. */ -template <> -struct hash -{ - explicit hash() = default; - - std::size_t operator() (beast::IP::AddressV6 const& addr) const - { assert(false); return 0; } -}; } #endif diff --git a/src/ripple/beast/net/IPEndpoint.h b/src/ripple/beast/net/IPEndpoint.h index 680362917..e4ced026d 100644 --- a/src/ripple/beast/net/IPEndpoint.h +++ b/src/ripple/beast/net/IPEndpoint.h @@ -48,7 +48,6 @@ public: */ static std::pair from_string_checked (std::string const& s); static Endpoint from_string (std::string const& s); - static Endpoint from_string_altform (std::string const& s); /** Returns a string representing the endpoint. */ std::string to_string () const; @@ -71,9 +70,9 @@ public: { return m_addr.is_v4(); } bool is_v6 () const { return m_addr.is_v6(); } - AddressV4 const& to_v4 () const + AddressV4 const to_v4 () const { return m_addr.to_v4 (); } - AddressV6 const& to_v6 () const + AddressV6 const to_v6 () const { return m_addr.to_v6 (); } /** @} */ diff --git a/src/ripple/beast/net/detail/Parse.h b/src/ripple/beast/net/detail/Parse.h deleted file mode 100644 index 33c72e25a..000000000 --- a/src/ripple/beast/net/detail/Parse.h +++ /dev/null @@ -1,103 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_DETAIL_PARSE_H_INCLUDED -#define BEAST_NET_DETAIL_PARSE_H_INCLUDED - -#include -#include - -namespace beast { -namespace IP { - -namespace detail { - -/** Require and consume the specified character from the input. - @return `true` if the character matched. -*/ -template -bool expect(InputStream& is, char v) -{ - char c; - if (is.get(c) && v == c) - return true; - is.unget(); - is.setstate (std::ios_base::failbit); - return false; -} - -/** Require and consume whitespace from the input. - @return `true` if the character matched. -*/ -template -bool expect_whitespace (InputStream& is) -{ - char c; - if (is.get(c) && isspace(static_cast(c))) - return true; - is.unget(); - is.setstate (std::ios_base::failbit); - return false; -} - -/** Used to disambiguate 8-bit integers from characters. */ -template -struct integer_holder -{ - IntType* pi; - explicit integer_holder (IntType& i) - : pi (&i) - { - } - template - IntType& operator= (OtherIntType o) const - { - *pi = o; - return *pi; - } -}; - -/** Parse 8-bit unsigned integer. */ -template -InputStream& operator>> (InputStream& is, integer_holder const& i) -{ - std::uint16_t v; - is >> v; - if (! (v>=0 && v<=255)) - { - is.setstate (std::ios_base::failbit); - return is; - } - i = std::uint8_t(v); - return is; -} - -/** Free function for template argument deduction. */ -template -integer_holder integer (IntType& i) -{ - return integer_holder (i); -} - -} - -} -} - -#endif diff --git a/src/ripple/beast/net/impl/IPAddressConversion.cpp b/src/ripple/beast/net/impl/IPAddressConversion.cpp index c6278da65..3e6193dae 100644 --- a/src/ripple/beast/net/impl/IPAddressConversion.cpp +++ b/src/ripple/beast/net/impl/IPAddressConversion.cpp @@ -24,43 +24,22 @@ namespace IP { Endpoint from_asio (boost::asio::ip::address const& address) { - if (address.is_v4 ()) - { - boost::asio::ip::address_v4::bytes_type const bytes ( - address.to_v4().to_bytes()); - return Endpoint (AddressV4 ( - bytes [0], bytes [1], bytes [2], bytes [3])); - } - - // VFALCO TODO IPv6 support - assert(false); - return Endpoint(); + return Endpoint {address}; } Endpoint from_asio (boost::asio::ip::tcp::endpoint const& endpoint) { - return from_asio (endpoint.address()).at_port (endpoint.port()); + return Endpoint {endpoint.address(), endpoint.port()}; } boost::asio::ip::address to_asio_address (Endpoint const& endpoint) { - if (endpoint.address().is_v4()) - { - return boost::asio::ip::address ( - boost::asio::ip::address_v4 ( - endpoint.address().to_v4().value)); - } - - // VFALCO TODO IPv6 support - assert(false); - return boost::asio::ip::address ( - boost::asio::ip::address_v6 ()); + return endpoint.address(); } boost::asio::ip::tcp::endpoint to_asio_endpoint (Endpoint const& endpoint) { - return boost::asio::ip::tcp::endpoint ( - to_asio_address (endpoint), endpoint.port()); + return boost::asio::ip::tcp::endpoint {endpoint.address(), endpoint.port()}; } } diff --git a/src/ripple/beast/net/impl/IPAddressV4.cpp b/src/ripple/beast/net/impl/IPAddressV4.cpp index ed75b0baf..d437d7b6e 100644 --- a/src/ripple/beast/net/impl/IPAddressV4.cpp +++ b/src/ripple/beast/net/impl/IPAddressV4.cpp @@ -21,7 +21,6 @@ #endif #include -#include #include #include @@ -29,154 +28,26 @@ namespace beast { namespace IP { -AddressV4::AddressV4 () - : value (0) -{ -} - -AddressV4::AddressV4 (std::uint32_t value_) - : value (value_) -{ -} - -AddressV4::AddressV4 (std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) - : value ((a<<24)|(b<<16)|(c<<8)|d) -{ -} - -std::pair AddressV4::from_string (std::string const& s) -{ - std::stringstream is (s); - AddressV4 addr; - is >> addr; - if (! is.fail() && is.rdbuf()->in_avail() == 0) - return std::make_pair (addr, true); - return std::make_pair (AddressV4 (), false); -} - -AddressV4 AddressV4::broadcast (AddressV4 const& address) -{ - return broadcast (address, netmask (address)); -} - -AddressV4 AddressV4::broadcast ( - AddressV4 const& address, AddressV4 const& mask) -{ - return AddressV4 (address.value | (mask.value ^ 0xffffffff)); -} - -char AddressV4::get_class (AddressV4 const& addr) -{ - static char const* table = "AAAABBCD"; - return table [(addr.value & 0xE0000000) >> 29]; -} - -AddressV4 AddressV4::netmask (char address_class) -{ - switch (address_class) - { - case 'A': return AddressV4 (0xff000000); - case 'B': return AddressV4 (0xffff0000); - case 'C': return AddressV4 (0xffffff00); - case 'D': - default: - break; - } - return AddressV4 (0xffffffff); -} - -AddressV4 AddressV4::netmask (AddressV4 const& addr) -{ - return netmask (get_class (addr)); -} - -AddressV4::Proxy AddressV4::operator[] (std::size_t index) const -{ - switch (index) - { - default: - throw std::out_of_range ("bad array index"); - case 0: return Proxy (24, &value); - case 1: return Proxy (16, &value); - case 2: return Proxy ( 8, &value); - case 3: return Proxy ( 0, &value); - }; -}; - -AddressV4::Proxy AddressV4::operator[] (std::size_t index) -{ - switch (index) - { - default: - throw std::out_of_range ("bad array index"); - case 0: return Proxy (24, &value); - case 1: return Proxy (16, &value); - case 2: return Proxy ( 8, &value); - case 3: return Proxy ( 0, &value); - }; -}; - -//------------------------------------------------------------------------------ - -bool is_loopback (AddressV4 const& addr) -{ - return (addr.value & 0xff000000) == 0x7f000000; -} - -bool is_unspecified (AddressV4 const& addr) -{ - return addr.value == 0; -} - -bool is_multicast (AddressV4 const& addr) -{ - return (addr.value & 0xf0000000) == 0xe0000000; -} - bool is_private (AddressV4 const& addr) { return - ((addr.value & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.# - ((addr.value & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.# - ((addr.value & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.# - is_loopback (addr); + ((addr.to_ulong() & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.# + ((addr.to_ulong() & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.# + ((addr.to_ulong() & 0xffff0000) == 0xc0a80000) || // Prefix /16 192.168.#.# + addr.is_loopback(); } bool is_public (AddressV4 const& addr) { return ! is_private (addr) && - ! is_multicast (addr); + ! addr.is_multicast(); } -//------------------------------------------------------------------------------ - -std::string to_string (AddressV4 const& addr) +char get_class (AddressV4 const& addr) { - std::string s; - s.reserve (15); - s = - std::to_string (addr[0]) + "." + - std::to_string (addr[1]) + "." + - std::to_string (addr[2]) + "." + - std::to_string (addr[3]); - return s; -} - -std::istream& operator>> (std::istream& is, AddressV4& addr) -{ - std::uint8_t octet [4]; - is >> IP::detail::integer (octet [0]); - for (int i = 1; i < 4; ++i) - { - if (!is || !IP::detail::expect(is, '.')) - return is; - is >> IP::detail::integer (octet [i]); - if (!is) - return is; - } - addr = AddressV4 (octet[0], octet[1], octet[2], octet[3]); - return is; + static char const* table = "AAAABBCD"; + return table [(addr.to_ulong() & 0xE0000000) >> 29]; } } diff --git a/src/ripple/beast/net/impl/IPAddressV6.cpp b/src/ripple/beast/net/impl/IPAddressV6.cpp index 1a286488e..0e8d88714 100644 --- a/src/ripple/beast/net/impl/IPAddressV6.cpp +++ b/src/ripple/beast/net/impl/IPAddressV6.cpp @@ -21,62 +21,25 @@ #endif #include +#include namespace beast { namespace IP { -//------------------------------------------------------------------------------ - -bool is_loopback (AddressV6 const&) +bool is_private (AddressV6 const& addr) { - // VFALCO TODO - assert(false); - return false; + return ((addr.to_bytes()[0] & 0xfd) || // TODO fc00::/8 too ? + (addr.is_v4_mapped() && is_private(addr.to_v4())) ); } -bool is_unspecified (AddressV6 const&) +bool is_public (AddressV6 const& addr) { - // VFALCO TODO - assert(false); - return false; + // TODO is this correct? + return + ! is_private (addr) && + ! addr.is_multicast(); } -bool is_multicast (AddressV6 const&) -{ - // VFALCO TODO - assert(false); - return false; -} - -bool is_private (AddressV6 const&) -{ - // VFALCO TODO - assert(false); - return false; -} - -bool is_public (AddressV6 const&) -{ - // VFALCO TODO - assert(false); - return false; -} - -//------------------------------------------------------------------------------ - -std::string to_string (AddressV6 const&) -{ - // VFALCO TODO - assert(false); - return ""; -} - -std::istream& operator>> (std::istream& is, AddressV6&) -{ - // VFALCO TODO - assert(false); - return is; -} } } diff --git a/src/ripple/beast/net/impl/IPEndpoint.cpp b/src/ripple/beast/net/impl/IPEndpoint.cpp index 9f3cec9f8..d757abac4 100644 --- a/src/ripple/beast/net/impl/IPEndpoint.cpp +++ b/src/ripple/beast/net/impl/IPEndpoint.cpp @@ -21,7 +21,6 @@ #endif #include -#include namespace beast { namespace IP { @@ -44,7 +43,7 @@ std::pair Endpoint::from_string_checked (std::string const& s) is >> endpoint; if (! is.fail() && is.rdbuf()->in_avail() == 0) return std::make_pair (endpoint, true); - return std::make_pair (Endpoint (), false); + return std::make_pair (Endpoint {}, false); } Endpoint Endpoint::from_string (std::string const& s) @@ -53,69 +52,26 @@ Endpoint Endpoint::from_string (std::string const& s) from_string_checked (s)); if (result.second) return result.first; - return Endpoint(); -} - -// VFALCO NOTE This is a hack to support legacy data format -// -Endpoint Endpoint::from_string_altform (std::string const& s) -{ - // Accept the regular form if it parses - { - Endpoint ep (Endpoint::from_string (s)); - if (! is_unspecified (ep)) - return ep; - } - - // Now try the alt form - std::stringstream is (s); - - AddressV4 v4; - is >> v4; - if (! is.fail()) - { - Endpoint ep (v4); - - if (is.rdbuf()->in_avail()>0) - { - if (! IP::detail::expect_whitespace (is)) - return Endpoint(); - - while (is.rdbuf()->in_avail()>0) - { - char c; - is.get(c); - if (!isspace (static_cast(c))) - { - is.unget(); - break; - } - } - - Port port; - is >> port; - if (is.fail()) - return Endpoint(); - - return ep.at_port (port); - } - else - { - // Just an address with no port - return ep; - } - } - - // Could be V6 here... - - return Endpoint(); + return Endpoint {}; } std::string Endpoint::to_string () const { - std::string s (address ().to_string ()); - if (port() != 0) - s = s + ":" + std::to_string (port()); + std::string s; + s.reserve( + (address().is_v6() ? INET6_ADDRSTRLEN-1 : 15) + + (port() == 0 ? 0 : 6 + (address().is_v6() ? 2 : 0))); + + if (port() != 0 && address().is_v6()) + s += '['; + s += address ().to_string(); + if (port()) + { + if (address().is_v6()) + s += ']'; + s += ":" + std::to_string (port()); + } + return s; } @@ -138,34 +94,88 @@ bool operator< (Endpoint const& lhs, Endpoint const& rhs) std::istream& operator>> (std::istream& is, Endpoint& endpoint) { - // VFALCO TODO Support ipv6! + std::string addrStr; + // valid addresses only need INET6_ADDRSTRLEN-1 chars, but allow the extra + // char to check for invalid lengths + addrStr.reserve(INET6_ADDRSTRLEN); + char i {0}; + char readTo {0}; + is.get(i); + if (i == '[') // we are an IPv6 endpoint + readTo = ']'; + else + addrStr+=i; - Address addr; - is >> addr; - if (is.fail()) - return is; - - if (is.rdbuf()->in_avail()>0) + while (is && is.rdbuf()->in_avail() > 0 && is.get(i)) { - char c; - is.get(c); - if (c != ':') + // NOTE: There is a legacy data format + // that allowed space to be used as address / port separator + // so we continue to honor that here by assuming we are at the end + // of the address portion if we hit a space (or the separator + // we were expecting to see) + if (isspace(static_cast(i)) || (readTo && i == readTo)) + break; + + if ((i == '.') || + (i >= '0' && i <= ':') || + (i >= 'a' && i <= 'f') || + (i >= 'A' && i <= 'F')) + { + addrStr+=i; + + // don't exceed a reasonable length... + if ( addrStr.size() == INET6_ADDRSTRLEN || + (readTo && readTo == ':' && addrStr.size() > 15)) + { + is.setstate (std::ios_base::failbit); + return is; + } + + if (! readTo && (i == '.' || i == ':')) + { + // if we see a dot first, must be IPv4 + // otherwise must be non-bracketed IPv6 + readTo = (i == '.') ? ':' : ' '; + } + } + else // invalid char { is.unget(); - endpoint = Endpoint (addr); + is.setstate (std::ios_base::failbit); return is; } + } + if (readTo == ']' && is.rdbuf()->in_avail() > 0) + { + is.get(i); + if (! (isspace(static_cast(i)) || i == ':')) + { + is.unget(); + is.setstate (std::ios_base::failbit); + return is; + } + } + + boost::system::error_code ec; + auto addr = Address::from_string(addrStr, ec); + if (ec) + { + is.setstate (std::ios_base::failbit); + return is; + } + + if (is.rdbuf()->in_avail() > 0) + { Port port; is >> port; if (is.fail()) return is; - endpoint = Endpoint (addr, port); - return is; } + else + endpoint = Endpoint (addr); - endpoint = Endpoint (addr); return is; } diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 6cc359395..5157a3d51 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -26,7 +26,6 @@ #include #include #include -#include // VFALCO FIX: This include should not be here #include // VFALCO FIX: This include should not be here #include #include @@ -174,8 +173,7 @@ public: std::size_t WORKERS = 0; // These override the command line client settings - boost::optional rpc_ip; - boost::optional rpc_port; + boost::optional rpc_ip; std::unordered_set> features; diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/ripple/net/impl/RPCCall.cpp index 11eff5444..a91bbd6d9 100644 --- a/src/ripple/net/impl/RPCCall.cpp +++ b/src/ripple/net/impl/RPCCall.cpp @@ -1355,9 +1355,10 @@ rpcClient(std::vector const& args, } if (config.rpc_ip) - setup.client.ip = config.rpc_ip->to_string(); - if (config.rpc_port) - setup.client.port = *config.rpc_port; + { + setup.client.ip = config.rpc_ip->address().to_string(); + setup.client.port = config.rpc_ip->port(); + } Json::Value jvParams (Json::arrayValue); diff --git a/src/ripple/overlay/impl/OverlayImpl.cpp b/src/ripple/overlay/impl/OverlayImpl.cpp index 8ea11175c..679582425 100644 --- a/src/ripple/overlay/impl/OverlayImpl.cpp +++ b/src/ripple/overlay/impl/OverlayImpl.cpp @@ -1048,11 +1048,9 @@ setup_Overlay (BasicConfig const& config) set (ip, "public_ip", section); if (! ip.empty ()) { - bool valid; - std::tie (setup.public_ip, valid) = - beast::IP::Address::from_string (ip); - if (! valid || ! setup.public_ip.is_v4() || - is_private (setup.public_ip)) + boost::system::error_code ec; + setup.public_ip = beast::IP::Address::from_string (ip, ec); + if (ec || beast::IP::is_private (setup.public_ip)) Throw ("Configured public IP is invalid"); } return setup; diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp index 33c03ad04..22ac787cb 100644 --- a/src/ripple/overlay/impl/PeerImp.cpp +++ b/src/ripple/overlay/impl/PeerImp.cpp @@ -1019,37 +1019,75 @@ PeerImp::onMessage (std::shared_ptr const& m) std::vector endpoints; - endpoints.reserve (m->endpoints().size()); - - for (int i = 0; i < m->endpoints ().size (); ++i) + if (m->endpoints_v2().size()) { - PeerFinder::Endpoint endpoint; - protocol::TMEndpoint const& tm (m->endpoints(i)); - - // hops - endpoint.hops = tm.hops(); - - // ipv4 - if (endpoint.hops > 0) + endpoints.reserve (m->endpoints_v2().size()); + for (auto const& tm : m->endpoints_v2 ()) { - in_addr addr; - addr.s_addr = tm.ipv4().ipv4(); - beast::IP::AddressV4 v4 (ntohl (addr.s_addr)); - endpoint.address = beast::IP::Endpoint (v4, tm.ipv4().ipv4port ()); - } - else - { - // This Endpoint describes the peer we are connected to. - // We will take the remote address seen on the socket and - // store that in the IP::Endpoint. If this is the first time, - // then we'll verify that their listener can receive incoming - // by performing a connectivity test. - // - endpoint.address = remote_address_.at_port ( - tm.ipv4().ipv4port ()); - } + // these endpoint strings support ipv4 and ipv6 + auto result = beast::IP::Endpoint::from_string_checked(tm.endpoint()); + if (! result.second) + { + JLOG(p_journal_.error()) << + "failed to parse incoming endpoint: {" << + tm.endpoint() << "}"; + continue; + } - endpoints.push_back (endpoint); + // If hops == 0, this Endpoint describes the peer we are connected + // to -- in that case, we take the remote address seen on the + // socket and store that in the IP::Endpoint. If this is the first + // time, then we'll verify that their listener can receive incoming + // by performing a connectivity test. if hops > 0, then we just + // take the address/port we were given + + endpoints.emplace_back( + tm.hops() > 0 ? + result.first : + remote_address_.at_port(result.first.port()), + tm.hops()); + JLOG(p_journal_.trace()) << + "got v2 EP: " << endpoints.back().address << + ", hops = " << endpoints.back().hops; + } + } + else + { + // this branch can be removed once the entire network is operating with + // endpoint_v2() items (strings) + endpoints.reserve (m->endpoints().size()); + for (int i = 0; i < m->endpoints ().size (); ++i) + { + PeerFinder::Endpoint endpoint; + protocol::TMEndpoint const& tm (m->endpoints(i)); + + // hops + endpoint.hops = tm.hops(); + + // ipv4 + if (endpoint.hops > 0) + { + in_addr addr; + addr.s_addr = tm.ipv4().ipv4(); + beast::IP::AddressV4 v4 (ntohl (addr.s_addr)); + endpoint.address = beast::IP::Endpoint (v4, tm.ipv4().ipv4port ()); + } + else + { + // This Endpoint describes the peer we are connected to. + // We will take the remote address seen on the socket and + // store that in the IP::Endpoint. If this is the first time, + // then we'll verify that their listener can receive incoming + // by performing a connectivity test. + // + endpoint.address = remote_address_.at_port ( + tm.ipv4().ipv4port ()); + } + endpoints.push_back (endpoint); + JLOG(p_journal_.trace()) << + "got v1 EP: " << endpoints.back().address << + ", hops = " << endpoints.back().hops; + } } if (! endpoints.empty()) diff --git a/src/ripple/overlay/impl/PeerImp.h b/src/ripple/overlay/impl/PeerImp.h index 67e118a44..3e3377e88 100644 --- a/src/ripple/overlay/impl/PeerImp.h +++ b/src/ripple/overlay/impl/PeerImp.h @@ -514,16 +514,24 @@ PeerImp::sendEndpoints (FwdIt first, FwdIt last) for (;first != last; ++first) { auto const& ep = *first; + // eventually remove endpoints and just keep endpoints_v2 + // (once we are sure the entire network understands endpoints_v2) protocol::TMEndpoint& tme (*tm.add_endpoints()); if (ep.address.is_v4()) tme.mutable_ipv4()->set_ipv4( - beast::toNetworkByteOrder (ep.address.to_v4().value)); + beast::toNetworkByteOrder ( + ep.address.to_v4().to_ulong())); else tme.mutable_ipv4()->set_ipv4(0); tme.mutable_ipv4()->set_ipv4port (ep.address.port()); tme.set_hops (ep.hops); + + // add v2 endpoints (strings) + auto& tme2 (*tm.add_endpoints_v2()); + tme2.set_endpoint(ep.address.to_string()); + tme2.set_hops (ep.hops); } - tm.set_version (1); + tm.set_version (2); send (std::make_shared (tm, protocol::mtENDPOINTS)); } diff --git a/src/ripple/overlay/impl/TMHello.cpp b/src/ripple/overlay/impl/TMHello.cpp index c3fca6d81..e8bf4a85c 100644 --- a/src/ripple/overlay/impl/TMHello.cpp +++ b/src/ripple/overlay/impl/TMHello.cpp @@ -114,19 +114,14 @@ buildHello ( TokenType::NodePublic, app.nodeIdentity().first)); h.set_nodeproof (sig.data(), sig.size()); - // h.set_ipv4port (portNumber); // ignored now h.set_testnet (false); - if (remote.is_v4()) + if (beast::IP::is_public (remote)) { - auto addr = remote.to_v4 (); - if (is_public (addr)) - { - // Connection is to a public IP - h.set_remote_ip (addr.value); - if (public_ip != beast::IP::Address()) - h.set_local_ip (public_ip.to_v4().value); - } + // Connection is to a public IP + h.set_remote_ip_str (remote.to_string()); + if (! public_ip.is_unspecified()) + h.set_local_ip_str (public_ip.to_string()); } // We always advertise ourselves as private in the HELLO message. This @@ -174,13 +169,11 @@ appendHello (boost::beast::http::fields& h, h.insert ("Previous-Ledger", boost::beast::detail::base64_encode ( hello.ledgerprevious())); - if (hello.has_local_ip()) - h.insert ("Local-IP", beast::IP::to_string ( - beast::IP::AddressV4(hello.local_ip()))); + if (hello.has_local_ip_str()) + h.insert ("Local-IP", hello.local_ip_str()); if (hello.has_remote_ip()) - h.insert ("Remote-IP", beast::IP::to_string ( - beast::IP::AddressV4(hello.remote_ip()))); + h.insert ("Remote-IP", hello.remote_ip_str()); } std::vector @@ -306,14 +299,16 @@ parseHello (bool request, boost::beast::http::fields const& h, beast::Journal jo auto const iter = h.find ("Local-IP"); if (iter != h.end()) { - bool valid; - beast::IP::Address address; - std::tie (address, valid) = - beast::IP::Address::from_string (iter->value().to_string()); - if (!valid) + boost::system::error_code ec; + auto address = + beast::IP::Address::from_string (iter->value().to_string(), ec); + if (ec) + { + JLOG(journal.warn()) << "invalid Local-IP: " + << iter->value().to_string(); return boost::none; - if (address.is_v4()) - hello.set_local_ip(address.to_v4().value); + } + hello.set_local_ip_str(address.to_string()); } } @@ -321,14 +316,16 @@ parseHello (bool request, boost::beast::http::fields const& h, beast::Journal jo auto const iter = h.find ("Remote-IP"); if (iter != h.end()) { - bool valid; - beast::IP::Address address; - std::tie (address, valid) = - beast::IP::Address::from_string (iter->value().to_string()); - if (!valid) + boost::system::error_code ec; + auto address = + beast::IP::Address::from_string (iter->value().to_string(), ec); + if (ec) + { + JLOG(journal.warn()) << "invalid Remote-IP: " + << iter->value().to_string(); return boost::none; - if (address.is_v4()) - hello.set_remote_ip(address.to_v4().value); + } + hello.set_remote_ip_str(address.to_string()); } } @@ -412,33 +409,50 @@ verifyHello (protocol::TMHello const& h, return boost::none; } - if (h.has_local_ip () && - is_public (remote) && - remote.is_v4 () && - (remote.to_v4().value != h.local_ip ())) + if (h.has_local_ip_str () && + is_public (remote)) { - // Remote asked us to confirm connection is from - // correct IP - JLOG(journal.info()) << - "Hello: Disconnect: Peer IP is " << - beast::IP::to_string (remote.to_v4()) - << " not " << - beast::IP::to_string (beast::IP::AddressV4 (h.local_ip())); - return boost::none; + boost::system::error_code ec; + auto local_ip = + beast::IP::Address::from_string (h.local_ip_str(), ec); + if (ec) + { + JLOG(journal.warn()) << "invalid local-ip: " << h.local_ip_str(); + return boost::none; + } + + if (remote.address() != local_ip) + { + // Remote asked us to confirm connection is from correct IP + JLOG(journal.info()) << + "Hello: Disconnect: Peer IP is " << remote.address().to_string() + << " not " << local_ip.to_string(); + return boost::none; + } } - if (h.has_remote_ip() && is_public (remote) && - (public_ip != beast::IP::Address()) && - (h.remote_ip() != public_ip.to_v4().value)) + if (h.has_remote_ip_str () && + is_public (remote) && + (! beast::IP::is_unspecified(public_ip))) { - // We know our public IP and peer reports connection - // from some other IP - JLOG(journal.info()) << - "Hello: Disconnect: Our IP is " << - beast::IP::to_string (public_ip.to_v4()) - << " not " << - beast::IP::to_string (beast::IP::AddressV4 (h.remote_ip())); - return boost::none; + boost::system::error_code ec; + auto remote_ip = + beast::IP::Address::from_string (h.remote_ip_str(), ec); + if (ec) + { + JLOG(journal.warn()) << "invalid remote-ip: " << h.remote_ip_str(); + return boost::none; + } + + if (remote_ip != public_ip) + { + // We know our public IP and peer reports connection from some + // other IP + JLOG(journal.info()) << + "Hello: Disconnect: Our IP is " << public_ip.to_string() + << " not " << remote_ip.to_string(); + return boost::none; + } } return publicKey; diff --git a/src/ripple/peerfinder/impl/Logic.h b/src/ripple/peerfinder/impl/Logic.h index 34734311d..ff929649d 100644 --- a/src/ripple/peerfinder/impl/Logic.h +++ b/src/ripple/peerfinder/impl/Logic.h @@ -618,8 +618,15 @@ public: { Endpoint ep; ep.hops = 0; + // we use the unspecified (0) address here because the value is + // irrelevant to recipients. When peers receive an endpoint + // with 0 hops, they use the socket remote_addr instead of the + // value in the message. Furthermore, since the address value + // is ignored, the type/version (ipv4 vs ipv6) doesn't matter + // either. ipv6 has a slightly more compact string + // representation of 0, so use that for self entries. ep.address = beast::IP::Endpoint ( - beast::IP::AddressV4 ()).at_port ( + beast::IP::AddressV6 ()).at_port ( config_.listeningPort); for (auto& t : targets) t.insert (ep); diff --git a/src/ripple/peerfinder/impl/SourceStrings.cpp b/src/ripple/peerfinder/impl/SourceStrings.cpp index 39337fabc..dafce633f 100644 --- a/src/ripple/peerfinder/impl/SourceStrings.cpp +++ b/src/ripple/peerfinder/impl/SourceStrings.cpp @@ -48,7 +48,7 @@ public: { beast::IP::Endpoint ep (beast::IP::Endpoint::from_string (m_strings [i])); if (is_unspecified (ep)) - ep = beast::IP::Endpoint::from_string_altform (m_strings [i]); + ep = beast::IP::Endpoint::from_string (m_strings [i]); if (! is_unspecified (ep)) results.addresses.push_back (ep); } diff --git a/src/ripple/proto/ripple.proto b/src/ripple/proto/ripple.proto index e14090772..4f8b9b117 100644 --- a/src/ripple/proto/ripple.proto +++ b/src/ripple/proto/ripple.proto @@ -89,15 +89,17 @@ message TMHello required bytes nodeProof = 4; optional string fullVersion = 5; optional uint64 netTime = 6; - optional uint32 ipv4Port = 7; + optional uint32 ipv4Port = 7; // NOT USED optional uint32 ledgerIndex = 8; optional bytes ledgerClosed = 9; // our last closed ledger optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger optional bool nodePrivate = 11; // Request to not forward IP. optional TMProofWork proofOfWork = 12; // request/provide proof of work optional bool testNet = 13; // Running as testnet. - optional uint32 local_ip = 14; // our public IP - optional uint32 remote_ip = 15; // IP we see connection from + optional uint32 local_ip = 14; // NOT USED -- our public IP + optional uint32 remote_ip = 15; // NOT USED -- IP we see connection from + optional string local_ip_str = 16; // our public IP + optional string remote_ip_str = 17; // IP we see connection from } // The status of a node in our cluster @@ -234,6 +236,7 @@ message TMIPv4Endpoint required uint32 ipv4Port = 2; } +// this message is obsolete/no longer procesed message TMPeers { repeated TMIPv4Endpoint nodes = 1; @@ -254,6 +257,15 @@ message TMEndpoints required uint32 version = 1; repeated TMEndpoint endpoints = 2; + + // An update to the Endpoint type that uses a string + // to represent endpoints, thus allowing ipv6 or ipv4 addresses + message TMEndpointv2 + { + required string endpoint = 1; + required uint32 hops = 2; + } + repeated TMEndpointv2 endpoints_v2 = 3; }; message TMIndexedObject diff --git a/src/ripple/rpc/impl/Role.cpp b/src/ripple/rpc/impl/Role.cpp index 512a66f80..b515ef08b 100644 --- a/src/ripple/rpc/impl/Role.cpp +++ b/src/ripple/rpc/impl/Role.cpp @@ -41,7 +41,7 @@ ipAllowed (beast::IP::Address const& remoteIp, std::vector const& adminIp) { return std::find_if (adminIp.begin (), adminIp.end (), - [&remoteIp](beast::IP::Address const& ip) { return ip.is_any () || + [&remoteIp](beast::IP::Address const& ip) { return ip.is_unspecified () || ip == remoteIp; }) != adminIp.end (); } diff --git a/src/ripple/rpc/impl/ServerHandlerImp.cpp b/src/ripple/rpc/impl/ServerHandlerImp.cpp index cc3ddf645..a7bcaee46 100644 --- a/src/ripple/rpc/impl/ServerHandlerImp.cpp +++ b/src/ripple/rpc/impl/ServerHandlerImp.cpp @@ -1041,10 +1041,11 @@ setup_Client (ServerHandler::Setup& setup) return; setup.client.secure = iter->protocol.count("https") > 0; - setup.client.ip = iter->ip.to_string(); - // VFALCO HACK! to make localhost work - if (setup.client.ip == "0.0.0.0") - setup.client.ip = "127.0.0.1"; + setup.client.ip = + beast::IP::is_unspecified(iter->ip) ? + // VFALCO HACK! to make localhost work + (iter->ip.is_v6() ? "::1" : "127.0.0.1") : + iter->ip.to_string(); setup.client.port = iter->port; setup.client.user = iter->user; setup.client.password = iter->password; diff --git a/src/ripple/server/impl/Port.cpp b/src/ripple/server/impl/Port.cpp index 0e7bcea9a..7848ded24 100644 --- a/src/ripple/server/impl/Port.cpp +++ b/src/ripple/server/impl/Port.cpp @@ -95,7 +95,7 @@ populate (Section const& section, std::string const& field, std::ostream& log, { if (! allowAllIps) { - log << "0.0.0.0 not allowed'" << + log << addr.first.address() << " not allowed'" << "' for key '" << field << "' in [" << section.name () << "]"; Throw (); @@ -108,8 +108,8 @@ populate (Section const& section, std::string const& field, std::ostream& log, if (has_any && ! ips->empty ()) { - log << "IP specified along with 0.0.0.0 '" << ip << - "' for key '" << field << "' in [" << + log << "IP specified along with " << addr.first.address() << + " '" << ip << "' for key '" << field << "' in [" << section.name () << "]"; Throw (); } diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index b46ee196d..07322fe75 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -172,21 +172,12 @@ private: while (list2.size () < listSize) list2.push_back (randomValidator()); - - using endpoint_type = boost::asio::ip::tcp::endpoint; - using address_type = boost::asio::ip::address; - - // Use ports of 0 to allow OS selection - endpoint_type ep1{address_type::from_string("127.0.0.1"), 0}; - endpoint_type ep2{address_type::from_string("127.0.0.1"), 0}; - auto const sequence = 1; auto const version = 1; NetClock::time_point const expiration = env.timeKeeper().now() + 3600s; TrustedPublisherServer server1( - ep1, env.app().getIOService(), pubSigningKeys1, manifest1, @@ -196,7 +187,6 @@ private: list1); TrustedPublisherServer server2( - ep2, env.app().getIOService(), pubSigningKeys2, manifest2, @@ -205,14 +195,13 @@ private: version, list2); - std::uint16_t const port1 = server1.local_endpoint().port(); - std::uint16_t const port2 = server2.local_endpoint().port(); - + std::stringstream url1, url2; + url1 << "http://" << server1.local_endpoint() << "/validators"; + url2 << "http://" << server2.local_endpoint() << "/validators"; { // fetch single site - std::vector cfgSites( - {"http://127.0.0.1:" + std::to_string(port1) + "/validators"}); + std::vector cfgSites({ url1.str() }); auto sites = std::make_unique ( env.app().getIOService(), env.app().validators(), journal); @@ -229,9 +218,7 @@ private: } { // fetch multiple sites - std::vector cfgSites({ - "http://127.0.0.1:" + std::to_string(port1) + "/validators", - "http://127.0.0.1:" + std::to_string(port2) + "/validators"}); + std::vector cfgSites({ url1.str(), url2.str() }); auto sites = std::make_unique ( env.app().getIOService(), env.app().validators(), journal); diff --git a/src/test/basics/StringUtilities_test.cpp b/src/test/basics/StringUtilities_test.cpp index d7a0d9049..eebe51f41 100644 --- a/src/test/basics/StringUtilities_test.cpp +++ b/src/test/basics/StringUtilities_test.cpp @@ -77,6 +77,9 @@ public: BEAST_EXPECT(parseUrl (pUrl, "Mixed://domain/path")); BEAST_EXPECT(pUrl.scheme == "mixed"); BEAST_EXPECT(pUrl.path == "/path"); + BEAST_EXPECT(parseUrl (pUrl, "scheme://[::1]:123/path")); + BEAST_EXPECT(*pUrl.port == 123); + BEAST_EXPECT(pUrl.domain == "::1"); } void testToString () diff --git a/src/test/beast/IPEndpointCommon.h b/src/test/beast/IPEndpointCommon.h new file mode 100644 index 000000000..dc1361654 --- /dev/null +++ b/src/test/beast/IPEndpointCommon.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2017 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include + +namespace beast { +namespace IP { + +inline Endpoint randomEP (bool v4 = true) +{ + using namespace ripple; + auto dv4 = []() -> AddressV4::bytes_type { + return {{ + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)) + }}; + }; + auto dv6 = []() -> AddressV6::bytes_type { + return {{ + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)), + static_cast(rand_int(1, UINT8_MAX)) + }}; + }; + return Endpoint { + v4 ? Address { AddressV4 {dv4()} } : Address{ AddressV6 {dv6()} }, + rand_int(1, UINT16_MAX) + }; +} + +} +} diff --git a/src/test/beast/IPEndpoint_test.cpp b/src/test/beast/IPEndpoint_test.cpp index 5e486f8b9..e671280dc 100644 --- a/src/test/beast/IPEndpoint_test.cpp +++ b/src/test/beast/IPEndpoint_test.cpp @@ -23,10 +23,12 @@ #endif #include -#include - #include - +#include +#include +#include +#include +#include #include namespace beast { @@ -37,91 +39,111 @@ namespace IP { class IPEndpoint_test : public unit_test::suite { public: - void shouldParseV4 (std::string const& s, std::uint32_t value) + void shouldParseAddrV4 ( + std::string const& s, + std::uint32_t value, + std::string const& normal = "") { - std::pair const result ( - AddressV4::from_string (s)); - - if (BEAST_EXPECT(result.second)) - { - if (BEAST_EXPECT(result.first.value == value)) - { - BEAST_EXPECT(to_string (result.first) == s); - } - } + boost::system::error_code ec; + Address const result {Address::from_string (s, ec)}; + if (! BEAST_EXPECTS(! ec, ec.message())) + return; + if (! BEAST_EXPECTS(result.is_v4(), s + " not v4")) + return; + if (! BEAST_EXPECTS(result.to_v4().to_ulong() == value, + s + " value mismatch")) + return; + BEAST_EXPECTS(result.to_string () == (normal.empty() ? s : normal), + s + " as string"); } - void failParseV4 (std::string const& s) + void failParseAddr (std::string const& s) { - unexpected (AddressV4::from_string (s).second); + boost::system::error_code ec; + auto a = Address::from_string (s, ec); + BEAST_EXPECTS(ec, s + " parses as " + a.to_string()); } void testAddressV4 () { testcase ("AddressV4"); - BEAST_EXPECT(AddressV4().value == 0); - BEAST_EXPECT(is_unspecified (AddressV4())); - BEAST_EXPECT(AddressV4(0x01020304).value == 0x01020304); - BEAST_EXPECT(AddressV4(1, 2, 3, 4).value == 0x01020304); + BEAST_EXPECT(AddressV4{}.to_ulong() == 0); + BEAST_EXPECT(is_unspecified (AddressV4{})); + BEAST_EXPECT(AddressV4{0x01020304}.to_ulong() == 0x01020304); + AddressV4::bytes_type d = {{1,2,3,4}}; + BEAST_EXPECT(AddressV4{d}.to_ulong() == 0x01020304); - unexpected (is_unspecified (AddressV4(1, 2, 3, 4))); + unexpected (is_unspecified (AddressV4{d})); - AddressV4 const v1 (1); - BEAST_EXPECT(AddressV4(v1).value == 1); + AddressV4 const v1 {1}; + BEAST_EXPECT(AddressV4{v1}.to_ulong() == 1); { AddressV4 v; v = v1; - BEAST_EXPECT(v.value == v1.value); + BEAST_EXPECT(v.to_ulong() == v1.to_ulong()); } { AddressV4 v; - v [0] = 1; - v [1] = 2; - v [2] = 3; - v [3] = 4; - BEAST_EXPECT(v.value == 0x01020304); + auto d = v.to_bytes(); + d[0] = 1; + d[1] = 2; + d[2] = 3; + d[3] = 4; + v = AddressV4{d}; + BEAST_EXPECT(v.to_ulong() == 0x01020304); } - BEAST_EXPECT(to_string (AddressV4(0x01020304)) == "1.2.3.4"); + BEAST_EXPECT(AddressV4(0x01020304).to_string() == "1.2.3.4"); - shouldParseV4 ("1.2.3.4", 0x01020304); - shouldParseV4 ("255.255.255.255", 0xffffffff); - shouldParseV4 ("0.0.0.0", 0); + shouldParseAddrV4 ("1.2.3.4", 0x01020304); + shouldParseAddrV4 ("255.255.255.255", 0xffffffff); + shouldParseAddrV4 ("0.0.0.0", 0); - failParseV4 ("."); - failParseV4 (".."); - failParseV4 ("..."); - failParseV4 ("...."); - failParseV4 ("1"); - failParseV4 ("1."); - failParseV4 ("1.2"); - failParseV4 ("1.2."); - failParseV4 ("1.2.3"); - failParseV4 ("1.2.3."); - failParseV4 ("256.0.0.0"); - failParseV4 ("-1.2.3.4"); + failParseAddr ("."); + failParseAddr (".."); + failParseAddr ("..."); + failParseAddr ("...."); +#if BOOST_OS_WINDOWS + // WINDOWS bug in asio - I don't think these should parse + // at all, and in-fact they do not on mac/linux + shouldParseAddrV4 ("1", 0x00000001, "0.0.0.1"); + shouldParseAddrV4 ("1.2", 0x01000002, "1.0.0.2"); + shouldParseAddrV4 ("1.2.3", 0x01020003, "1.2.0.3"); +#else + failParseAddr ("1"); + failParseAddr ("1.2"); + failParseAddr ("1.2.3"); +#endif + failParseAddr ("1."); + failParseAddr ("1.2."); + failParseAddr ("1.2.3."); + failParseAddr ("256.0.0.0"); + failParseAddr ("-1.2.3.4"); } void testAddressV4Proxy () { - testcase ("AddressV4::Proxy"); + testcase ("AddressV4::Bytes"); - AddressV4 v4 (10, 0, 0, 1); - BEAST_EXPECT(v4[0]==10); - BEAST_EXPECT(v4[1]==0); - BEAST_EXPECT(v4[2]==0); - BEAST_EXPECT(v4[3]==1); + AddressV4::bytes_type d1 = {{10,0,0,1}}; + AddressV4 v4 {d1}; + BEAST_EXPECT(v4.to_bytes()[0]==10); + BEAST_EXPECT(v4.to_bytes()[1]==0); + BEAST_EXPECT(v4.to_bytes()[2]==0); + BEAST_EXPECT(v4.to_bytes()[3]==1); BEAST_EXPECT((~((0xff)<<16)) == 0xff00ffff); - v4[1] = 10; - BEAST_EXPECT(v4[0]==10); - BEAST_EXPECT(v4[1]==10); - BEAST_EXPECT(v4[2]==0); - BEAST_EXPECT(v4[3]==1); + auto d2 = v4.to_bytes(); + d2[1] = 10; + v4 = AddressV4{d2}; + BEAST_EXPECT(v4.to_bytes()[0]==10); + BEAST_EXPECT(v4.to_bytes()[1]==10); + BEAST_EXPECT(v4.to_bytes()[2]==0); + BEAST_EXPECT(v4.to_bytes()[3]==1); } //-------------------------------------------------------------------------- @@ -130,76 +152,160 @@ public: { testcase ("Address"); - std::pair result ( - Address::from_string ("1.2.3.4")); - BEAST_EXPECT(result.second); - if (BEAST_EXPECT(result.first.is_v4 ())) - BEAST_EXPECT(result.first.to_v4() == AddressV4 (1, 2, 3, 4)); + boost::system::error_code ec; + Address result {Address::from_string ("1.2.3.4", ec)}; + AddressV4::bytes_type d = {{1,2,3,4}}; + BEAST_EXPECT(! ec); + BEAST_EXPECT( + result.is_v4 () && + result.to_v4() == AddressV4{d}); } //-------------------------------------------------------------------------- + void shouldParseEPV4 ( + std::string const& s, + AddressV4::bytes_type const& value, + std::uint16_t p, + std::string const& normal = "") + { + auto result {Endpoint::from_string_checked (s)}; + if (! BEAST_EXPECT(result.second)) + return; + if (! BEAST_EXPECT(result.first.address().is_v4 ())) + return; + if (! BEAST_EXPECT(result.first.address().to_v4() == AddressV4 {value})) + return; + + BEAST_EXPECT(result.first.port() == p); + BEAST_EXPECT(to_string (result.first) == (normal.empty() ? s : normal)); + } + + void shouldParseEPV6 ( + std::string const& s, + AddressV6::bytes_type const& value, + std::uint16_t p, + std::string const& normal = "") + { + auto result {Endpoint::from_string_checked (s)}; + if (! BEAST_EXPECT(result.second)) + return; + if (! BEAST_EXPECT(result.first.address().is_v6 ())) + return; + if (! BEAST_EXPECT(result.first.address().to_v6() == AddressV6 {value})) + return; + + BEAST_EXPECT(result.first.port() == p); + BEAST_EXPECT(to_string (result.first) == (normal.empty() ? s : normal)); + } + + void failParseEP (std::string s) + { + auto a1 = Endpoint::from_string(s); + BEAST_EXPECTS(is_unspecified (a1), s + " parses as " + a1.to_string()); + + auto a2 = Endpoint::from_string(s); + BEAST_EXPECTS(is_unspecified (a2), s + " parses as " + a2.to_string()); + + boost::replace_last(s, ":", " "); + auto a3 = Endpoint::from_string(s); + BEAST_EXPECTS(is_unspecified (a3), s + " parses as " + a3.to_string()); + } + void testEndpoint () { testcase ("Endpoint"); - { - std::pair result ( - Endpoint::from_string_checked ("1.2.3.4")); - BEAST_EXPECT(result.second); - if (BEAST_EXPECT(result.first.address().is_v4 ())) - { - BEAST_EXPECT(result.first.address().to_v4() == - AddressV4 (1, 2, 3, 4)); - BEAST_EXPECT(result.first.port() == 0); - BEAST_EXPECT(to_string (result.first) == "1.2.3.4"); - } - } - - { - std::pair result ( - Endpoint::from_string_checked ("1.2.3.4:5")); - BEAST_EXPECT(result.second); - if (BEAST_EXPECT(result.first.address().is_v4 ())) - { - BEAST_EXPECT(result.first.address().to_v4() == - AddressV4 (1, 2, 3, 4)); - BEAST_EXPECT(result.first.port() == 5); - BEAST_EXPECT(to_string (result.first) == "1.2.3.4:5"); - } - } + shouldParseEPV4("1.2.3.4", {{1,2,3,4}}, 0); + shouldParseEPV4("1.2.3.4:5", {{1,2,3,4}}, 5); + shouldParseEPV4("1.2.3.4 5", {{1,2,3,4}}, 5, "1.2.3.4:5"); + shouldParseEPV6( + "2001:db8:a0b:12f0::1", + {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, + 0); + shouldParseEPV6( + "[2001:db8:a0b:12f0::1]:8", + {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}}, + 8); + shouldParseEPV6( + "[2001:2002:2003:2004:2005:2006:2007:2008]:65535", + {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}}, + 65535); + shouldParseEPV6( + "2001:2002:2003:2004:2005:2006:2007:2008 65535", + {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}}, + 65535, + "[2001:2002:2003:2004:2005:2006:2007:2008]:65535"); Endpoint ep; - ep = Endpoint (AddressV4 (127,0,0,1), 80); + AddressV4::bytes_type d = {{127,0,0,1}}; + ep = Endpoint (AddressV4 {d}, 80); BEAST_EXPECT(! is_unspecified (ep)); BEAST_EXPECT(! is_public (ep)); BEAST_EXPECT( is_private (ep)); BEAST_EXPECT(! is_multicast (ep)); BEAST_EXPECT( is_loopback (ep)); BEAST_EXPECT(to_string (ep) == "127.0.0.1:80"); + // same address as v4 mapped in ipv6 + ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d}), 80); + BEAST_EXPECT(! is_unspecified (ep)); + BEAST_EXPECT(! is_public (ep)); + BEAST_EXPECT( is_private (ep)); + BEAST_EXPECT(! is_multicast (ep)); + BEAST_EXPECT(! is_loopback (ep)); //mapped loopback is not a loopback + BEAST_EXPECTS(to_string (ep) == "[::ffff:127.0.0.1]:80", to_string (ep)); - ep = Endpoint (AddressV4 (10,0,0,1)); - BEAST_EXPECT(AddressV4::get_class (ep.to_v4()) == 'A'); + d = {{10,0,0,1}}; + ep = Endpoint (AddressV4 {d}); + BEAST_EXPECT(get_class (ep.to_v4()) == 'A'); BEAST_EXPECT(! is_unspecified (ep)); BEAST_EXPECT(! is_public (ep)); BEAST_EXPECT( is_private (ep)); BEAST_EXPECT(! is_multicast (ep)); BEAST_EXPECT(! is_loopback (ep)); BEAST_EXPECT(to_string (ep) == "10.0.0.1"); + // same address as v4 mapped in ipv6 + ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d})); + BEAST_EXPECT(get_class (ep.to_v6().to_v4()) == 'A'); + BEAST_EXPECT(! is_unspecified (ep)); + BEAST_EXPECT(! is_public (ep)); + BEAST_EXPECT( is_private (ep)); + BEAST_EXPECT(! is_multicast (ep)); + BEAST_EXPECT(! is_loopback (ep)); + BEAST_EXPECTS(to_string (ep) == "::ffff:10.0.0.1", to_string(ep)); - ep = Endpoint (AddressV4 (166,78,151,147)); + d = {{166,78,151,147}}; + ep = Endpoint (AddressV4 {d}); BEAST_EXPECT(! is_unspecified (ep)); BEAST_EXPECT( is_public (ep)); BEAST_EXPECT(! is_private (ep)); BEAST_EXPECT(! is_multicast (ep)); BEAST_EXPECT(! is_loopback (ep)); BEAST_EXPECT(to_string (ep) == "166.78.151.147"); + // same address as v4 mapped in ipv6 + ep = Endpoint (AddressV6::v4_mapped(AddressV4 {d})); + BEAST_EXPECT(! is_unspecified (ep)); + BEAST_EXPECT( is_public (ep)); + BEAST_EXPECT(! is_private (ep)); + BEAST_EXPECT(! is_multicast (ep)); + BEAST_EXPECT(! is_loopback (ep)); + BEAST_EXPECTS(to_string (ep) == "::ffff:166.78.151.147", to_string(ep)); + + // a private IPv6 + AddressV6::bytes_type d2 = {{253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}; + ep = Endpoint (AddressV6 {d2}); + BEAST_EXPECT(! is_unspecified (ep)); + BEAST_EXPECT(! is_public (ep)); + BEAST_EXPECT( is_private (ep)); + BEAST_EXPECT(! is_multicast (ep)); + BEAST_EXPECT(! is_loopback (ep)); + BEAST_EXPECTS(to_string (ep) == "fd00::1", to_string(ep)); { ep = Endpoint::from_string ("192.0.2.112"); BEAST_EXPECT(! is_unspecified (ep)); - BEAST_EXPECT(ep == Endpoint::from_string_altform ("192.0.2.112")); + BEAST_EXPECT(ep == Endpoint::from_string ("192.0.2.112")); auto const ep1 = Endpoint::from_string ("192.0.2.112:2016"); BEAST_EXPECT(! is_unspecified (ep1)); @@ -207,21 +313,21 @@ public: BEAST_EXPECT(ep1.port() == 2016); auto const ep2 = - Endpoint::from_string_altform ("192.0.2.112:2016"); + Endpoint::from_string ("192.0.2.112:2016"); BEAST_EXPECT(! is_unspecified (ep2)); BEAST_EXPECT(ep.address() == ep2.address()); BEAST_EXPECT(ep2.port() == 2016); BEAST_EXPECT(ep1 == ep2); auto const ep3 = - Endpoint::from_string_altform ("192.0.2.112 2016"); + Endpoint::from_string ("192.0.2.112 2016"); BEAST_EXPECT(! is_unspecified (ep3)); BEAST_EXPECT(ep.address() == ep3.address()); BEAST_EXPECT(ep3.port() == 2016); BEAST_EXPECT(ep2 == ep3); auto const ep4 = - Endpoint::from_string_altform ("192.0.2.112 2016"); + Endpoint::from_string ("192.0.2.112 2016"); BEAST_EXPECT(! is_unspecified (ep4)); BEAST_EXPECT(ep.address() == ep4.address()); BEAST_EXPECT(ep4.port() == 2016); @@ -232,87 +338,79 @@ public: BEAST_EXPECT(to_string(ep1) == to_string(ep4)); } + { + ep = Endpoint::from_string("[::]:2017"); + BEAST_EXPECT(is_unspecified (ep)); + BEAST_EXPECT(ep.port() == 2017); + BEAST_EXPECT(ep.address() == AddressV6{}); + } + // Failures: - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string ("192.0.2.112:port"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform ("192.0.2.112:port"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform ("192.0.2.112 port"))); + failParseEP ("192.0.2.112:port"); + failParseEP ("ip:port"); + failParseEP (""); + failParseEP ("1.2.3.256"); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string ("ip:port"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform ("ip:port"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform ("ip port"))); +#if BOOST_OS_WINDOWS + // windows asio bugs...false positives + shouldParseEPV4 ("255", {{0,0,0,255}}, 0, "0.0.0.255"); + shouldParseEPV4 ("512", {{0,0,2,0}}, 0, "0.0.2.0"); + shouldParseEPV4 ("1.2.3:80", {{1,2,0,3}}, 80, "1.2.0.3:80"); +#else + failParseEP ("255"); + failParseEP ("512"); + failParseEP ("1.2.3:80"); +#endif - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string(""))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform(""))); + failParseEP ("1.2.3.4:65536"); + failParseEP ("1.2.3.4:89119"); + failParseEP ("1.2.3:89119"); + failParseEP ("[::1]:89119"); + failParseEP ("[::az]:1"); + failParseEP ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1"); + failParseEP ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345"); + failParseEP ("abcdef:12345"); + failParseEP ("[abcdef]:12345"); + failParseEP ("foo.org 12345"); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("255"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("255"))); - - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("512"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("512"))); - - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("1.2.3.256"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3.256"))); - - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("1.2.3:80"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3:80"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3 80"))); - - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("1.2.3.4:65536"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3:65536"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3 65536"))); - - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string("1.2.3.4:89119"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3:89119"))); - BEAST_EXPECT(is_unspecified ( - Endpoint::from_string_altform("1.2.3 89119"))); + // test with hashed container + std::unordered_set eps; + constexpr auto items {100}; + float max_lf {0}; + for (auto i = 0; i < items; ++i) + { + eps.insert(randomEP(ripple::rand_int(0,1) == 1)); + max_lf = std::max(max_lf, eps.load_factor()); + } + BEAST_EXPECT(eps.bucket_count() >= items); + BEAST_EXPECT(max_lf > 0.90); } //-------------------------------------------------------------------------- template - bool parse (char const* text, T& t) + bool parse (std::string const& text, T& t) { - std::string input (text); - std::istringstream stream (input); + std::istringstream stream {text}; stream >> t; return !stream.fail(); } template - void shouldPass (char const* text) + void shouldPass (std::string const& text, std::string const& normal="") { + using namespace std::literals; T t; BEAST_EXPECT(parse (text, t)); - BEAST_EXPECT(to_string (t) == std::string (text)); + BEAST_EXPECTS(to_string (t) == (normal.empty() ? text : normal), + "string mismatch for "s + text); } template - void shouldFail (char const* text) + void shouldFail (std::string const& text) { T t; - unexpected (parse (text, t)); + unexpected (parse (text, t), text + " should not parse"); } template @@ -325,14 +423,30 @@ public: shouldPass ("168.127.149.132"); shouldPass ("168.127.149.132:80"); shouldPass ("168.127.149.132:54321"); + shouldPass ("2001:db8:a0b:12f0::1"); + shouldPass ("[2001:db8:a0b:12f0::1]:8"); + shouldPass ("2001:db8:a0b:12f0::1 8", "[2001:db8:a0b:12f0::1]:8"); + shouldPass ("[::1]:8"); + shouldPass ("[2001:2002:2003:2004:2005:2006:2007:2008]:65535"); - shouldFail (""); - shouldFail ("255"); - shouldFail ("512"); shouldFail ("1.2.3.256"); + shouldFail (""); +#if BOOST_OS_WINDOWS + // windows asio bugs...false positives + shouldPass ("512", "0.0.2.0"); + shouldPass ("255", "0.0.0.255"); + shouldPass ("1.2.3:80", "1.2.0.3:80"); +#else + shouldFail ("512"); + shouldFail ("255"); shouldFail ("1.2.3:80"); +#endif shouldFail ("1.2.3:65536"); shouldFail ("1.2.3:72131"); + shouldFail ("[::1]:89119"); + shouldFail ("[::az]:1"); + shouldFail ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1"); + shouldFail ("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345"); } void run () override @@ -341,7 +455,6 @@ public: testAddressV4Proxy(); testAddress (); testEndpoint (); - testParse ("Parse Endpoint"); } }; diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index 3288127f7..ccc0ac1ba 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ public: }; TrustedPublisherServer( - endpoint_type const& ep, boost::asio::io_service& ios, std::pair keys, std::string const& manifest, @@ -65,6 +65,9 @@ public: std::vector const& validators) : sock_(ios), acceptor_(ios) { + endpoint_type const& ep { + beast::IP::Address::from_string (ripple::test::getEnvLocalhostAddr()), + 0}; // 0 means let OS pick the port based on what's available std::string data = "{\"sequence\":" + std::to_string(sequence) + ",\"expiration\":" + std::to_string(expiration.time_since_epoch().count()) + diff --git a/src/test/jtx/envconfig.h b/src/test/jtx/envconfig.h index dd9d5be2b..d265678a8 100644 --- a/src/test/jtx/envconfig.h +++ b/src/test/jtx/envconfig.h @@ -25,6 +25,15 @@ namespace ripple { namespace test { +extern std::atomic envUseIPv4; + +inline +const char * +getEnvLocalhostAddr() +{ + return envUseIPv4 ? "127.0.0.1" : "::1"; +} + /// @brief initializes a config object for use with jtx::Env /// /// @param config the configuration object to be initialized diff --git a/src/test/jtx/impl/JSONRPCClient.cpp b/src/test/jtx/impl/JSONRPCClient.cpp index f32d5cf04..2b142363f 100644 --- a/src/test/jtx/impl/JSONRPCClient.cpp +++ b/src/test/jtx/impl/JSONRPCClient.cpp @@ -49,9 +49,9 @@ class JSONRPCClient : public AbstractClient parse_Port(pp, cfg[name], log); if(pp.protocol.count("http") == 0) continue; - using boost::asio::ip::address_v4; - if(*pp.ip == address_v4{0x00000000}) - *pp.ip = address_v4{0x7f000001}; + using namespace boost::asio::ip; + if(pp.ip && pp.ip->is_unspecified()) + *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; return { *pp.ip, *pp.port }; } Throw("Missing HTTP port"); @@ -83,7 +83,7 @@ public: : ep_(getEndpoint(cfg)) , stream_(ios_) , rpc_version_(rpc_version) - { + { stream_.connect(ep_); } diff --git a/src/test/jtx/impl/WSClient.cpp b/src/test/jtx/impl/WSClient.cpp index f239b9c36..71dd46fd7 100644 --- a/src/test/jtx/impl/WSClient.cpp +++ b/src/test/jtx/impl/WSClient.cpp @@ -64,9 +64,9 @@ class WSClientImpl : public WSClient parse_Port(pp, cfg[name], log); if(pp.protocol.count(ps) == 0) continue; - using boost::asio::ip::address_v4; - if(*pp.ip == address_v4{0x00000000}) - *pp.ip = address_v4{0x7f000001}; + using namespace boost::asio::ip; + if(pp.ip && pp.ip->is_unspecified()) + *pp.ip = pp.ip->is_v6() ? address{address_v6::loopback()} : address{address_v4::loopback()}; return { *pp.ip, *pp.port }; } Throw("Missing WebSocket port"); diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index 3868725ef..4de1066da 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -30,6 +30,8 @@ void incPorts() port_base += 3; } +std::atomic envUseIPv4 {false}; + void setupConfigForUnitTests (Config& cfg) { @@ -43,19 +45,21 @@ setupConfigForUnitTests (Config& cfg) cfg.legacy("database_path", ""); cfg.setupControl(true, true, true); cfg["server"].append("port_peer"); - cfg["port_peer"].set("ip", "127.0.0.1"); + cfg["port_peer"].set("ip", getEnvLocalhostAddr()); cfg["port_peer"].set("port", port_peer); cfg["port_peer"].set("protocol", "peer"); + cfg["server"].append("port_rpc"); - cfg["port_rpc"].set("ip", "127.0.0.1"); + cfg["port_rpc"].set("ip", getEnvLocalhostAddr()); + cfg["port_rpc"].set("admin", getEnvLocalhostAddr()); cfg["port_rpc"].set("port", port_rpc); cfg["port_rpc"].set("protocol", "http,ws2"); - cfg["port_rpc"].set("admin", "127.0.0.1"); + cfg["server"].append("port_ws"); - cfg["port_ws"].set("ip", "127.0.0.1"); + cfg["port_ws"].set("ip", getEnvLocalhostAddr()); + cfg["port_ws"].set("admin", getEnvLocalhostAddr()); cfg["port_ws"].set("port", port_ws); cfg["port_ws"].set("protocol", "ws"); - cfg["port_ws"].set("admin", "127.0.0.1"); } namespace jtx { diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index 688a7e65a..ce5f13339 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -183,7 +184,8 @@ private: , server_(server) , test_(server_.test_) , acceptor_(test_.io_service_, - endpoint_type(address_type::from_string("127.0.0.1"), 0)) + endpoint_type(beast::IP::Address::from_string( + test::getEnvLocalhostAddr()), 0)) , socket_(test_.io_service_) , strand_(socket_.get_io_service()) { diff --git a/src/test/peerfinder/Livecache_test.cpp b/src/test/peerfinder/Livecache_test.cpp index 70124cd37..b67f5bfc8 100644 --- a/src/test/peerfinder/Livecache_test.cpp +++ b/src/test/peerfinder/Livecache_test.cpp @@ -21,10 +21,18 @@ #include #include #include +#include +#include namespace ripple { namespace PeerFinder { +bool operator== (Endpoint const& a, Endpoint const& b) +{ + return (a.hops == b.hops && + a.address == b.address); +} + class Livecache_test : public beast::unit_test::suite { public: @@ -32,38 +40,178 @@ public: // Add the address as an endpoint template - void add (std::uint32_t index, std::uint16_t port, C& c) + inline void add (beast::IP::Endpoint ep, C& c, int hops = 0) { - Endpoint ep; - ep.hops = 0; - ep.address = beast::IP::Endpoint ( - beast::IP::AddressV4 (index), port); - c.insert (ep); + Endpoint cep {ep, hops}; + c.insert (cep); } - void testFetch () + void testBasicInsert () { + testcase ("Basic Insert"); + Livecache <> c (m_clock, beast::Journal()); + BEAST_EXPECT(c.empty()); + + for (auto i = 0; i < 10; ++i) + add(beast::IP::randomEP(true), c); + + BEAST_EXPECT(! c.empty()); + BEAST_EXPECT(c.size() == 10); + + for (auto i = 0; i < 10; ++i) + add(beast::IP::randomEP(false), c); + + BEAST_EXPECT(! c.empty()); + BEAST_EXPECT(c.size() == 20); + } + + void testInsertUpdate () + { + testcase ("Insert/Update"); Livecache <> c (m_clock, beast::Journal()); - add (1, 1, c); - add (2, 1, c); - add (3, 1, c); - add (4, 1, c); - add (4, 2, c); - add (4, 3, c); - add (5, 1, c); - add (6, 1, c); - add (6, 2, c); - add (7, 1, c); + auto ep1 = Endpoint {beast::IP::randomEP(), 2}; + c.insert(ep1); + BEAST_EXPECT(c.size() == 1); + // third position list will contain the entry + BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2); - // VFALCO TODO! + auto ep2 = Endpoint {ep1.address, 4}; + // this will not change the entry has higher hops + c.insert(ep2); + BEAST_EXPECT(c.size() == 1); + // still in third position list + BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2); - pass(); + auto ep3 = Endpoint {ep1.address, 2}; + // this will not change the entry has the same hops as existing + c.insert(ep3); + BEAST_EXPECT(c.size() == 1); + // still in third position list + BEAST_EXPECT((c.hops.begin()+2)->begin()->hops == 2); + + auto ep4 = Endpoint {ep1.address, 1}; + c.insert(ep4); + BEAST_EXPECT(c.size() == 1); + // now at second position list + BEAST_EXPECT((c.hops.begin()+1)->begin()->hops == 1); + } + + void testExpire () + { + testcase ("Expire"); + using namespace std::chrono_literals; + Livecache <> c (m_clock, beast::Journal()); + + auto ep1 = Endpoint {beast::IP::randomEP(), 1}; + c.insert(ep1); + BEAST_EXPECT(c.size() == 1); + c.expire(); + BEAST_EXPECT(c.size() == 1); + // verify that advancing to 1 sec before expiration + // leaves our entry intact + m_clock.advance(Tuning::liveCacheSecondsToLive - 1s); + c.expire(); + BEAST_EXPECT(c.size() == 1); + // now advance to the point of expiration + m_clock.advance(1s); + c.expire(); + BEAST_EXPECT(c.empty()); + } + + void testHistogram () + { + testcase ("Histogram"); + constexpr auto num_eps = 40; + Livecache <> c (m_clock, beast::Journal()); + for (auto i = 0; i < num_eps; ++i) + add( + beast::IP::randomEP(true), + c, + ripple::rand_int(0, static_cast(Tuning::maxHops + 1))); + auto h = c.hops.histogram(); + if(! BEAST_EXPECT(! h.empty())) + return; + std::vector v; + boost::split (v, h, boost::algorithm::is_any_of (",")); + auto sum = 0; + for (auto const& n : v) + { + auto val = boost::lexical_cast(boost::trim_copy(n)); + sum += val; + BEAST_EXPECT(val >= 0); + } + BEAST_EXPECT(sum == num_eps); + } + + + void testShuffle () + { + testcase ("Shuffle"); + Livecache <> c (m_clock, beast::Journal()); + for (auto i = 0; i < 100; ++i) + add( + beast::IP::randomEP(true), + c, + ripple::rand_int(0, static_cast(Tuning::maxHops + 1))); + + using at_hop = std::vector ; + using all_hops = std::array ; + + auto cmp_EP = [](Endpoint const& a, Endpoint const& b) { + return (b.hops < a.hops || (b.hops == a.hops && b.address < a.address)); + }; + all_hops before; + all_hops before_sorted; + for (auto i = std::make_pair(0, c.hops.begin()); + i.second != c.hops.end(); ++i.first, ++i.second) + { + std::copy ((*i.second).begin(), (*i.second).end(), + std::back_inserter (before[i.first])); + std::copy ((*i.second).begin(), (*i.second).end(), + std::back_inserter (before_sorted[i.first])); + std::sort( + before_sorted[i.first].begin(), + before_sorted[i.first].end(), + cmp_EP); + } + + c.hops.shuffle(); + + all_hops after; + all_hops after_sorted; + for (auto i = std::make_pair(0, c.hops.begin()); + i.second != c.hops.end(); ++i.first, ++i.second) + { + std::copy ((*i.second).begin(), (*i.second).end(), + std::back_inserter (after[i.first])); + std::copy ((*i.second).begin(), (*i.second).end(), + std::back_inserter (after_sorted[i.first])); + std::sort( + after_sorted[i.first].begin(), + after_sorted[i.first].end(), + cmp_EP); + } + + // each hop bucket should contain the same items + // before and after sort, albeit in different order + bool all_match = true; + for (auto i = 0; i < before.size(); ++i) + { + BEAST_EXPECT(before[i].size() == after[i].size()); + all_match = all_match && (before[i] == after[i]); + BEAST_EXPECT(before_sorted[i] == after_sorted[i]); + } + BEAST_EXPECT(! all_match); } void run () override { - testFetch (); + testBasicInsert (); + testInsertUpdate (); + testExpire (); + testHistogram (); + testShuffle (); } }; diff --git a/src/test/resource/Logic_test.cpp b/src/test/resource/Logic_test.cpp index 6d6b4ccaa..d730c8d1c 100644 --- a/src/test/resource/Logic_test.cpp +++ b/src/test/resource/Logic_test.cpp @@ -63,15 +63,16 @@ public: void createGossip (Gossip& gossip) { - int const v (10 + rand_int(9)); - int const n (10 + rand_int(9)); + std::uint8_t const v (10 + rand_int(9)); + std::uint8_t const n (10 + rand_int(9)); gossip.items.reserve (n); - for (int i = 0; i < n; ++i) + for (std::uint8_t i = 0; i < n; ++i) { Gossip::Item item; item.balance = 100 + rand_int(499); - item.address = beast::IP::Endpoint ( - beast::IP::AddressV4 (192, 0, 2, v + i)); + beast::IP::AddressV4::bytes_type d = + {{192,0,2,static_cast(v + i)}}; + item.address = beast::IP::Endpoint { beast::IP::AddressV4 {d} }; gossip.items.push_back (item); } } @@ -193,8 +194,8 @@ public: Gossip g; Gossip::Item item; item.balance = 100; - item.address = beast::IP::Endpoint ( - beast::IP::AddressV4 (192, 0, 2, 1)); + beast::IP::AddressV4::bytes_type d = {{192, 0, 2, 1}}; + item.address = beast::IP::Endpoint { beast::IP::AddressV4 {d} }; g.items.push_back (item); logic.importConsumers ("g", g); diff --git a/src/test/rpc/NoRippleCheck_test.cpp b/src/test/rpc/NoRippleCheck_test.cpp index 5c367c6e8..a630a4bf1 100644 --- a/src/test/rpc/NoRippleCheck_test.cpp +++ b/src/test/rpc/NoRippleCheck_test.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +266,7 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite using namespace std::chrono; using namespace beast::IP; auto c = env.app().getResourceManager() - .newInboundEndpoint (Endpoint::from_string ("127.0.0.1")); + .newInboundEndpoint (Endpoint::from_string (test::getEnvLocalhostAddr())); if (dropThreshold - c.balance() <= 20) { using clock_type = beast::abstract_clock ; diff --git a/src/test/rpc/ValidatorRPC_test.cpp b/src/test/rpc/ValidatorRPC_test.cpp index 4966bd8f0..d6ca23b2d 100644 --- a/src/test/rpc/ValidatorRPC_test.cpp +++ b/src/test/rpc/ValidatorRPC_test.cpp @@ -178,8 +178,6 @@ public: testDynamicUNL() { using namespace test::jtx; - using endpoint_type = boost::asio::ip::tcp::endpoint; - using address_type = boost::asio::ip::address; auto toStr = [](PublicKey const& publicKey) { return toBase58(TokenType::NodePublic, publicKey); @@ -208,7 +206,9 @@ public: // Publisher list site unavailable { // Publisher site information - std::string siteURI = "http://127.0.0.1:1234/validators"; + using namespace std::string_literals; + std::string siteURI = + "http://"s + getEnvLocalhostAddr() + ":1234/validators"; Env env{ *this, @@ -271,9 +271,6 @@ public: { NetClock::time_point const expiration{3600s}; - // 0 port means to use OS port selection - endpoint_type ep{address_type::from_string("127.0.0.1"), 0}; - // Manage single thread io_service for server struct Worker : BasicApp { @@ -282,7 +279,6 @@ public: Worker w; TrustedPublisherServer server( - ep, w.get_io_service(), publisherSigningKeys, manifest, @@ -291,9 +287,9 @@ public: 1, validators); - endpoint_type const & local_ep = server.local_endpoint(); - std::string siteURI = "http://127.0.0.1:" + - std::to_string(local_ep.port()) + "/validators"; + std::stringstream uri; + uri << "http://" << server.local_endpoint() << "/validators"; + auto siteURI = uri.str(); Env env{ *this, diff --git a/src/test/server/ServerStatus_test.cpp b/src/test/server/ServerStatus_test.cpp index 33be5b655..8bc81f13b 100644 --- a/src/test/server/ServerStatus_test.cpp +++ b/src/test/server/ServerStatus_test.cpp @@ -73,10 +73,10 @@ class ServerStatus_test : // which requires an http endpoint to talk to. In the connection // failure test, this endpoint should never be used (*p)["server"].append("port_alt"); - (*p)["port_alt"].set("ip", "127.0.0.1"); + (*p)["port_alt"].set("ip", getEnvLocalhostAddr()); (*p)["port_alt"].set("port", "8099"); (*p)["port_alt"].set("protocol", "http"); - (*p)["port_alt"].set("admin", "127.0.0.1"); + (*p)["port_alt"].set("admin", getEnvLocalhostAddr()); } return p; diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index c2857c200..5856c9205 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -283,7 +283,7 @@ public: thread.get_io_service(), journal); std::vector serverPort(1); serverPort.back().ip = - boost::asio::ip::address::from_string ("127.0.0.1"), + beast::IP::Address::from_string (getEnvLocalhostAddr()), serverPort.back().port = 0; serverPort.back().protocol.insert("http"); auto eps = s->ports (serverPort); @@ -355,7 +355,7 @@ public: thread.get_io_service(), {}); std::vector serverPort(1); serverPort.back().ip = - boost::asio::ip::address::from_string ("127.0.0.1"), + beast::IP::Address::from_string (getEnvLocalhostAddr()), serverPort.back().port = 0; serverPort.back().protocol.insert("http"); s->ports (serverPort); @@ -441,7 +441,7 @@ public: Env env {*this, envconfig([](std::unique_ptr cfg) { (*cfg).deprecatedClearSection("port_rpc"); - (*cfg)["port_rpc"].set("ip", "127.0.0.1"); + (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); return cfg; }), std::make_unique(messages)}; @@ -455,7 +455,7 @@ public: Env env {*this, envconfig([](std::unique_ptr cfg) { (*cfg).deprecatedClearSection("port_rpc"); - (*cfg)["port_rpc"].set("ip", "127.0.0.1"); + (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); (*cfg)["port_rpc"].set("port", "0"); return cfg; }), @@ -470,7 +470,7 @@ public: Env env {*this, envconfig([](std::unique_ptr cfg) { (*cfg).deprecatedClearSection("port_rpc"); - (*cfg)["port_rpc"].set("ip", "127.0.0.1"); + (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); (*cfg)["port_rpc"].set("port", "8081"); (*cfg)["port_rpc"].set("protocol", ""); return cfg; @@ -495,17 +495,17 @@ public: ConfigSection::importNodeDatabase ()); cfg->legacy("database_path", ""); cfg->setupControl(true, true, true); - (*cfg)["port_peer"].set("ip", "127.0.0.1"); + (*cfg)["port_peer"].set("ip", getEnvLocalhostAddr()); (*cfg)["port_peer"].set("port", "8080"); (*cfg)["port_peer"].set("protocol", "peer"); - (*cfg)["port_rpc"].set("ip", "127.0.0.1"); + (*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr()); (*cfg)["port_rpc"].set("port", "8081"); (*cfg)["port_rpc"].set("protocol", "http,ws2"); - (*cfg)["port_rpc"].set("admin", "127.0.0.1"); - (*cfg)["port_ws"].set("ip", "127.0.0.1"); + (*cfg)["port_rpc"].set("admin", getEnvLocalhostAddr()); + (*cfg)["port_ws"].set("ip", getEnvLocalhostAddr()); (*cfg)["port_ws"].set("port", "8082"); (*cfg)["port_ws"].set("protocol", "ws"); - (*cfg)["port_ws"].set("admin", "127.0.0.1"); + (*cfg)["port_ws"].set("admin", getEnvLocalhostAddr()); return cfg; }), std::make_unique(messages)};