2018-07-26 18:36:45 -04:00
|
|
|
// Copyright (c) 2012-2018 The Bitcoin Core developers
|
2016-03-16 13:54:30 -03:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2017-11-09 21:57:53 -03:00
|
|
|
#include <addrman.h>
|
|
|
|
#include <test/test_bitcoin.h>
|
2016-03-16 13:54:30 -03:00
|
|
|
#include <string>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
2017-11-09 21:57:53 -03:00
|
|
|
#include <hash.h>
|
|
|
|
#include <serialize.h>
|
|
|
|
#include <streams.h>
|
|
|
|
#include <net.h>
|
|
|
|
#include <netbase.h>
|
|
|
|
#include <chainparams.h>
|
2018-10-22 19:51:11 -03:00
|
|
|
#include <util/system.h>
|
2016-03-16 13:54:30 -03:00
|
|
|
|
2018-04-02 15:31:40 -03:00
|
|
|
#include <memory>
|
|
|
|
|
2016-03-16 13:54:30 -03:00
|
|
|
class CAddrManSerializationMock : public CAddrMan
|
|
|
|
{
|
|
|
|
public:
|
2016-10-28 20:29:17 -03: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 11:19:20 -03:00
|
|
|
insecure_rand = FastRandomContext(true);
|
2016-05-18 12:04:07 -04:00
|
|
|
}
|
2016-03-16 13:54:30 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
class CAddrManUncorrupted : public CAddrManSerializationMock
|
|
|
|
{
|
|
|
|
public:
|
2017-06-20 15:58:56 -04:00
|
|
|
void Serialize(CDataStream& s) const override
|
2016-03-16 13:54:30 -03:00
|
|
|
{
|
2016-10-28 20:29:17 -03:00
|
|
|
CAddrMan::Serialize(s);
|
2016-03-16 13:54:30 -03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CAddrManCorrupted : public CAddrManSerializationMock
|
|
|
|
{
|
|
|
|
public:
|
2017-06-20 15:58:56 -04:00
|
|
|
void Serialize(CDataStream& s) const override
|
2016-03-16 13:54:30 -03: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 10:31:38 -03: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 10:31:38 -03: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 13:54:30 -03:00
|
|
|
s << info;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-02 12:14:48 -03:00
|
|
|
static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
|
2016-03-16 13:54:30 -03:00
|
|
|
{
|
|
|
|
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
|
2018-03-20 21:37:32 -03:00
|
|
|
ssPeersIn << Params().MessageStart();
|
2016-09-02 13:19:01 -03:00
|
|
|
ssPeersIn << _addrman;
|
2016-03-16 13:54:30 -03:00
|
|
|
std::string str = ssPeersIn.str();
|
2016-12-05 04:03:53 -03:00
|
|
|
std::vector<unsigned char> vchData(str.begin(), str.end());
|
2016-03-16 13:54:30 -03:00
|
|
|
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
|
|
|
|
|
2017-04-25 11:26:43 -03:00
|
|
|
BOOST_AUTO_TEST_CASE(cnode_listen_port)
|
|
|
|
{
|
|
|
|
// test default
|
|
|
|
unsigned short port = GetListenPort();
|
|
|
|
BOOST_CHECK(port == Params().GetDefaultPort());
|
|
|
|
// test set port
|
|
|
|
unsigned short altPort = 12345;
|
2018-12-12 10:31:38 -03:00
|
|
|
BOOST_CHECK(gArgs.SoftSetArg("-port", std::to_string(altPort)));
|
2017-04-25 11:26:43 -03:00
|
|
|
port = GetListenPort();
|
|
|
|
BOOST_CHECK(port == altPort);
|
|
|
|
}
|
|
|
|
|
2016-03-16 13:54:30 -03:00
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read)
|
|
|
|
{
|
2018-07-14 10:36:14 -04:00
|
|
|
SetDataDir("caddrdb_read");
|
2016-03-16 13:54:30 -03:00
|
|
|
CAddrManUncorrupted addrmanUncorrupted;
|
2016-05-18 12:04:07 -04:00
|
|
|
addrmanUncorrupted.MakeDeterministic();
|
2016-03-16 13:54:30 -03:00
|
|
|
|
2016-05-31 13:51:11 -04:00
|
|
|
CService addr1, addr2, addr3;
|
2018-12-12 10:31:38 -03: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));
|
2016-03-16 13:54:30 -03:00
|
|
|
|
|
|
|
// Add three addresses to new table.
|
2016-05-31 13:51:11 -04:00
|
|
|
CService source;
|
2018-12-12 10:31:38 -03: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 13:54:30 -03: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 21:37:32 -03:00
|
|
|
ssPeers1 >> pchMsgTmp;
|
2016-03-16 13:54:30 -03:00
|
|
|
ssPeers1 >> addrman1;
|
2018-08-28 16:42:07 -03:00
|
|
|
} catch (const std::exception&) {
|
2016-03-16 13:54:30 -03: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;
|
|
|
|
CAddrDB adb;
|
|
|
|
BOOST_CHECK(addrman2.size() == 0);
|
2018-12-12 10:31:38 -03:00
|
|
|
BOOST_CHECK(adb.Read(addrman2, ssPeers2));
|
2016-03-16 13:54:30 -03:00
|
|
|
BOOST_CHECK(addrman2.size() == 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
|
|
|
|
{
|
2018-07-14 10:36:14 -04:00
|
|
|
SetDataDir("caddrdb_read_corrupted");
|
2016-03-16 13:54:30 -03:00
|
|
|
CAddrManCorrupted addrmanCorrupted;
|
2016-05-18 12:04:07 -04:00
|
|
|
addrmanCorrupted.MakeDeterministic();
|
2016-03-16 13:54:30 -03: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 21:37:32 -03:00
|
|
|
ssPeers1 >> pchMsgTmp;
|
2016-03-16 13:54:30 -03:00
|
|
|
ssPeers1 >> addrman1;
|
2018-08-28 16:42:07 -03:00
|
|
|
} catch (const std::exception&) {
|
2016-03-16 13:54:30 -03: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 13:54:30 -03: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;
|
|
|
|
CAddrDB adb;
|
|
|
|
BOOST_CHECK(addrman2.size() == 0);
|
2018-12-12 10:31:38 -03:00
|
|
|
BOOST_CHECK(!adb.Read(addrman2, ssPeers2));
|
2016-03-16 13:54:30 -03: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 21:20:34 -03: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 11:59:49 -04:00
|
|
|
|
2016-06-17 00:10:07 -04:00
|
|
|
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
2018-01-14 14:15:31 -03:00
|
|
|
std::string pszDest;
|
2016-06-17 00:10:07 -04:00
|
|
|
bool fInboundIn = false;
|
|
|
|
|
|
|
|
// Test that fFeeler is false by default.
|
2018-09-21 06:03:21 -03:00
|
|
|
std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn);
|
2016-06-17 00:10:07 -04:00
|
|
|
BOOST_CHECK(pnode1->fInbound == false);
|
|
|
|
BOOST_CHECK(pnode1->fFeeler == false);
|
|
|
|
|
|
|
|
fInboundIn = true;
|
2018-09-21 06:03:21 -03:00
|
|
|
std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn);
|
2016-06-17 00:10:07 -04:00
|
|
|
BOOST_CHECK(pnode2->fInbound == true);
|
|
|
|
BOOST_CHECK(pnode2->fFeeler == false);
|
|
|
|
}
|
|
|
|
|
2018-11-15 17:34:46 -03: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);
|
|
|
|
std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, false);
|
|
|
|
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 12:20:30 -03:00
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
|
|
|
|
{
|
|
|
|
SetLimited(NET_IPV4, true);
|
|
|
|
SetLimited(NET_IPV6, true);
|
|
|
|
SetLimited(NET_ONION, true);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_ONION), true);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false);
|
|
|
|
|
|
|
|
|
|
|
|
SetLimited(NET_IPV4, false);
|
|
|
|
SetLimited(NET_IPV6, false);
|
|
|
|
SetLimited(NET_ONION, false);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_ONION), false);
|
|
|
|
|
|
|
|
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(IsLimited(NET_UNROUTABLE), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
|
|
|
|
|
|
|
|
SetLimited(NET_UNROUTABLE, true);
|
|
|
|
SetLimited(NET_INTERNAL, true);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_UNROUTABLE), false); // Ignored for both networks
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false);
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
|
|
|
|
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
|
|
|
|
|
|
|
|
SetLimited(NET_IPV4, false);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(addr), false);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(addr), true);
|
|
|
|
|
|
|
|
SetLimited(NET_IPV4, true);
|
|
|
|
BOOST_CHECK_EQUAL(IsLimited(addr), true);
|
|
|
|
BOOST_CHECK_EQUAL(IsReachable(addr), false);
|
|
|
|
|
|
|
|
SetLimited(NET_IPV4, false); // have to reset this, because this is stateful.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
|
|
|
|
{
|
|
|
|
CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
|
|
|
|
|
|
|
|
SetLimited(NET_IPV4, false);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-16 13:54:30 -03:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|