mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-14 22:02:37 -03:00
dbb1f640e6
Tests if addresses are online or offline by briefly connecting to them. These short lived connections are referred to as feeler connections. Feeler connections are designed to increase the number of fresh online addresses in tried by selecting and connecting to addresses in new. One feeler connection is attempted on average once every two minutes. This change was suggested as Countermeasure 4 in Eclipse Attacks on Bitcoin’s Peer-to-Peer Network, Ethan Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg. ePrint Archive Report 2015/263. March 2015.
175 lines
5.2 KiB
C++
175 lines
5.2 KiB
C++
// Copyright (c) 2012-2016 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
#include "addrman.h"
|
|
#include "test/test_bitcoin.h"
|
|
#include <string>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include "hash.h"
|
|
#include "serialize.h"
|
|
#include "streams.h"
|
|
#include "net.h"
|
|
#include "netbase.h"
|
|
#include "chainparams.h"
|
|
|
|
using namespace std;
|
|
|
|
class CAddrManSerializationMock : public CAddrMan
|
|
{
|
|
public:
|
|
virtual void Serialize(CDataStream& s, int nType, int nVersionDummy) const = 0;
|
|
|
|
//! Ensure that bucket placement is always the same for testing purposes.
|
|
void MakeDeterministic()
|
|
{
|
|
nKey.SetNull();
|
|
seed_insecure_rand(true);
|
|
}
|
|
};
|
|
|
|
class CAddrManUncorrupted : public CAddrManSerializationMock
|
|
{
|
|
public:
|
|
void Serialize(CDataStream& s, int nType, int nVersionDummy) const
|
|
{
|
|
CAddrMan::Serialize(s, nType, nVersionDummy);
|
|
}
|
|
};
|
|
|
|
class CAddrManCorrupted : public CAddrManSerializationMock
|
|
{
|
|
public:
|
|
void Serialize(CDataStream& s, int nType, int nVersionDummy) const
|
|
{
|
|
// 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;
|
|
|
|
CService serv;
|
|
Lookup("252.1.1.1", serv, 7777, false);
|
|
CAddress addr = CAddress(serv, NODE_NONE);
|
|
CNetAddr resolved;
|
|
LookupHost("252.2.2.2", resolved, false);
|
|
CAddrInfo info = CAddrInfo(addr, resolved);
|
|
s << info;
|
|
}
|
|
};
|
|
|
|
CDataStream AddrmanToStream(CAddrManSerializationMock& addrman)
|
|
{
|
|
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
|
|
ssPeersIn << FLATDATA(Params().MessageStart());
|
|
ssPeersIn << addrman;
|
|
std::string str = ssPeersIn.str();
|
|
vector<unsigned char> vchData(str.begin(), str.end());
|
|
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
|
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read)
|
|
{
|
|
CAddrManUncorrupted addrmanUncorrupted;
|
|
addrmanUncorrupted.MakeDeterministic();
|
|
|
|
CService addr1, addr2, addr3;
|
|
Lookup("250.7.1.1", addr1, 8333, false);
|
|
Lookup("250.7.2.2", addr2, 9999, false);
|
|
Lookup("250.7.3.3", addr3, 9999, false);
|
|
|
|
// Add three addresses to new table.
|
|
CService source;
|
|
Lookup("252.5.1.1", source, 8333, false);
|
|
addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);
|
|
addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);
|
|
addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);
|
|
|
|
// 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];
|
|
ssPeers1 >> FLATDATA(pchMsgTmp);
|
|
ssPeers1 >> addrman1;
|
|
} catch (const std::exception& e) {
|
|
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);
|
|
adb.Read(addrman2, ssPeers2);
|
|
BOOST_CHECK(addrman2.size() == 3);
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
|
|
{
|
|
CAddrManCorrupted addrmanCorrupted;
|
|
addrmanCorrupted.MakeDeterministic();
|
|
|
|
// 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];
|
|
ssPeers1 >> FLATDATA(pchMsgTmp);
|
|
ssPeers1 >> addrman1;
|
|
} catch (const std::exception& e) {
|
|
exceptionThrown = true;
|
|
}
|
|
// Even through de-serialization failed addrman is not left in a clean state.
|
|
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);
|
|
adb.Read(addrman2, ssPeers2);
|
|
BOOST_CHECK(addrman2.size() == 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
|
{
|
|
SOCKET hSocket = INVALID_SOCKET;
|
|
|
|
in_addr ipv4Addr;
|
|
ipv4Addr.s_addr = 0xa0b0c001;
|
|
|
|
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
|
|
std::string pszDest = "";
|
|
bool fInboundIn = false;
|
|
|
|
// Test that fFeeler is false by default.
|
|
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
|
|
BOOST_CHECK(pnode1->fInbound == false);
|
|
BOOST_CHECK(pnode1->fFeeler == false);
|
|
|
|
fInboundIn = true;
|
|
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
|
|
BOOST_CHECK(pnode2->fInbound == true);
|
|
BOOST_CHECK(pnode2->fFeeler == false);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|