|
4 | 4 |
|
5 | 5 | #include <chainparams.h>
|
6 | 6 | #include <clientversion.h>
|
| 7 | +#include <compat.h> |
7 | 8 | #include <cstdint>
|
8 | 9 | #include <net.h>
|
| 10 | +#include <net_processing.h> |
9 | 11 | #include <netaddress.h>
|
10 | 12 | #include <netbase.h>
|
| 13 | +#include <netmessagemaker.h> |
11 | 14 | #include <serialize.h>
|
12 | 15 | #include <span.h>
|
13 | 16 | #include <streams.h>
|
14 | 17 | #include <test/util/setup_common.h>
|
| 18 | +#include <test/util/validation.h> |
| 19 | +#include <timedata.h> |
15 | 20 | #include <util/strencodings.h>
|
16 | 21 | #include <util/string.h>
|
17 | 22 | #include <util/system.h>
|
| 23 | +#include <validation.h> |
18 | 24 | #include <version.h>
|
19 | 25 |
|
20 | 26 | #include <boost/test/unit_test.hpp>
|
|
27 | 33 |
|
28 | 34 | using namespace std::literals;
|
29 | 35 |
|
30 |
| -BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup) |
| 36 | +BOOST_FIXTURE_TEST_SUITE(net_tests, RegTestingSetup) |
31 | 37 |
|
32 | 38 | BOOST_AUTO_TEST_CASE(cnode_listen_port)
|
33 | 39 | {
|
@@ -607,15 +613,15 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
607 | 613 | // set up local addresses; all that's necessary to reproduce the bug is
|
608 | 614 | // that a normal IPv4 address is among the entries, but if this address is
|
609 | 615 | // !IsRoutable the undefined behavior is easier to trigger deterministically
|
| 616 | + in_addr raw_addr; |
| 617 | + raw_addr.s_addr = htonl(0x7f000001); |
| 618 | + const CNetAddr mapLocalHost_entry = CNetAddr(raw_addr); |
610 | 619 | {
|
611 | 620 | LOCK(g_maplocalhost_mutex);
|
612 |
| - in_addr ipv4AddrLocal; |
613 |
| - ipv4AddrLocal.s_addr = 0x0100007f; |
614 |
| - CNetAddr addr = CNetAddr(ipv4AddrLocal); |
615 | 621 | LocalServiceInfo lsi;
|
616 | 622 | lsi.nScore = 23;
|
617 | 623 | lsi.nPort = 42;
|
618 |
| - mapLocalHost[addr] = lsi; |
| 624 | + mapLocalHost[mapLocalHost_entry] = lsi; |
619 | 625 | }
|
620 | 626 |
|
621 | 627 | // create a peer with an IPv4 address
|
@@ -646,8 +652,79 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
646 | 652 |
|
647 | 653 | // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
|
648 | 654 | BOOST_CHECK(1);
|
| 655 | + |
| 656 | + // Cleanup, so that we don't confuse other tests. |
| 657 | + { |
| 658 | + LOCK(g_maplocalhost_mutex); |
| 659 | + mapLocalHost.erase(mapLocalHost_entry); |
| 660 | + } |
649 | 661 | }
|
650 | 662 |
|
| 663 | +BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port) |
| 664 | +{ |
| 665 | + // Test that GetLocalAddrForPeer() properly selects the address to self-advertise: |
| 666 | + // |
| 667 | + // 1. GetLocalAddrForPeer() calls GetLocalAddress() which returns an address that is |
| 668 | + // not routable. |
| 669 | + // 2. GetLocalAddrForPeer() overrides the address with whatever the peer has told us |
| 670 | + // he sees us as. |
| 671 | + // 2.1. For inbound connections we must override both the address and the port. |
| 672 | + // 2.2. For outbound connections we must override only the address. |
| 673 | + |
| 674 | + // Pretend that we bound to this port. |
| 675 | + const uint16_t bind_port = 20001; |
| 676 | + m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port)); |
| 677 | + |
| 678 | + // Our address:port as seen from the peer, completely different from the above. |
| 679 | + in_addr peer_us_addr; |
| 680 | + peer_us_addr.s_addr = htonl(0x02030405); |
| 681 | + const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK}; |
| 682 | + |
| 683 | + // Create a peer with a routable IPv4 address (outbound). |
| 684 | + in_addr peer_out_in_addr; |
| 685 | + peer_out_in_addr.s_addr = htonl(0x01020304); |
| 686 | + CNode peer_out{/*id=*/0, |
| 687 | + /*nLocalServicesIn=*/NODE_NETWORK, |
| 688 | + /*sock=*/nullptr, |
| 689 | + /*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK}, |
| 690 | + /*nKeyedNetGroupIn=*/0, |
| 691 | + /*nLocalHostNonceIn=*/0, |
| 692 | + /*addrBindIn=*/CAddress{}, |
| 693 | + /*addrNameIn=*/std::string{}, |
| 694 | + /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY, |
| 695 | + /*inbound_onion=*/false}; |
| 696 | + peer_out.fSuccessfullyConnected = true; |
| 697 | + peer_out.SetAddrLocal(peer_us); |
| 698 | + |
| 699 | + // Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port. |
| 700 | + auto chosen_local_addr = GetLocalAddrForPeer(&peer_out); |
| 701 | + BOOST_REQUIRE(chosen_local_addr); |
| 702 | + const CService expected{peer_us_addr, bind_port}; |
| 703 | + BOOST_CHECK(*chosen_local_addr == expected); |
| 704 | + |
| 705 | + // Create a peer with a routable IPv4 address (inbound). |
| 706 | + in_addr peer_in_in_addr; |
| 707 | + peer_in_in_addr.s_addr = htonl(0x05060708); |
| 708 | + CNode peer_in{/*id=*/0, |
| 709 | + /*nLocalServicesIn=*/NODE_NETWORK, |
| 710 | + /*sock=*/nullptr, |
| 711 | + /*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK}, |
| 712 | + /*nKeyedNetGroupIn=*/0, |
| 713 | + /*nLocalHostNonceIn=*/0, |
| 714 | + /*addrBindIn=*/CAddress{}, |
| 715 | + /*addrNameIn=*/std::string{}, |
| 716 | + /*conn_type_in=*/ConnectionType::INBOUND, |
| 717 | + /*inbound_onion=*/false}; |
| 718 | + peer_in.fSuccessfullyConnected = true; |
| 719 | + peer_in.SetAddrLocal(peer_us); |
| 720 | + |
| 721 | + // Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort(). |
| 722 | + chosen_local_addr = GetLocalAddrForPeer(&peer_in); |
| 723 | + BOOST_REQUIRE(chosen_local_addr); |
| 724 | + BOOST_CHECK(*chosen_local_addr == peer_us); |
| 725 | + |
| 726 | + m_node.args->ForceSetArg("-bind", ""); |
| 727 | +} |
651 | 728 |
|
652 | 729 | BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
|
653 | 730 | {
|
@@ -728,4 +805,108 @@ BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle)
|
728 | 805 | BOOST_CHECK(!IsLocal(addr));
|
729 | 806 | }
|
730 | 807 |
|
| 808 | +BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) |
| 809 | +{ |
| 810 | + // Tests the following scenario: |
| 811 | + // * -bind=3.4.5.6:20001 is specified |
| 812 | + // * we make an outbound connection to a peer |
| 813 | + // * the peer reports he sees us as 2.3.4.5:20002 in the version message |
| 814 | + // (20002 is a random port assigned by our OS for the outgoing TCP connection, |
| 815 | + // we cannot accept connections to it) |
| 816 | + // * we should self-advertise to that peer as 2.3.4.5:20001 |
| 817 | + |
| 818 | + // Pretend that we bound to this port. |
| 819 | + const uint16_t bind_port = 20001; |
| 820 | + m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port)); |
| 821 | + m_node.args->ForceSetArg("-capturemessages", "1"); |
| 822 | + |
| 823 | + // Our address:port as seen from the peer - 2.3.4.5:20002 (different from the above). |
| 824 | + in_addr peer_us_addr; |
| 825 | + peer_us_addr.s_addr = htonl(0x02030405); |
| 826 | + const CService peer_us{peer_us_addr, 20002}; |
| 827 | + |
| 828 | + // Create a peer with a routable IPv4 address. |
| 829 | + in_addr peer_in_addr; |
| 830 | + peer_in_addr.s_addr = htonl(0x01020304); |
| 831 | + CNode peer{/*id=*/0, |
| 832 | + /*nLocalServicesIn=*/NODE_NETWORK, |
| 833 | + /*sock=*/nullptr, |
| 834 | + /*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK}, |
| 835 | + /*nKeyedNetGroupIn=*/0, |
| 836 | + /*nLocalHostNonceIn=*/0, |
| 837 | + /*addrBindIn=*/CAddress{}, |
| 838 | + /*addrNameIn=*/std::string{}, |
| 839 | + /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY, |
| 840 | + /*inbound_onion=*/false}; |
| 841 | + |
| 842 | + const uint64_t services{NODE_NETWORK | NODE_WITNESS}; |
| 843 | + const int64_t time{0}; |
| 844 | + const CNetMsgMaker msg_maker{PROTOCOL_VERSION}; |
| 845 | + |
| 846 | + // Force CChainState::IsInitialBlockDownload() to return false. |
| 847 | + // Otherwise PushAddress() isn't called by PeerManager::ProcessMessage(). |
| 848 | + TestChainState& chainstate = |
| 849 | + *static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate()); |
| 850 | + chainstate.JumpOutOfIbd(); |
| 851 | + |
| 852 | + m_node.peerman->InitializeNode(&peer); |
| 853 | + |
| 854 | + std::atomic<bool> interrupt_dummy{false}; |
| 855 | + std::chrono::microseconds time_received_dummy{0}; |
| 856 | + |
| 857 | + const auto msg_version = |
| 858 | + msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, peer_us); |
| 859 | + CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION}; |
| 860 | + |
| 861 | + m_node.peerman->ProcessMessage( |
| 862 | + peer, NetMsgType::VERSION, msg_version_stream, time_received_dummy, interrupt_dummy); |
| 863 | + |
| 864 | + const auto msg_verack = msg_maker.Make(NetMsgType::VERACK); |
| 865 | + CDataStream msg_verack_stream{msg_verack.data, SER_NETWORK, PROTOCOL_VERSION}; |
| 866 | + |
| 867 | + // Will set peer.fSuccessfullyConnected to true (necessary in SendMessages()). |
| 868 | + m_node.peerman->ProcessMessage( |
| 869 | + peer, NetMsgType::VERACK, msg_verack_stream, time_received_dummy, interrupt_dummy); |
| 870 | + |
| 871 | + // Ensure that peer_us_addr:bind_port is sent to the peer. |
| 872 | + const CService expected{peer_us_addr, bind_port}; |
| 873 | + bool sent{false}; |
| 874 | + |
| 875 | + const auto CaptureMessageOrig = CaptureMessage; |
| 876 | + CaptureMessage = [&sent, &expected](const CAddress& addr, |
| 877 | + const std::string& msg_type, |
| 878 | + Span<const unsigned char> data, |
| 879 | + bool is_incoming) -> void { |
| 880 | + if (!is_incoming && msg_type == "addr") { |
| 881 | + CDataStream s(data, SER_NETWORK, PROTOCOL_VERSION); |
| 882 | + std::vector<CAddress> addresses; |
| 883 | + |
| 884 | + s >> addresses; |
| 885 | + |
| 886 | + for (const auto& addr : addresses) { |
| 887 | + if (addr == expected) { |
| 888 | + sent = true; |
| 889 | + return; |
| 890 | + } |
| 891 | + } |
| 892 | + } |
| 893 | + }; |
| 894 | + |
| 895 | + { |
| 896 | + LOCK(peer.cs_sendProcessing); |
| 897 | + m_node.peerman->SendMessages(&peer); |
| 898 | + } |
| 899 | + |
| 900 | + BOOST_CHECK(sent); |
| 901 | + |
| 902 | + CaptureMessage = CaptureMessageOrig; |
| 903 | + chainstate.ResetIbd(); |
| 904 | + m_node.args->ForceSetArg("-capturemessages", "0"); |
| 905 | + m_node.args->ForceSetArg("-bind", ""); |
| 906 | + // PeerManager::ProcessMessage() calls AddTimeData() which changes the internal state |
| 907 | + // in timedata.cpp and later confuses the test "timedata_tests/addtimedata". Thus reset |
| 908 | + // that state as it was before our test was run. |
| 909 | + TestOnlyResetTimeData(); |
| 910 | +} |
| 911 | + |
731 | 912 | BOOST_AUTO_TEST_SUITE_END()
|
0 commit comments