LCOV - code coverage report
Current view: top level - src/test - net_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 238 239 99.6 %
Date: 2020-09-26 01:30:44 Functions: 101 101 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2012-2020 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <addrdb.h>
       6             : #include <addrman.h>
       7             : #include <chainparams.h>
       8             : #include <clientversion.h>
       9             : #include <cstdint>
      10             : #include <net.h>
      11             : #include <netbase.h>
      12             : #include <serialize.h>
      13             : #include <streams.h>
      14             : #include <test/util/setup_common.h>
      15             : #include <util/memory.h>
      16             : #include <util/strencodings.h>
      17             : #include <util/string.h>
      18             : #include <util/system.h>
      19             : #include <version.h>
      20             : 
      21             : #include <boost/test/unit_test.hpp>
      22             : 
      23             : #include <memory>
      24             : #include <string>
      25             : 
      26           4 : class CAddrManSerializationMock : public CAddrMan
      27             : {
      28             : public:
      29             :     virtual void Serialize(CDataStream& s) const = 0;
      30             : 
      31             :     //! Ensure that bucket placement is always the same for testing purposes.
      32           2 :     void MakeDeterministic()
      33             :     {
      34           2 :         nKey.SetNull();
      35           2 :         insecure_rand = FastRandomContext(true);
      36           2 :     }
      37             : };
      38             : 
      39           4 : class CAddrManUncorrupted : public CAddrManSerializationMock
      40             : {
      41             : public:
      42           2 :     void Serialize(CDataStream& s) const override
      43             :     {
      44           2 :         CAddrMan::Serialize(s);
      45           2 :     }
      46             : };
      47             : 
      48           4 : class CAddrManCorrupted : public CAddrManSerializationMock
      49             : {
      50             : public:
      51           2 :     void Serialize(CDataStream& s) const override
      52             :     {
      53             :         // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
      54           2 :         unsigned char nVersion = 1;
      55           2 :         s << nVersion;
      56           2 :         s << ((unsigned char)32);
      57           2 :         s << nKey;
      58           2 :         s << 10; // nNew
      59           2 :         s << 10; // nTried
      60             : 
      61           2 :         int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
      62           2 :         s << nUBuckets;
      63             : 
      64           2 :         CService serv;
      65           2 :         BOOST_CHECK(Lookup("252.1.1.1", serv, 7777, false));
      66           2 :         CAddress addr = CAddress(serv, NODE_NONE);
      67           2 :         CNetAddr resolved;
      68           2 :         BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
      69           2 :         CAddrInfo info = CAddrInfo(addr, resolved);
      70           2 :         s << info;
      71           2 :     }
      72             : };
      73             : 
      74           4 : static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
      75             : {
      76           4 :     CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
      77           4 :     ssPeersIn << Params().MessageStart();
      78           4 :     ssPeersIn << _addrman;
      79           4 :     std::string str = ssPeersIn.str();
      80           4 :     std::vector<unsigned char> vchData(str.begin(), str.end());
      81           4 :     return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
      82           4 : }
      83             : 
      84          89 : BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
      85             : 
      86          95 : BOOST_AUTO_TEST_CASE(cnode_listen_port)
      87             : {
      88             :     // test default
      89           1 :     uint16_t port = GetListenPort();
      90           1 :     BOOST_CHECK(port == Params().GetDefaultPort());
      91             :     // test set port
      92           1 :     uint16_t altPort = 12345;
      93           1 :     BOOST_CHECK(gArgs.SoftSetArg("-port", ToString(altPort)));
      94           1 :     port = GetListenPort();
      95           1 :     BOOST_CHECK(port == altPort);
      96           1 : }
      97             : 
      98          95 : BOOST_AUTO_TEST_CASE(caddrdb_read)
      99             : {
     100           1 :     CAddrManUncorrupted addrmanUncorrupted;
     101           1 :     addrmanUncorrupted.MakeDeterministic();
     102             : 
     103           1 :     CService addr1, addr2, addr3;
     104           1 :     BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
     105           1 :     BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
     106           1 :     BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
     107           1 :     BOOST_CHECK(Lookup(std::string("250.7.3.3", 9), addr3, 9999, false));
     108           1 :     BOOST_CHECK(!Lookup(std::string("250.7.3.3\0example.com", 21), addr3, 9999, false));
     109             : 
     110             :     // Add three addresses to new table.
     111           1 :     CService source;
     112           1 :     BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
     113           1 :     BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source));
     114           1 :     BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source));
     115           1 :     BOOST_CHECK(addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source));
     116             : 
     117             :     // Test that the de-serialization does not throw an exception.
     118           1 :     CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
     119             :     bool exceptionThrown = false;
     120           1 :     CAddrMan addrman1;
     121             : 
     122           1 :     BOOST_CHECK(addrman1.size() == 0);
     123             :     try {
     124           1 :         unsigned char pchMsgTmp[4];
     125           1 :         ssPeers1 >> pchMsgTmp;
     126           1 :         ssPeers1 >> addrman1;
     127           1 :     } catch (const std::exception&) {
     128             :         exceptionThrown = true;
     129           0 :     }
     130             : 
     131           1 :     BOOST_CHECK(addrman1.size() == 3);
     132           1 :     BOOST_CHECK(exceptionThrown == false);
     133             : 
     134             :     // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
     135           1 :     CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
     136             : 
     137           1 :     CAddrMan addrman2;
     138           1 :     BOOST_CHECK(addrman2.size() == 0);
     139           1 :     BOOST_CHECK(CAddrDB::Read(addrman2, ssPeers2));
     140           1 :     BOOST_CHECK(addrman2.size() == 3);
     141           1 : }
     142             : 
     143             : 
     144          95 : BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
     145             : {
     146           1 :     CAddrManCorrupted addrmanCorrupted;
     147           1 :     addrmanCorrupted.MakeDeterministic();
     148             : 
     149             :     // Test that the de-serialization of corrupted addrman throws an exception.
     150           1 :     CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
     151             :     bool exceptionThrown = false;
     152           1 :     CAddrMan addrman1;
     153           1 :     BOOST_CHECK(addrman1.size() == 0);
     154             :     try {
     155           1 :         unsigned char pchMsgTmp[4];
     156           1 :         ssPeers1 >> pchMsgTmp;
     157           1 :         ssPeers1 >> addrman1;
     158           1 :     } catch (const std::exception&) {
     159             :         exceptionThrown = true;
     160           1 :     }
     161             :     // Even through de-serialization failed addrman is not left in a clean state.
     162           1 :     BOOST_CHECK(addrman1.size() == 1);
     163           1 :     BOOST_CHECK(exceptionThrown);
     164             : 
     165             :     // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
     166           1 :     CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
     167             : 
     168           1 :     CAddrMan addrman2;
     169           1 :     BOOST_CHECK(addrman2.size() == 0);
     170           1 :     BOOST_CHECK(!CAddrDB::Read(addrman2, ssPeers2));
     171           1 :     BOOST_CHECK(addrman2.size() == 0);
     172           2 : }
     173             : 
     174          95 : BOOST_AUTO_TEST_CASE(cnode_simple_test)
     175             : {
     176           1 :     SOCKET hSocket = INVALID_SOCKET;
     177             :     NodeId id = 0;
     178           1 :     int height = 0;
     179             : 
     180           1 :     in_addr ipv4Addr;
     181           1 :     ipv4Addr.s_addr = 0xa0b0c001;
     182             : 
     183           1 :     CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
     184           1 :     std::string pszDest;
     185             : 
     186           1 :     std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
     187           1 :     BOOST_CHECK(pnode1->IsFullOutboundConn() == true);
     188           1 :     BOOST_CHECK(pnode1->IsManualConn() == false);
     189           1 :     BOOST_CHECK(pnode1->IsBlockOnlyConn() == false);
     190           1 :     BOOST_CHECK(pnode1->IsFeelerConn() == false);
     191           1 :     BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
     192           1 :     BOOST_CHECK(pnode1->IsInboundConn() == false);
     193             : 
     194           1 :     std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND);
     195           1 :     BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
     196           1 :     BOOST_CHECK(pnode2->IsManualConn() == false);
     197           1 :     BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
     198           1 :     BOOST_CHECK(pnode2->IsFeelerConn() == false);
     199           1 :     BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
     200           1 :     BOOST_CHECK(pnode2->IsInboundConn() == true);
     201           1 : }
     202             : 
     203          95 : BOOST_AUTO_TEST_CASE(cnetaddr_basic)
     204             : {
     205           1 :     CNetAddr addr;
     206             : 
     207             :     // IPv4, INADDR_ANY
     208           1 :     BOOST_REQUIRE(LookupHost("0.0.0.0", addr, false));
     209           1 :     BOOST_REQUIRE(!addr.IsValid());
     210           1 :     BOOST_REQUIRE(addr.IsIPv4());
     211             : 
     212           1 :     BOOST_CHECK(addr.IsBindAny());
     213           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
     214             : 
     215             :     // IPv4, INADDR_NONE
     216           1 :     BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
     217           1 :     BOOST_REQUIRE(!addr.IsValid());
     218           1 :     BOOST_REQUIRE(addr.IsIPv4());
     219             : 
     220           1 :     BOOST_CHECK(!addr.IsBindAny());
     221           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
     222             : 
     223             :     // IPv4, casual
     224           1 :     BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
     225           1 :     BOOST_REQUIRE(addr.IsValid());
     226           1 :     BOOST_REQUIRE(addr.IsIPv4());
     227             : 
     228           1 :     BOOST_CHECK(!addr.IsBindAny());
     229           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
     230             : 
     231             :     // IPv6, in6addr_any
     232           1 :     BOOST_REQUIRE(LookupHost("::", addr, false));
     233           1 :     BOOST_REQUIRE(!addr.IsValid());
     234           1 :     BOOST_REQUIRE(addr.IsIPv6());
     235             : 
     236           1 :     BOOST_CHECK(addr.IsBindAny());
     237           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "::");
     238             : 
     239             :     // IPv6, casual
     240           1 :     BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
     241           1 :     BOOST_REQUIRE(addr.IsValid());
     242           1 :     BOOST_REQUIRE(addr.IsIPv6());
     243             : 
     244           1 :     BOOST_CHECK(!addr.IsBindAny());
     245           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
     246             : 
     247             :     // TORv2
     248           1 :     addr.SetSpecial("6hzph5hv6337r6p2.onion");
     249           1 :     BOOST_REQUIRE(addr.IsValid());
     250           1 :     BOOST_REQUIRE(addr.IsTor());
     251             : 
     252           1 :     BOOST_CHECK(!addr.IsBindAny());
     253           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
     254             : 
     255             :     // Internal
     256           1 :     addr.SetInternal("esffpp");
     257           1 :     BOOST_REQUIRE(!addr.IsValid()); // "internal" is considered invalid
     258           1 :     BOOST_REQUIRE(addr.IsInternal());
     259             : 
     260           1 :     BOOST_CHECK(!addr.IsBindAny());
     261           1 :     BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
     262           1 : }
     263             : 
     264          95 : BOOST_AUTO_TEST_CASE(cnetaddr_serialize)
     265             : {
     266           1 :     CNetAddr addr;
     267           1 :     CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
     268             : 
     269           1 :     addr.SetInternal("a");
     270           1 :     s << addr;
     271           1 :     BOOST_CHECK_EQUAL(HexStr(s), "fd6b88c08724ca978112ca1bbdcafac2");
     272           1 :     s.clear();
     273           1 : }
     274             : 
     275             : // prior to PR #14728, this test triggers an undefined behavior
     276          95 : BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
     277             : {
     278             :     // set up local addresses; all that's necessary to reproduce the bug is
     279             :     // that a normal IPv4 address is among the entries, but if this address is
     280             :     // !IsRoutable the undefined behavior is easier to trigger deterministically
     281             :     {
     282           1 :         LOCK(cs_mapLocalHost);
     283           1 :         in_addr ipv4AddrLocal;
     284           1 :         ipv4AddrLocal.s_addr = 0x0100007f;
     285           1 :         CNetAddr addr = CNetAddr(ipv4AddrLocal);
     286             :         LocalServiceInfo lsi;
     287             :         lsi.nScore = 23;
     288             :         lsi.nPort = 42;
     289           1 :         mapLocalHost[addr] = lsi;
     290           1 :     }
     291             : 
     292             :     // create a peer with an IPv4 address
     293           1 :     in_addr ipv4AddrPeer;
     294           1 :     ipv4AddrPeer.s_addr = 0xa0b0c001;
     295           1 :     CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
     296           1 :     std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY);
     297           1 :     pnode->fSuccessfullyConnected.store(true);
     298             : 
     299             :     // the peer claims to be reaching us via IPv6
     300           1 :     in6_addr ipv6AddrLocal;
     301           1 :     memset(ipv6AddrLocal.s6_addr, 0, 16);
     302           1 :     ipv6AddrLocal.s6_addr[0] = 0xcc;
     303           1 :     CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
     304           1 :     pnode->SetAddrLocal(addrLocal);
     305             : 
     306             :     // before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
     307           1 :     AdvertiseLocal(&*pnode);
     308             : 
     309             :     // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
     310           1 :     BOOST_CHECK(1);
     311           1 : }
     312             : 
     313             : 
     314          95 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
     315             : {
     316           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
     317           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
     318           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
     319             : 
     320           1 :     SetReachable(NET_IPV4, false);
     321           1 :     SetReachable(NET_IPV6, false);
     322           1 :     SetReachable(NET_ONION, false);
     323             : 
     324           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false);
     325           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false);
     326           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false);
     327             : 
     328           1 :     SetReachable(NET_IPV4, true);
     329           1 :     SetReachable(NET_IPV6, true);
     330           1 :     SetReachable(NET_ONION, true);
     331             : 
     332           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
     333           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
     334           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
     335           1 : }
     336             : 
     337          95 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
     338             : {
     339           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
     340           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
     341             : 
     342           1 :     SetReachable(NET_UNROUTABLE, false);
     343           1 :     SetReachable(NET_INTERNAL, false);
     344             : 
     345           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); // Ignored for both networks
     346           1 :     BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
     347           1 : }
     348             : 
     349           2 : CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4)
     350             : {
     351             :     unsigned char ip[] = {p1, p2, p3, p4};
     352             : 
     353           2 :     struct sockaddr_in sa;
     354           2 :     memset(&sa, 0, sizeof(sockaddr_in)); // initialize the memory block
     355           2 :     memcpy(&(sa.sin_addr), &ip, sizeof(ip));
     356           2 :     return CNetAddr(sa.sin_addr);
     357           2 : }
     358             : 
     359             : 
     360          95 : BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr)
     361             : {
     362           1 :     CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1
     363             : 
     364           1 :     SetReachable(NET_IPV4, true);
     365           1 :     BOOST_CHECK_EQUAL(IsReachable(addr), true);
     366             : 
     367           1 :     SetReachable(NET_IPV4, false);
     368           1 :     BOOST_CHECK_EQUAL(IsReachable(addr), false);
     369             : 
     370           1 :     SetReachable(NET_IPV4, true); // have to reset this, because this is stateful.
     371           1 : }
     372             : 
     373             : 
     374          95 : BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
     375             : {
     376           1 :     CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000
     377             : 
     378           1 :     SetReachable(NET_IPV4, true);
     379             : 
     380           1 :     BOOST_CHECK_EQUAL(IsLocal(addr), false);
     381           1 :     BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true);
     382           1 :     BOOST_CHECK_EQUAL(IsLocal(addr), true);
     383             : 
     384           1 :     RemoveLocal(addr);
     385           1 :     BOOST_CHECK_EQUAL(IsLocal(addr), false);
     386           1 : }
     387             : 
     388          95 : BOOST_AUTO_TEST_CASE(PoissonNextSend)
     389             : {
     390           1 :     g_mock_deterministic_tests = true;
     391             : 
     392           1 :     int64_t now = 5000;
     393           1 :     int average_interval_seconds = 600;
     394             : 
     395           1 :     auto poisson = ::PoissonNextSend(now, average_interval_seconds);
     396           1 :     std::chrono::microseconds poisson_chrono = ::PoissonNextSend(std::chrono::microseconds{now}, std::chrono::seconds{average_interval_seconds});
     397             : 
     398           1 :     BOOST_CHECK_EQUAL(poisson, poisson_chrono.count());
     399             : 
     400           1 :     g_mock_deterministic_tests = false;
     401           1 : }
     402             : 
     403          89 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.15