2020-04-16 13:14:08 -04:00
|
|
|
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
2016-03-16 12:54:30 -04:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2019-06-24 17:22:28 +02:00
|
|
|
|
|
|
|
#include <addrdb.h>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <addrman.h>
|
2020-04-16 13:11:54 -04:00
|
|
|
#include <chainparams.h>
|
|
|
|
#include <clientversion.h>
|
2019-12-29 13:04:02 -08:00
|
|
|
#include <cstdint>
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <net.h>
|
|
|
|
#include <netbase.h>
|
2020-11-06 11:40:09 +00:00
|
|
|
#include <optional.h>
|
2020-04-16 13:11:54 -04:00
|
|
|
#include <serialize.h>
|
2020-05-19 15:01:50 +02:00
|
|
|
#include <span.h>
|
2020-04-16 13:11:54 -04:00
|
|
|
#include <streams.h>
|
|
|
|
#include <test/util/setup_common.h>
|
2019-06-24 17:22:28 +02:00
|
|
|
#include <util/memory.h>
|
2020-08-24 21:34:26 +02:00
|
|
|
#include <util/strencodings.h>
|
2020-02-12 23:01:45 -05:00
|
|
|
#include <util/string.h>
|
2020-04-16 13:11:54 -04:00
|
|
|
#include <util/system.h>
|
2020-08-24 21:34:26 +02:00
|
|
|
#include <version.h>
|
2016-03-16 12:54:30 -04:00
|
|
|
|
2020-04-17 06:41:14 -04:00
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
2020-11-06 11:40:09 +00:00
|
|
|
#include <algorithm>
|
2020-05-19 15:01:50 +02:00
|
|
|
#include <ios>
|
2018-04-02 18:31:40 +00:00
|
|
|
#include <memory>
|
2020-04-17 06:41:14 -04:00
|
|
|
#include <string>
|
2018-04-02 18:31:40 +00:00
|
|
|
|
2020-09-23 08:40:38 +02:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2016-03-16 12:54:30 -04:00
|
|
|
class CAddrManSerializationMock : public CAddrMan
|
|
|
|
{
|
|
|
|
public:
|
2016-10-28 16:29:17 -07:00
|
|
|
virtual void Serialize(CDataStream& s) const = 0;
|
2016-05-18 12:04:07 -04:00
|
|
|
|
|
|
|
//! Ensure that bucket placement is always the same for testing purposes.
|
|
|
|
void MakeDeterministic()
|
|
|
|
{
|
|
|
|
nKey.SetNull();
|
2016-10-13 16:19:20 +02:00
|
|
|
insecure_rand = FastRandomContext(true);
|
2016-05-18 12:04:07 -04:00
|
|
|
}
|
2016-03-16 12:54:30 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class CAddrManUncorrupted : public CAddrManSerializationMock
|
|
|
|
{
|
|
|
|
public:
|
2017-06-20 21:58:56 +02:00
|
|
|
void Serialize(CDataStream& s) const override
|
2016-03-16 12:54:30 -04:00
|
|
|
{
|
2016-10-28 16:29:17 -07:00
|
|
|
CAddrMan::Serialize(s);
|
2016-03-16 12:54:30 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CAddrManCorrupted : public CAddrManSerializationMock
|
|
|
|
{
|
|
|
|
public:
|
2017-06-20 21:58:56 +02:00
|
|
|
void Serialize(CDataStream& s) const override
|
2016-03-16 12:54:30 -04:00
|
|
|
{
|
|
|
|
// Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
|
|
|
|
unsigned char nVersion = 1;
|
|
|
|
s << nVersion;
|
|
|
|
s << ((unsigned char)32);
|
|
|
|
s << nKey;
|
|
|
|
s << 10; // nNew
|
|
|
|
s << 10; // nTried
|
|
|
|
|
|
|
|
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
|
|
|
|
s << nUBuckets;
|
|
|
|
|
2016-05-31 13:51:11 -04:00
|
|
|
CService serv;
|
2018-12-12 14:31:38 +01:00
|
|
|
BOOST_CHECK(Lookup("252.1.1.1", serv, 7777, false));
|
2016-05-31 13:51:11 -04:00
|
|
|
CAddress addr = CAddress(serv, NODE_NONE);
|
2016-05-31 13:05:52 -04:00
|
|
|
CNetAddr resolved;
|
2018-12-12 14:31:38 +01:00
|
|
|
BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
|
2016-05-31 13:05:52 -04:00
|
|
|
CAddrInfo info = CAddrInfo(addr, resolved);
|
2016-03-16 12:54:30 -04:00
|
|
|
s << info;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-12-06 00:14:17 +00:00
|
|
|
static CDataStream AddrmanToStream(const CAddrManSerializationMock& _addrman)
|
2016-03-16 12:54:30 -04:00
|
|
|
{
|
|
|
|
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
|
2018-03-20 17:37:32 -07:00
|
|
|
ssPeersIn << Params().MessageStart();
|
2016-09-02 18:19:01 +02:00
|
|
|
ssPeersIn << _addrman;
|
2016-03-16 12:54:30 -04:00
|
|
|
std::string str = ssPeersIn.str();
|
2016-12-05 16:03:53 +09:00
|
|
|
std::vector<unsigned char> vchData(str.begin(), str.end());
|
2016-03-16 12:54:30 -04:00
|
|
|
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
|
|
|
|
|
2017-04-25 07:26:43 -07:00
|
|
|
BOOST_AUTO_TEST_CASE(cnode_listen_port)
|
|
|
|
{
|
|
|
|
// test default
|
2019-12-29 13:04:02 -08:00
|
|
|
uint16_t port = GetListenPort();
|
2017-04-25 07:26:43 -07:00
|
|
|
BOOST_CHECK(port == Params().GetDefaultPort());
|
|
|
|
// test set port
|
2019-12-29 13:04:02 -08:00
|
|
|
uint16_t altPort = 12345;
|
2020-02-12 23:01:45 -05:00
|
|
|
BOOST_CHECK(gArgs.SoftSetArg("-port", ToString(altPort)));
|
2017-04-25 07:26:43 -07:00
|
|
|
port = GetListenPort();
|
|
|
|
BOOST_CHECK(port == altPort);
|
|
|
|
}
|
|
|
|
|
2016-03-16 12:54:30 -04:00
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read)
|
|
|
|
{
|
|
|
|
CAddrManUncorrupted addrmanUncorrupted;
|
2016-05-18 12:04:07 -04:00
|
|
|
addrmanUncorrupted.MakeDeterministic();
|
2016-03-16 12:54:30 -04:00
|
|
|
|
2016-05-31 13:51:11 -04:00
|
|
|
CService addr1, addr2, addr3;
|
2018-12-12 14:31:38 +01:00
|
|
|
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
|
|
|
|
BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
|
|
|
|
BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
|
2020-09-23 08:40:38 +02:00
|
|
|
BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false));
|
|
|
|
BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false));
|
2016-03-16 12:54:30 -04:00
|
|
|
|
|
|
|
// Add three addresses to new table.
|
2016-05-31 13:51:11 -04:00
|
|
|
CService source;
|
2018-12-12 14:31:38 +01:00
|
|
|
BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
|
|
|
|
BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source));
|
|
|
|
BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source));
|
|
|
|
BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source));
|
2016-03-16 12:54:30 -04:00
|
|
|
|
|
|
|
// Test that the de-serialization does not throw an exception.
|
|
|
|
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
|
|
|
|
bool exceptionThrown = false;
|
|
|
|
CAddrMan addrman1;
|
|
|
|
|
|
|
|
BOOST_CHECK(addrman1.size() == 0);
|
|
|
|
try {
|
|
|
|
unsigned char pchMsgTmp[4];
|
2018-03-20 17:37:32 -07:00
|
|
|
ssPeers1 >> pchMsgTmp;
|
2016-03-16 12:54:30 -04:00
|
|
|
ssPeers1 >> addrman1;
|
2018-08-28 21:42:07 +02:00
|
|
|
} catch (const std::exception&) {
|
2016-03-16 12:54:30 -04:00
|
|
|
exceptionThrown = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_CHECK(addrman1.size() == 3);
|
|
|
|
BOOST_CHECK(exceptionThrown == false);
|
|
|
|
|
|
|
|
// Test that CAddrDB::Read creates an addrman with the correct number of addrs.
|
|
|
|
CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
|
|
|
|
|
|
|
|
CAddrMan addrman2;
|
|
|
|
BOOST_CHECK(addrman2.size() == 0);
|
2019-11-01 19:28:15 +02:00
|
|
|
BOOST_CHECK(CAddrDB::Read(addrman2, ssPeers2));
|
2016-03-16 12:54:30 -04:00
|
|
|
BOOST_CHECK(addrman2.size() == 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
|
|
|
|
{
|
|
|
|
CAddrManCorrupted addrmanCorrupted;
|
2016-05-18 12:04:07 -04:00
|
|
|
addrmanCorrupted.MakeDeterministic();
|
2016-03-16 12:54:30 -04:00
|
|
|
|
|
|
|
// Test that the de-serialization of corrupted addrman throws an exception.
|
|
|
|
CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
|
|
|
|
bool exceptionThrown = false;
|
|
|
|
CAddrMan addrman1;
|
|
|
|
BOOST_CHECK(addrman1.size() == 0);
|
|
|
|
try {
|
|
|
|
unsigned char pchMsgTmp[4];
|
2018-03-20 17:37:32 -07:00
|
|
|
ssPeers1 >> pchMsgTmp;
|
2016-03-16 12:54:30 -04:00
|
|
|
ssPeers1 >> addrman1;
|
2018-08-28 21:42:07 +02:00
|
|
|
} catch (const std::exception&) {
|
2016-03-16 12:54:30 -04:00
|
|
|
exceptionThrown = true;
|
|
|
|
}
|
2016-05-18 20:14:26 -04:00
|
|
|
// Even through de-serialization failed addrman is not left in a clean state.
|
2016-03-16 12:54:30 -04:00
|
|
|
BOOST_CHECK(addrman1.size() == 1);
|
|
|
|
BOOST_CHECK(exceptionThrown);
|
|
|
|
|
|
|
|
// Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
|
|
|
|
CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
|
|
|
|
|
|
|
|
CAddrMan addrman2;
|
|
|
|
BOOST_CHECK(addrman2.size() == 0);
|
2019-11-01 19:28:15 +02:00
|
|
|
BOOST_CHECK(!CAddrDB::Read(addrman2, ssPeers2));
|
2016-03-16 12:54:30 -04:00
|
|
|
BOOST_CHECK(addrman2.size() == 0);
|
|
|
|
}
|
|
|
|
|
2016-06-17 00:10:07 -04:00
|
|
|
BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|
|
|
{
|
|
|
|
SOCKET hSocket = INVALID_SOCKET;
|
2016-04-17 20:20:34 -04:00
|
|
|
NodeId id = 0;
|
2016-05-24 16:42:17 -04:00
|
|
|
int height = 0;
|
2016-06-17 00:10:07 -04:00
|
|
|
|
|
|
|
in_addr ipv4Addr;
|
|
|
|
ipv4Addr.s_addr = 0xa0b0c001;
|
2018-07-24 16:59:49 +01:00
|
|
|
|
2016-06-17 00:10:07 -04:00
|
|
|
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
2018-01-14 18:15:31 +01:00
|
|
|
std::string pszDest;
|
2016-06-17 00:10:07 -04:00
|
|
|
|
2020-10-03 12:18:36 +03:00
|
|
|
std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(
|
|
|
|
id++, NODE_NETWORK, height, hSocket, addr,
|
|
|
|
/* nKeyedNetGroupIn = */ 0,
|
|
|
|
/* nLocalHostNonceIn = */ 0,
|
|
|
|
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
|
2020-08-11 10:37:57 -07:00
|
|
|
BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
|
|
|
|
BOOST_CHECK(pnode1->IsManualConn() == false);
|
|
|
|
BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
|
|
|
|
BOOST_CHECK(pnode1->IsFeelerConn() == false);
|
|
|
|
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
|
2020-07-28 13:39:38 -07:00
|
|
|
BOOST_CHECK(pnode1->IsInboundConn() == false);
|
2020-10-03 12:18:36 +03:00
|
|
|
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
|
|
|
|
std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(
|
|
|
|
id++, NODE_NETWORK, height, hSocket, addr,
|
|
|
|
/* nKeyedNetGroupIn = */ 1,
|
|
|
|
/* nLocalHostNonceIn = */ 1,
|
|
|
|
CAddress(), pszDest, ConnectionType::INBOUND,
|
|
|
|
/* inbound_onion = */ false);
|
2020-08-11 10:37:57 -07:00
|
|
|
BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
|
|
|
|
BOOST_CHECK(pnode2->IsManualConn() == false);
|
|
|
|
BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
|
|
|
|
BOOST_CHECK(pnode2->IsFeelerConn() == false);
|
|
|
|
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
|
2020-07-28 13:39:38 -07:00
|
|
|
BOOST_CHECK(pnode2->IsInboundConn() == true);
|
2020-10-03 12:18:36 +03:00
|
|
|
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
|
|
|
|
std::unique_ptr<CNode> pnode3 = MakeUnique<CNode>(
|
|
|
|
id++, NODE_NETWORK, height, hSocket, addr,
|
|
|
|
/* nKeyedNetGroupIn = */ 0,
|
|
|
|
/* nLocalHostNonceIn = */ 0,
|
|
|
|
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY,
|
2020-12-17 16:33:56 +01:00
|
|
|
/* inbound_onion = */ false);
|
2020-10-03 12:18:36 +03:00
|
|
|
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
|
|
|
|
BOOST_CHECK(pnode3->IsManualConn() == false);
|
|
|
|
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
|
|
|
|
BOOST_CHECK(pnode3->IsFeelerConn() == false);
|
|
|
|
BOOST_CHECK(pnode3->IsAddrFetchConn() == false);
|
|
|
|
BOOST_CHECK(pnode3->IsInboundConn() == false);
|
|
|
|
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
|
|
|
|
|
|
|
|
std::unique_ptr<CNode> pnode4 = MakeUnique<CNode>(
|
|
|
|
id++, NODE_NETWORK, height, hSocket, addr,
|
|
|
|
/* nKeyedNetGroupIn = */ 1,
|
|
|
|
/* nLocalHostNonceIn = */ 1,
|
|
|
|
CAddress(), pszDest, ConnectionType::INBOUND,
|
|
|
|
/* inbound_onion = */ true);
|
|
|
|
BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
|
|
|
|
BOOST_CHECK(pnode4->IsManualConn() == false);
|
|
|
|
BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
|
|
|
|
BOOST_CHECK(pnode4->IsFeelerConn() == false);
|
|
|
|
BOOST_CHECK(pnode4->IsAddrFetchConn() == false);
|
|
|
|
BOOST_CHECK(pnode4->IsInboundConn() == true);
|
|
|
|
BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION);
|
2016-06-17 00:10:07 -04:00
|
|
|
}
|
|
|
|
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
|
|
|
{
|
|
|
|
CNetAddr addr;
|
|
|
|
|
|
|
|
// IPv4, INADDR_ANY
|
|
|
|
BOOST_REQUIRE(LookupHost("0.0.0.0", addr, false));
|
|
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
|
|
|
|
BOOST_CHECK(addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
|
|
|
|
|
|
|
|
// IPv4, INADDR_NONE
|
|
|
|
BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
|
|
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
|
|
|
|
|
|
|
|
// IPv4, casual
|
|
|
|
BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
|
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv4());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
|
|
|
|
|
|
|
|
// IPv6, in6addr_any
|
|
|
|
BOOST_REQUIRE(LookupHost("::", addr, false));
|
|
|
|
BOOST_REQUIRE(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
|
|
|
|
BOOST_CHECK(addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "::");
|
|
|
|
|
|
|
|
// IPv6, casual
|
|
|
|
BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
|
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
|
|
|
|
|
2020-09-13 11:04:50 +02:00
|
|
|
// IPv6, scoped/link-local. See https://tools.ietf.org/html/rfc4007
|
|
|
|
// We support non-negative decimal integers (uint32_t) as zone id indices.
|
|
|
|
// Test with a fairly-high value, e.g. 32, to avoid locally reserved ids.
|
|
|
|
const std::string link_local{"fe80::1"};
|
|
|
|
const std::string scoped_addr{link_local + "%32"};
|
|
|
|
BOOST_REQUIRE(LookupHost(scoped_addr, addr, false));
|
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
|
|
const std::string addr_str{addr.ToString()};
|
|
|
|
BOOST_CHECK(addr_str == scoped_addr || addr_str == "fe80:0:0:0:0:0:0:1");
|
|
|
|
// The fallback case "fe80:0:0:0:0:0:0:1" is needed for macOS 10.14/10.15 and (probably) later.
|
|
|
|
// Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
|
|
|
|
BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false));
|
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsIPv6());
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), link_local);
|
|
|
|
|
2020-08-24 21:34:26 +02:00
|
|
|
// TORv2
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsTor());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
|
|
|
|
|
2020-08-27 11:03:21 +02:00
|
|
|
// TORv3
|
|
|
|
const char* torv3_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion";
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial(torv3_addr));
|
|
|
|
BOOST_REQUIRE(addr.IsValid());
|
|
|
|
BOOST_REQUIRE(addr.IsTor());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), torv3_addr);
|
|
|
|
|
|
|
|
// TORv3, broken, with wrong checksum
|
|
|
|
BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscsad.onion"));
|
|
|
|
|
|
|
|
// TORv3, broken, with wrong version
|
|
|
|
BOOST_CHECK(!addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscrye.onion"));
|
|
|
|
|
|
|
|
// TORv3, malicious
|
|
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{
|
|
|
|
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd\0wtf.onion", 66}));
|
|
|
|
|
|
|
|
// TOR, bogus length
|
|
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{"mfrggzak.onion"}));
|
|
|
|
|
|
|
|
// TOR, invalid base32
|
|
|
|
BOOST_CHECK(!addr.SetSpecial(std::string{"mf*g zak.onion"}));
|
|
|
|
|
2020-08-24 21:34:26 +02:00
|
|
|
// Internal
|
|
|
|
addr.SetInternal("esffpp");
|
|
|
|
BOOST_REQUIRE(!addr.IsValid()); // "internal" is considered invalid
|
|
|
|
BOOST_REQUIRE(addr.IsInternal());
|
|
|
|
|
|
|
|
BOOST_CHECK(!addr.IsBindAny());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-08-24 21:34:26 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
|
2020-08-27 11:03:21 +02:00
|
|
|
|
|
|
|
// Totally bogus
|
|
|
|
BOOST_CHECK(!addr.SetSpecial("totally bogus"));
|
2020-08-24 21:34:26 +02:00
|
|
|
}
|
|
|
|
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
|
2020-08-24 21:34:26 +02:00
|
|
|
{
|
|
|
|
CNetAddr addr;
|
|
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
|
2020-05-19 15:01:50 +02:00
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "fd87d87eeb43f1f2f3f4f5f6f7f8f9fa");
|
|
|
|
s.clear();
|
|
|
|
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
|
|
|
|
s.clear();
|
|
|
|
|
2020-08-24 21:34:26 +02:00
|
|
|
addr.SetInternal("a");
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
|
|
|
|
s.clear();
|
|
|
|
}
|
|
|
|
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
|
|
|
|
{
|
|
|
|
CNetAddr addr;
|
|
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
// Add ADDRV2_FORMAT to the version so that the CNetAddr
|
|
|
|
// serialize method produces an address in v2 format.
|
|
|
|
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
|
|
|
|
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "030af1f2f3f4f5f6f7f8f9fa");
|
|
|
|
s.clear();
|
|
|
|
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "042053cd5648488c4707914182655b7664034e09e66f7e8cbf1084e654eb56c5bd88");
|
|
|
|
s.clear();
|
|
|
|
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_REQUIRE(addr.SetInternal("a"));
|
|
|
|
s << addr;
|
|
|
|
BOOST_CHECK_EQUAL(HexStr(s), "0210fd6b88c08724ca978112ca1bbdcafac2");
|
|
|
|
s.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
|
|
|
{
|
|
|
|
CNetAddr addr;
|
|
|
|
CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
// Add ADDRV2_FORMAT to the version so that the CNetAddr
|
|
|
|
// unserialize method expects an address in v2 format.
|
|
|
|
s.SetVersion(s.GetVersion() | ADDRV2_FORMAT);
|
|
|
|
|
|
|
|
// Valid IPv4.
|
|
|
|
s << MakeSpan(ParseHex("01" // network type (IPv4)
|
|
|
|
"04" // address length
|
|
|
|
"01020304")); // address
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
|
|
|
BOOST_CHECK(addr.IsIPv4());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "1.2.3.4");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid IPv4, valid length but address itself is shorter.
|
|
|
|
s << MakeSpan(ParseHex("01" // network type (IPv4)
|
|
|
|
"04" // address length
|
|
|
|
"0102")); // address
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure, HasReason("end of data"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Invalid IPv4, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("01" // network type (IPv4)
|
|
|
|
"05" // address length
|
|
|
|
"01020304")); // address
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 IPv4 address with length 5 (should be 4)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Invalid IPv4, with extreme length.
|
|
|
|
s << MakeSpan(ParseHex("01" // network type (IPv4)
|
|
|
|
"fd0102" // address length (513 as CompactSize)
|
|
|
|
"01020304")); // address
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("Address too long: 513 > 512"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Valid IPv6.
|
|
|
|
s << MakeSpan(ParseHex("02" // network type (IPv6)
|
|
|
|
"10" // address length
|
|
|
|
"0102030405060708090a0b0c0d0e0f10")); // address
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
|
|
|
BOOST_CHECK(addr.IsIPv6());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "102:304:506:708:90a:b0c:d0e:f10");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Valid IPv6, contains embedded "internal".
|
|
|
|
s << MakeSpan(ParseHex(
|
|
|
|
"02" // network type (IPv6)
|
|
|
|
"10" // address length
|
|
|
|
"fd6b88c08724ca978112ca1bbdcafac2")); // address: 0xfd + sha256("bitcoin")[0:5] +
|
|
|
|
// sha256(name)[0:10]
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsInternal());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "zklycewkdo64v6wc.internal");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid IPv6, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("02" // network type (IPv6)
|
|
|
|
"04" // address length
|
|
|
|
"00")); // address
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 IPv6 address with length 4 (should be 16)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Invalid IPv6, contains embedded IPv4.
|
|
|
|
s << MakeSpan(ParseHex("02" // network type (IPv6)
|
|
|
|
"10" // address length
|
|
|
|
"00000000000000000000ffff01020304")); // address
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid IPv6, contains embedded TORv2.
|
|
|
|
s << MakeSpan(ParseHex("02" // network type (IPv6)
|
|
|
|
"10" // address length
|
|
|
|
"fd87d87eeb430102030405060708090a")); // address
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Valid TORv2.
|
|
|
|
s << MakeSpan(ParseHex("03" // network type (TORv2)
|
|
|
|
"0a" // address length
|
|
|
|
"f1f2f3f4f5f6f7f8f9fa")); // address
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
|
|
|
BOOST_CHECK(addr.IsTor());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsAddrV1Compatible());
|
2020-05-19 15:01:50 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid TORv2, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("03" // network type (TORv2)
|
|
|
|
"07" // address length
|
|
|
|
"00")); // address
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 TORv2 address with length 7 (should be 10)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
2020-08-27 11:03:21 +02:00
|
|
|
// Valid TORv3.
|
|
|
|
s << MakeSpan(ParseHex("04" // network type (TORv3)
|
|
|
|
"20" // address length
|
|
|
|
"79bcc625184b05194975c28b66b66b04" // address
|
|
|
|
"69f7f6556fb1ac3189a79b40dda32f1f"
|
|
|
|
));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
|
|
|
BOOST_CHECK(addr.IsTor());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(),
|
|
|
|
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid TORv3, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("04" // network type (TORv3)
|
|
|
|
"00" // address length
|
|
|
|
"00" // address
|
|
|
|
));
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 TORv3 address with length 0 (should be 32)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Valid I2P.
|
|
|
|
s << MakeSpan(ParseHex("05" // network type (I2P)
|
|
|
|
"20" // address length
|
|
|
|
"a2894dabaec08c0051a481a6dac88b64" // address
|
|
|
|
"f98232ae42d4b6fd2fa81952dfe36a87"));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsI2P());
|
|
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(),
|
|
|
|
"ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Invalid I2P, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("05" // network type (I2P)
|
|
|
|
"03" // address length
|
|
|
|
"00" // address
|
|
|
|
));
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 I2P address with length 3 (should be 32)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Valid CJDNS.
|
|
|
|
s << MakeSpan(ParseHex("06" // network type (CJDNS)
|
|
|
|
"10" // address length
|
|
|
|
"fc000001000200030004000500060007" // address
|
|
|
|
));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsValid());
|
2020-05-20 12:05:18 +02:00
|
|
|
BOOST_CHECK(addr.IsCJDNS());
|
|
|
|
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
2020-08-27 11:03:21 +02:00
|
|
|
BOOST_CHECK_EQUAL(addr.ToString(), "fc00:1:2:3:4:5:6:7");
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
2020-12-10 14:26:58 -03:00
|
|
|
// Invalid CJDNS, wrong prefix.
|
|
|
|
s << MakeSpan(ParseHex("06" // network type (CJDNS)
|
|
|
|
"10" // address length
|
|
|
|
"aa000001000200030004000500060007" // address
|
|
|
|
));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(addr.IsCJDNS());
|
|
|
|
BOOST_CHECK(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
2020-08-27 11:03:21 +02:00
|
|
|
// Invalid CJDNS, with bogus length.
|
|
|
|
s << MakeSpan(ParseHex("06" // network type (CJDNS)
|
|
|
|
"01" // address length
|
|
|
|
"00" // address
|
|
|
|
));
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("BIP155 CJDNS address with length 1 (should be 16)"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
2020-05-19 15:01:50 +02:00
|
|
|
// Unknown, with extreme length.
|
|
|
|
s << MakeSpan(ParseHex("aa" // network type (unknown)
|
|
|
|
"fe00000002" // address length (CompactSize's MAX_SIZE)
|
|
|
|
"01020304050607" // address
|
|
|
|
));
|
|
|
|
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
|
|
|
|
HasReason("Address too long: 33554432 > 512"));
|
|
|
|
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
|
|
|
|
s.clear();
|
|
|
|
|
|
|
|
// Unknown, with reasonable length.
|
|
|
|
s << MakeSpan(ParseHex("aa" // network type (unknown)
|
|
|
|
"04" // address length
|
|
|
|
"01020304" // address
|
|
|
|
));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
|
|
|
|
// Unknown, with zero length.
|
|
|
|
s << MakeSpan(ParseHex("aa" // network type (unknown)
|
|
|
|
"00" // address length
|
|
|
|
"" // address
|
|
|
|
));
|
|
|
|
s >> addr;
|
|
|
|
BOOST_CHECK(!addr.IsValid());
|
|
|
|
BOOST_REQUIRE(s.empty());
|
|
|
|
}
|
|
|
|
|
2018-11-15 12:34:46 -08:00
|
|
|
// prior to PR #14728, this test triggers an undefined behavior
|
|
|
|
BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
|
|
|
{
|
|
|
|
// set up local addresses; all that's necessary to reproduce the bug is
|
|
|
|
// that a normal IPv4 address is among the entries, but if this address is
|
|
|
|
// !IsRoutable the undefined behavior is easier to trigger deterministically
|
|
|
|
{
|
|
|
|
LOCK(cs_mapLocalHost);
|
|
|
|
in_addr ipv4AddrLocal;
|
|
|
|
ipv4AddrLocal.s_addr = 0x0100007f;
|
|
|
|
CNetAddr addr = CNetAddr(ipv4AddrLocal);
|
|
|
|
LocalServiceInfo lsi;
|
|
|
|
lsi.nScore = 23;
|
|
|
|
lsi.nPort = 42;
|
|
|
|
mapLocalHost[addr] = lsi;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a peer with an IPv4 address
|
|
|
|
in_addr ipv4AddrPeer;
|
|
|
|
ipv4AddrPeer.s_addr = 0xa0b0c001;
|
|
|
|
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
|
2020-08-11 20:37:32 -07:00
|
|
|
std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY);
|
2018-11-15 12:34:46 -08:00
|
|
|
pnode->fSuccessfullyConnected.store(true);
|
|
|
|
|
|
|
|
// the peer claims to be reaching us via IPv6
|
|
|
|
in6_addr ipv6AddrLocal;
|
|
|
|
memset(ipv6AddrLocal.s6_addr, 0, 16);
|
|
|
|
ipv6AddrLocal.s6_addr[0] = 0xcc;
|
|
|
|
CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
|
|
|
|
pnode->SetAddrLocal(addrLocal);
|
|
|
|
|
|
|
|
// before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
|
|
|
|
AdvertiseLocal(&*pnode);
|
|
|
|
|
|
|
|
// suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
|
|
|
|
BOOST_CHECK(1);
|
|
|
|
}
|
|
|
|
|
2018-12-28 16:20:30 +01:00
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
|
|
|
|
{
|
2019-01-09 16:41:37 -08:00
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
|
2018-12-28 16:20:30 +01:00
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, false);
|
|
|
|
SetReachable(NET_IPV6, false);
|
|
|
|
SetReachable(NET_ONION, false);
|
2018-12-28 16:20:30 +01:00
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false);
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, true);
|
|
|
|
SetReachable(NET_IPV6, true);
|
|
|
|
SetReachable(NET_ONION, true);
|
2018-12-28 16:20:30 +01:00
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
|
|
|
|
{
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_UNROUTABLE, false);
|
|
|
|
SetReachable(NET_INTERNAL, false);
|
2018-12-28 16:20:30 +01:00
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); // Ignored for both networks
|
2018-12-28 16:20:30 +01:00
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4)
|
|
|
|
{
|
|
|
|
unsigned char ip[] = {p1, p2, p3, p4};
|
|
|
|
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block
|
|
|
|
memcpy(&(sa.sin_addr), &ip, sizeof(ip));
|
|
|
|
return CNetAddr(sa.sin_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr)
|
|
|
|
{
|
|
|
|
CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, true);
|
2018-12-28 16:20:30 +01:00
|
|
|
BOOST_CHECK_EQUAL(IsReachable(addr), true);
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, false);
|
2018-12-28 16:20:30 +01:00
|
|
|
BOOST_CHECK_EQUAL(IsReachable(addr), false);
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, true); // have to reset this, because this is stateful.
|
2018-12-28 16:20:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
|
|
|
|
{
|
|
|
|
CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
|
|
|
|
|
2019-01-09 16:41:37 -08:00
|
|
|
SetReachable(NET_IPV4, true);
|
2018-12-28 16:20:30 +01:00
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsLocal(addr), false);
|
|
|
|
BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsLocal(addr), true);
|
|
|
|
|
|
|
|
RemoveLocal(addr);
|
|
|
|
BOOST_CHECK_EQUAL(IsLocal(addr), false);
|
|
|
|
}
|
|
|
|
|
2019-11-05 11:06:53 +01:00
|
|
|
BOOST_AUTO_TEST_CASE(PoissonNextSend)
|
|
|
|
{
|
|
|
|
g_mock_deterministic_tests = true;
|
|
|
|
|
|
|
|
int64_t now = 5000;
|
|
|
|
int average_interval_seconds = 600;
|
|
|
|
|
|
|
|
auto poisson = ::PoissonNextSend(now, average_interval_seconds);
|
|
|
|
std::chrono::microseconds poisson_chrono = ::PoissonNextSend(std::chrono::microseconds{now}, std::chrono::seconds{average_interval_seconds});
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(poisson, poisson_chrono.count());
|
|
|
|
|
|
|
|
g_mock_deterministic_tests = false;
|
|
|
|
}
|
2018-12-28 16:20:30 +01:00
|
|
|
|
2020-11-06 11:40:09 +00:00
|
|
|
std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(const int n_candidates, FastRandomContext& random_context)
|
|
|
|
{
|
|
|
|
std::vector<NodeEvictionCandidate> candidates;
|
|
|
|
for (int id = 0; id < n_candidates; ++id) {
|
|
|
|
candidates.push_back({
|
|
|
|
/* id */ id,
|
|
|
|
/* nTimeConnected */ static_cast<int64_t>(random_context.randrange(100)),
|
|
|
|
/* nMinPingUsecTime */ static_cast<int64_t>(random_context.randrange(100)),
|
|
|
|
/* nLastBlockTime */ static_cast<int64_t>(random_context.randrange(100)),
|
|
|
|
/* nLastTXTime */ static_cast<int64_t>(random_context.randrange(100)),
|
|
|
|
/* fRelevantServices */ random_context.randbool(),
|
|
|
|
/* fRelayTxes */ random_context.randbool(),
|
|
|
|
/* fBloomFilter */ random_context.randbool(),
|
|
|
|
/* nKeyedNetGroup */ random_context.randrange(100),
|
|
|
|
/* prefer_evict */ random_context.randbool(),
|
|
|
|
/* m_is_local */ random_context.randbool(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return candidates;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if any of the node ids in node_ids are selected for eviction.
|
|
|
|
bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::vector<NodeId>& node_ids, FastRandomContext& random_context)
|
|
|
|
{
|
|
|
|
Shuffle(candidates.begin(), candidates.end(), random_context);
|
|
|
|
const Optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates));
|
|
|
|
if (!evicted_node_id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return std::find(node_ids.begin(), node_ids.end(), *evicted_node_id) != node_ids.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create number_of_nodes random nodes, apply setup function candidate_setup_fn,
|
|
|
|
// apply eviction logic and then return true if any of the node ids in node_ids
|
|
|
|
// are selected for eviction.
|
|
|
|
bool IsEvicted(const int number_of_nodes, std::function<void(NodeEvictionCandidate&)> candidate_setup_fn, const std::vector<NodeId>& node_ids, FastRandomContext& random_context)
|
|
|
|
{
|
|
|
|
std::vector<NodeEvictionCandidate> candidates = GetRandomNodeEvictionCandidates(number_of_nodes, random_context);
|
|
|
|
for (NodeEvictionCandidate& candidate : candidates) {
|
|
|
|
candidate_setup_fn(candidate);
|
|
|
|
}
|
|
|
|
return IsEvicted(candidates, node_ids, random_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
constexpr int NODE_EVICTION_TEST_ROUNDS{10};
|
|
|
|
constexpr int NODE_EVICTION_TEST_UP_TO_N_NODES{200};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(node_eviction_test)
|
|
|
|
{
|
|
|
|
FastRandomContext random_context{true};
|
|
|
|
|
|
|
|
for (int i = 0; i < NODE_EVICTION_TEST_ROUNDS; ++i) {
|
|
|
|
for (int number_of_nodes = 0; number_of_nodes < NODE_EVICTION_TEST_UP_TO_N_NODES; ++number_of_nodes) {
|
|
|
|
// Four nodes with the highest keyed netgroup values should be
|
|
|
|
// protected from eviction.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nKeyedNetGroup = number_of_nodes - candidate.id;
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3}, random_context));
|
|
|
|
|
|
|
|
// Eight nodes with the lowest minimum ping time should be protected
|
|
|
|
// from eviction.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nMinPingUsecTime = candidate.id;
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3, 4, 5, 6, 7}, random_context));
|
|
|
|
|
|
|
|
// Four nodes that most recently sent us novel transactions accepted
|
|
|
|
// into our mempool should be protected from eviction.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nLastTXTime = number_of_nodes - candidate.id;
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3}, random_context));
|
|
|
|
|
|
|
|
// Up to eight non-tx-relay peers that most recently sent us novel
|
|
|
|
// blocks should be protected from eviction.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nLastBlockTime = number_of_nodes - candidate.id;
|
|
|
|
if (candidate.id <= 7) {
|
|
|
|
candidate.fRelayTxes = false;
|
|
|
|
candidate.fRelevantServices = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3, 4, 5, 6, 7}, random_context));
|
|
|
|
|
|
|
|
// Four peers that most recently sent us novel blocks should be
|
|
|
|
// protected from eviction.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nLastBlockTime = number_of_nodes - candidate.id;
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3}, random_context));
|
|
|
|
|
|
|
|
// Combination of the previous two tests.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nLastBlockTime = number_of_nodes - candidate.id;
|
|
|
|
if (candidate.id <= 7) {
|
|
|
|
candidate.fRelayTxes = false;
|
|
|
|
candidate.fRelevantServices = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, random_context));
|
|
|
|
|
|
|
|
// Combination of all tests above.
|
|
|
|
BOOST_CHECK(!IsEvicted(
|
|
|
|
number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) {
|
|
|
|
candidate.nKeyedNetGroup = number_of_nodes - candidate.id; // 4 protected
|
|
|
|
candidate.nMinPingUsecTime = candidate.id; // 8 protected
|
|
|
|
candidate.nLastTXTime = number_of_nodes - candidate.id; // 4 protected
|
|
|
|
candidate.nLastBlockTime = number_of_nodes - candidate.id; // 4 protected
|
|
|
|
},
|
|
|
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, random_context));
|
|
|
|
|
2020-12-15 15:23:44 +00:00
|
|
|
// An eviction is expected given >= 29 random eviction candidates. The eviction logic protects at most
|
|
|
|
// four peers by net group, eight by lowest ping time, four by last time of novel tx, up to eight non-tx-relay
|
|
|
|
// peers by last novel block time, and four more peers by last novel block time.
|
|
|
|
if (number_of_nodes >= 29) {
|
|
|
|
BOOST_CHECK(SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// No eviction is expected given <= 20 random eviction candidates. The eviction logic protects at least
|
|
|
|
// four peers by net group, eight by lowest ping time, four by last time of novel tx and four peers by last
|
|
|
|
// novel block time.
|
|
|
|
if (number_of_nodes <= 20) {
|
|
|
|
BOOST_CHECK(!SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context)));
|
|
|
|
}
|
|
|
|
|
2020-11-06 11:40:09 +00:00
|
|
|
// Cases left to test:
|
|
|
|
// * "Protect the half of the remaining nodes which have been connected the longest. [...]"
|
|
|
|
// * "Pick out up to 1/4 peers that are localhost, sorted by longest uptime. [...]"
|
|
|
|
// * "If any remaining peers are preferred for eviction consider only them. [...]"
|
|
|
|
// * "Identify the network group with the most connections and youngest member. [...]"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-16 12:54:30 -04:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|