diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp index cd1a33794..0d9405da8 100644 --- a/src/net_permissions.cpp +++ b/src/net_permissions.cpp @@ -1,162 +1,169 @@ // Copyright (c) 2009-2018 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 #include #include #include #include const std::vector NET_PERMISSIONS_DOC{ "bloomfilter (allow requesting BIP37 filtered blocks and transactions)", "noban (do not ban for misbehavior; implies download)", "forcerelay (relay transactions that are already in the mempool; implies " "relay)", "relay (relay even in -blocksonly mode, and unlimited transaction " "announcements)", "mempool (allow requesting BIP35 mempool contents)", "download (allow getheaders during IBD, no disconnect after " "maxuploadtarget limit)", + "bypass_proof_request_limits (experimental, bypass the limits on avalanche " + "proof downloads)", }; namespace { // The parse the following format "perm1,perm2@xxxxxx" bool TryParsePermissionFlags(const std::string str, NetPermissionFlags &output, size_t &readen, bilingual_str &error) { NetPermissionFlags flags = PF_NONE; const auto atSeparator = str.find('@'); // if '@' is not found (ie, "xxxxx"), the caller should apply implicit // permissions if (atSeparator == std::string::npos) { NetPermissions::AddFlag(flags, PF_ISIMPLICIT); readen = 0; } // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by // splitting by ',' and calculate the flags else { readen = 0; // permissions == perm1,perm2 const auto permissions = str.substr(0, atSeparator); while (readen < permissions.length()) { const auto commaSeparator = permissions.find(',', readen); const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen; // permission == perm1 const auto permission = permissions.substr(readen, len); // We read "perm1" readen += len; if (commaSeparator != std::string::npos) { // We read "," readen++; } if (permission == "bloomfilter" || permission == "bloom") { NetPermissions::AddFlag(flags, PF_BLOOMFILTER); } else if (permission == "noban") { NetPermissions::AddFlag(flags, PF_NOBAN); } else if (permission == "forcerelay") { NetPermissions::AddFlag(flags, PF_FORCERELAY); } else if (permission == "mempool") { NetPermissions::AddFlag(flags, PF_MEMPOOL); } else if (permission == "download") { NetPermissions::AddFlag(flags, PF_DOWNLOAD); } else if (permission == "all") { NetPermissions::AddFlag(flags, PF_ALL); } else if (permission == "relay") { NetPermissions::AddFlag(flags, PF_RELAY); + } else if (permission == "bypass_proof_request_limits") { + NetPermissions::AddFlag(flags, PF_BYPASS_PROOF_REQUEST_LIMITS); } else if (permission.length() == 0) { // Allow empty entries } else { error = strprintf(_("Invalid P2P permission: '%s'"), permission); return false; } } readen++; } output = flags; error = Untranslated(""); return true; } } // namespace std::vector NetPermissions::ToStrings(NetPermissionFlags flags) { std::vector strings; if (NetPermissions::HasFlag(flags, PF_BLOOMFILTER)) { strings.push_back("bloomfilter"); } if (NetPermissions::HasFlag(flags, PF_NOBAN)) { strings.push_back("noban"); } if (NetPermissions::HasFlag(flags, PF_FORCERELAY)) { strings.push_back("forcerelay"); } if (NetPermissions::HasFlag(flags, PF_RELAY)) { strings.push_back("relay"); } if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) { strings.push_back("mempool"); } if (NetPermissions::HasFlag(flags, PF_DOWNLOAD)) { strings.push_back("download"); } + if (NetPermissions::HasFlag(flags, PF_BYPASS_PROOF_REQUEST_LIMITS)) { + strings.push_back("bypass_proof_request_limits"); + } return strings; } bool NetWhitebindPermissions::TryParse(const std::string str, NetWhitebindPermissions &output, bilingual_str &error) { NetPermissionFlags flags; size_t offset; if (!TryParsePermissionFlags(str, flags, offset, error)) { return false; } const std::string strBind = str.substr(offset); CService addrBind; if (!Lookup(strBind, addrBind, 0, false)) { error = ResolveErrMsg("whitebind", strBind); return false; } if (addrBind.GetPort() == 0) { error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind); return false; } output.m_flags = flags; output.m_service = addrBind; error = Untranslated(""); return true; } bool NetWhitelistPermissions::TryParse(const std::string str, NetWhitelistPermissions &output, bilingual_str &error) { NetPermissionFlags flags; size_t offset; if (!TryParsePermissionFlags(str, flags, offset, error)) { return false; } const std::string net = str.substr(offset); CSubNet subnet; LookupSubNet(net, subnet); if (!subnet.IsValid()) { error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net); return false; } output.m_flags = flags; output.m_subnet = subnet; error = Untranslated(""); return true; } diff --git a/src/net_permissions.h b/src/net_permissions.h index 953aa8e2e..d1f9079d8 100644 --- a/src/net_permissions.h +++ b/src/net_permissions.h @@ -1,74 +1,77 @@ // Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_NET_PERMISSIONS_H #define BITCOIN_NET_PERMISSIONS_H #include #include #include struct bilingual_str; extern const std::vector NET_PERMISSIONS_DOC; enum NetPermissionFlags { PF_NONE = 0, // Can query bloomfilter even if -peerbloomfilters is false PF_BLOOMFILTER = (1U << 1), // Relay and accept transactions from this peer, even if -blocksonly is true // This peer is also not subject to limits on how many transaction INVs are // tracked PF_RELAY = (1U << 3), // Always relay transactions from this peer, even if already in mempool or // rejected from policy Keep parameter interaction: forcerelay implies relay PF_FORCERELAY = (1U << 2) | PF_RELAY, // Allow getheaders during IBD and block-download after maxuploadtarget // limit PF_DOWNLOAD = (1U << 6), // Can't be banned/disconnected/discouraged for misbehavior PF_NOBAN = (1U << 4) | PF_DOWNLOAD, // Can query the mempool PF_MEMPOOL = (1U << 5), + // Bypass the limit on how many proof INVs are tracked from this peer as + // well as the delay penalty when reaching the the in-flight requests limit + PF_BYPASS_PROOF_REQUEST_LIMITS = (1U << 30), // True if the user did not specifically set fine grained permissions PF_ISIMPLICIT = (1U << 31), PF_ALL = PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY | PF_NOBAN | PF_MEMPOOL | - PF_DOWNLOAD, + PF_DOWNLOAD | PF_BYPASS_PROOF_REQUEST_LIMITS, }; class NetPermissions { public: NetPermissionFlags m_flags; static std::vector ToStrings(NetPermissionFlags flags); static inline bool HasFlag(const NetPermissionFlags &flags, NetPermissionFlags f) { return (flags & f) == f; } static inline void AddFlag(NetPermissionFlags &flags, NetPermissionFlags f) { flags = static_cast(flags | f); } static inline void ClearFlag(NetPermissionFlags &flags, NetPermissionFlags f) { flags = static_cast(flags & ~f); } }; class NetWhitebindPermissions : public NetPermissions { public: static bool TryParse(const std::string str, NetWhitebindPermissions &output, bilingual_str &error); CService m_service; }; class NetWhitelistPermissions : public NetPermissions { public: static bool TryParse(const std::string str, NetWhitelistPermissions &output, bilingual_str &error); CSubNet m_subnet; }; #endif // BITCOIN_NET_PERMISSIONS_H diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index 07d850fee..3cb9cc173 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -1,63 +1,64 @@ // Copyright (c) 2020 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 #include #include #include #include #include #include #include #include void test_one_input(const std::vector &buffer) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(32); const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray({ NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, + NetPermissionFlags::PF_BYPASS_PROOF_REQUEST_LIMITS, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL, }) : static_cast( fuzzed_data_provider.ConsumeIntegral()); NetWhitebindPermissions net_whitebind_permissions; bilingual_str error_net_whitebind_permissions; if (NetWhitebindPermissions::TryParse(s, net_whitebind_permissions, error_net_whitebind_permissions)) { (void)NetPermissions::ToStrings(net_whitebind_permissions.m_flags); (void)NetPermissions::AddFlag(net_whitebind_permissions.m_flags, net_permission_flags); assert(NetPermissions::HasFlag(net_whitebind_permissions.m_flags, net_permission_flags)); (void)NetPermissions::ClearFlag(net_whitebind_permissions.m_flags, net_permission_flags); (void)NetPermissions::ToStrings(net_whitebind_permissions.m_flags); } NetWhitelistPermissions net_whitelist_permissions; bilingual_str error_net_whitelist_permissions; if (NetWhitelistPermissions::TryParse(s, net_whitelist_permissions, error_net_whitelist_permissions)) { (void)NetPermissions::ToStrings(net_whitelist_permissions.m_flags); (void)NetPermissions::AddFlag(net_whitelist_permissions.m_flags, net_permission_flags); assert(NetPermissions::HasFlag(net_whitelist_permissions.m_flags, net_permission_flags)); (void)NetPermissions::ClearFlag(net_whitelist_permissions.m_flags, net_permission_flags); (void)NetPermissions::ToStrings(net_whitelist_permissions.m_flags); } } diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 0d90162f8..d983f34cf 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,658 +1,661 @@ // Copyright (c) 2012-2019 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 #include #include #include #include #include #include #include #include #include #include BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) static CNetAddr ResolveIP(const std::string &ip) { CNetAddr addr; LookupHost(ip, addr, false); return addr; } static CSubNet ResolveSubNet(const std::string &subnet) { CSubNet ret; LookupSubNet(subnet, ret); return ret; } static CNetAddr CreateInternal(const std::string &host) { CNetAddr addr; addr.SetInternal(host); return addr; } BOOST_AUTO_TEST_CASE(netbase_networks) { BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE); BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE); BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4); BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6); BOOST_CHECK( ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION); BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL); } BOOST_AUTO_TEST_CASE(netbase_properties) { BOOST_CHECK(ResolveIP("127.0.0.1").IsIPv4()); BOOST_CHECK(ResolveIP("::FFFF:192.168.1.1").IsIPv4()); BOOST_CHECK(ResolveIP("::1").IsIPv6()); BOOST_CHECK(ResolveIP("10.0.0.1").IsRFC1918()); BOOST_CHECK(ResolveIP("192.168.1.1").IsRFC1918()); BOOST_CHECK(ResolveIP("172.31.255.255").IsRFC1918()); BOOST_CHECK(ResolveIP("198.18.0.0").IsRFC2544()); BOOST_CHECK(ResolveIP("198.19.255.255").IsRFC2544()); BOOST_CHECK(ResolveIP("2001:0DB8::").IsRFC3849()); BOOST_CHECK(ResolveIP("169.254.1.1").IsRFC3927()); BOOST_CHECK(ResolveIP("2002::1").IsRFC3964()); BOOST_CHECK(ResolveIP("FC00::").IsRFC4193()); BOOST_CHECK(ResolveIP("2001::2").IsRFC4380()); BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843()); BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343()); BOOST_CHECK(ResolveIP("FE80::").IsRFC4862()); BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052()); BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor()); BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal()); BOOST_CHECK(ResolveIP("::1").IsLocal()); BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable()); BOOST_CHECK(ResolveIP("2001::1").IsRoutable()); BOOST_CHECK(ResolveIP("127.0.0.1").IsValid()); BOOST_CHECK( CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal()); BOOST_CHECK(CreateInternal("bar.com").IsInternal()); } static bool TestSplitHost(std::string test, std::string host, int port) { std::string hostOut; int portOut = -1; SplitHostPort(test, portOut, hostOut); return hostOut == host && port == portOut; } BOOST_AUTO_TEST_CASE(netbase_splithost) { BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1)); BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1)); BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80)); BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80)); BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1)); BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333)); BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1)); BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333)); BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1)); BOOST_CHECK( TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333)); BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333)); BOOST_CHECK(TestSplitHost("::8333", "::8333", -1)); BOOST_CHECK(TestSplitHost(":8333", "", 8333)); BOOST_CHECK(TestSplitHost("[]:8333", "", 8333)); BOOST_CHECK(TestSplitHost("", "", -1)); } static bool TestParse(std::string src, std::string canon) { CService addr(LookupNumeric(src, 65535)); return canon == addr.ToString(); } BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) { BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535")); BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333")); BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535")); BOOST_CHECK(TestParse("::", "[::]:65535")); BOOST_CHECK(TestParse("[::]:8333", "[::]:8333")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); BOOST_CHECK(TestParse(":::", "[::]:0")); // verify that an internal address fails to resolve BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0")); // and that a one-off resolves correctly BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535")); } BOOST_AUTO_TEST_CASE(onioncat_test) { // values from // https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion")); CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca")); BOOST_CHECK(addr1 == addr2); BOOST_CHECK(addr1.IsTor()); BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion"); BOOST_CHECK(addr1.IsRoutable()); } BOOST_AUTO_TEST_CASE(embedded_test) { CNetAddr addr1(ResolveIP("1.2.3.4")); CNetAddr addr2(ResolveIP("::FFFF:0102:0304")); BOOST_CHECK(addr2.IsIPv4()); BOOST_CHECK_EQUAL(addr1.ToString(), addr2.ToString()); } BOOST_AUTO_TEST_CASE(subnet_test) { BOOST_CHECK(ResolveSubNet("1.2.3.0/24") == ResolveSubNet("1.2.3.0/255.255.255.0")); BOOST_CHECK(ResolveSubNet("1.2.3.0/24") != ResolveSubNet("1.2.4.0/255.255.255.0")); BOOST_CHECK(ResolveSubNet("1.2.3.0/24").Match(ResolveIP("1.2.3.4"))); BOOST_CHECK(!ResolveSubNet("1.2.2.0/24").Match(ResolveIP("1.2.3.4"))); BOOST_CHECK(ResolveSubNet("1.2.3.4").Match(ResolveIP("1.2.3.4"))); BOOST_CHECK(ResolveSubNet("1.2.3.4/32").Match(ResolveIP("1.2.3.4"))); BOOST_CHECK(!ResolveSubNet("1.2.3.4").Match(ResolveIP("5.6.7.8"))); BOOST_CHECK(!ResolveSubNet("1.2.3.4/32").Match(ResolveIP("5.6.7.8"))); BOOST_CHECK( ResolveSubNet("::ffff:127.0.0.1").Match(ResolveIP("127.0.0.1"))); BOOST_CHECK( ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:8"))); BOOST_CHECK( !ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:9"))); BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:0/112") .Match(ResolveIP("1:2:3:4:5:6:7:1234"))); BOOST_CHECK( ResolveSubNet("192.168.0.1/24").Match(ResolveIP("192.168.0.2"))); BOOST_CHECK( ResolveSubNet("192.168.0.20/29").Match(ResolveIP("192.168.0.18"))); BOOST_CHECK(ResolveSubNet("1.2.2.1/24").Match(ResolveIP("1.2.2.4"))); BOOST_CHECK(ResolveSubNet("1.2.2.110/31").Match(ResolveIP("1.2.2.111"))); BOOST_CHECK(ResolveSubNet("1.2.2.20/26").Match(ResolveIP("1.2.2.63"))); // All-Matching IPv6 Matches arbitrary IPv6 BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1:2:3:4:5:6:7:1234"))); // But not `::` or `0.0.0.0` because they are considered invalid addresses BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("::"))); BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("0.0.0.0"))); // Addresses from one network (IPv4) don't belong to subnets of another // network (IPv6) BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("1.2.3.4"))); // All-Matching IPv4 does not Match IPv6 BOOST_CHECK( !ResolveSubNet("0.0.0.0/0").Match(ResolveIP("1:2:3:4:5:6:7:1234"))); // Invalid subnets Match nothing (not even invalid addresses) BOOST_CHECK(!CSubNet().Match(ResolveIP("1.2.3.4"))); BOOST_CHECK(!ResolveSubNet("").Match(ResolveIP("4.5.6.7"))); BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("0.0.0.0"))); BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("hab"))); // Check valid/invalid BOOST_CHECK(ResolveSubNet("1.2.3.0/0").IsValid()); BOOST_CHECK(!ResolveSubNet("1.2.3.0/-1").IsValid()); BOOST_CHECK(ResolveSubNet("1.2.3.0/32").IsValid()); BOOST_CHECK(!ResolveSubNet("1.2.3.0/33").IsValid()); BOOST_CHECK(!ResolveSubNet("1.2.3.0/300").IsValid()); BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/0").IsValid()); BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/33").IsValid()); BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/-1").IsValid()); BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/128").IsValid()); BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/129").IsValid()); BOOST_CHECK(!ResolveSubNet("fuzzy").IsValid()); // CNetAddr constructor test BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).IsValid()); BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.1"))); BOOST_CHECK(!CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.2"))); BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).ToString() == "127.0.0.1/32"); CSubNet subnet = CSubNet(ResolveIP("1.2.3.4"), 32); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); subnet = CSubNet(ResolveIP("1.2.3.4"), 8); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); subnet = CSubNet(ResolveIP("1.2.3.4"), 0); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.255.255.255")); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.0.0.0")); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("0.0.0.0")); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).IsValid()); BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")) .Match(ResolveIP("1:2:3:4:5:6:7:8"))); BOOST_CHECK(!CSubNet(ResolveIP("1:2:3:4:5:6:7:8")) .Match(ResolveIP("1:2:3:4:5:6:7:9"))); BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128"); // IPv4 address with IPv6 netmask or the other way around. BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid()); BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid()); // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network). BOOST_CHECK( !CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")) .IsValid()); subnet = ResolveSubNet("1.2.3.4/255.255.255.255"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); subnet = ResolveSubNet("1.2.3.4/255.255.255.254"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31"); subnet = ResolveSubNet("1.2.3.4/255.255.255.252"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30"); subnet = ResolveSubNet("1.2.3.4/255.255.255.248"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29"); subnet = ResolveSubNet("1.2.3.4/255.255.255.240"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28"); subnet = ResolveSubNet("1.2.3.4/255.255.255.224"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27"); subnet = ResolveSubNet("1.2.3.4/255.255.255.192"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26"); subnet = ResolveSubNet("1.2.3.4/255.255.255.128"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25"); subnet = ResolveSubNet("1.2.3.4/255.255.255.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24"); subnet = ResolveSubNet("1.2.3.4/255.255.254.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23"); subnet = ResolveSubNet("1.2.3.4/255.255.252.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22"); subnet = ResolveSubNet("1.2.3.4/255.255.248.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21"); subnet = ResolveSubNet("1.2.3.4/255.255.240.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20"); subnet = ResolveSubNet("1.2.3.4/255.255.224.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19"); subnet = ResolveSubNet("1.2.3.4/255.255.192.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18"); subnet = ResolveSubNet("1.2.3.4/255.255.128.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17"); subnet = ResolveSubNet("1.2.3.4/255.255.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16"); subnet = ResolveSubNet("1.2.3.4/255.254.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15"); subnet = ResolveSubNet("1.2.3.4/255.252.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14"); subnet = ResolveSubNet("1.2.3.4/255.248.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13"); subnet = ResolveSubNet("1.2.3.4/255.240.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12"); subnet = ResolveSubNet("1.2.3.4/255.224.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11"); subnet = ResolveSubNet("1.2.3.4/255.192.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10"); subnet = ResolveSubNet("1.2.3.4/255.128.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9"); subnet = ResolveSubNet("1.2.3.4/255.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8"); subnet = ResolveSubNet("1.2.3.4/254.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7"); subnet = ResolveSubNet("1.2.3.4/252.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6"); subnet = ResolveSubNet("1.2.3.4/248.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5"); subnet = ResolveSubNet("1.2.3.4/240.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4"); subnet = ResolveSubNet("1.2.3.4/224.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3"); subnet = ResolveSubNet("1.2.3.4/192.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2"); subnet = ResolveSubNet("1.2.3.4/128.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1"); subnet = ResolveSubNet("1.2.3.4/0.0.0.0"); BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0"); subnet = ResolveSubNet( "1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128"); subnet = ResolveSubNet( "1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000"); BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16"); subnet = ResolveSubNet( "1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000"); BOOST_CHECK_EQUAL(subnet.ToString(), "::/0"); // Invalid netmasks (with 1-bits after 0-bits) subnet = ResolveSubNet("1.2.3.4/255.255.232.0"); BOOST_CHECK(!subnet.IsValid()); subnet = ResolveSubNet("1.2.3.4/255.0.255.255"); BOOST_CHECK(!subnet.IsValid()); subnet = ResolveSubNet( "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); BOOST_CHECK(!subnet.IsValid()); } BOOST_AUTO_TEST_CASE(netbase_getgroup) { // use /16 std::vector asmap; typedef std::vector Vec8; // Local -> !Routable() BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup(asmap) == Vec8{0}); // !Valid -> !Routable() BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup(asmap) == Vec8{0}); // RFC1918 -> !Routable() BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup(asmap) == Vec8{0}); // RFC3927 -> !Routable() BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup(asmap) == Vec8{0}); // IPv4 BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2})); // RFC6145 BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2})); // RFC6052 BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2})); // RFC3964 BOOST_CHECK( ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2})); // RFC4380 BOOST_CHECK( ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2})); // Tor BOOST_CHECK( ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup(asmap) == Vec8({NET_ONION, 239})); // he.net BOOST_CHECK( ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) == Vec8({NET_IPV6, 32, 1, 4, 112, 175})); // IPv6 BOOST_CHECK( ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) == Vec8({NET_IPV6, 32, 1, 32, 1})); // baz.net sha256 hash: // 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505 Vec8 internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07}; BOOST_CHECK(CreateInternal("baz.net").GetGroup(asmap) == internal_group); } BOOST_AUTO_TEST_CASE(netbase_parsenetwork) { BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4); BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6); BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4); BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6); BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE); BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE); BOOST_CHECK_EQUAL(ParseNetwork("\xfe\xff"), NET_UNROUTABLE); BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE); } BOOST_AUTO_TEST_CASE(netpermissions_test) { bilingual_str error; NetWhitebindPermissions whitebindPermissions; NetWhitelistPermissions whitelistPermissions; // Detect invalid white bind BOOST_CHECK( !NetWhitebindPermissions::TryParse("", whitebindPermissions, error)); BOOST_CHECK(error.original.find("Cannot resolve -whitebind address") != std::string::npos); BOOST_CHECK(!NetWhitebindPermissions::TryParse( "127.0.0.1", whitebindPermissions, error)); BOOST_CHECK(error.original.find("Need to specify a port with -whitebind") != std::string::npos); BOOST_CHECK( !NetWhitebindPermissions::TryParse("", whitebindPermissions, error)); // If no permission flags, assume backward compatibility BOOST_CHECK(NetWhitebindPermissions::TryParse("1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK(error.empty()); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ISIMPLICIT); BOOST_CHECK( NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT)); NetPermissions::ClearFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT); BOOST_CHECK( !NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE); NetPermissions::AddFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT); BOOST_CHECK( NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT)); // Can set one permission BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER); BOOST_CHECK(NetWhitebindPermissions::TryParse("@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE); // Happy path, can parse flags BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay@1.2.3.4:32", whitebindPermissions, error)); // forcerelay should also activate the relay permission BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY); BOOST_CHECK(NetWhitebindPermissions::TryParse( "bloom,relay,noban@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN); BOOST_CHECK(NetWhitebindPermissions::TryParse( "bloom,forcerelay,noban@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK(NetWhitebindPermissions::TryParse("all@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ALL); // Allow dups BOOST_CHECK(NetWhitebindPermissions::TryParse( "bloom,relay,noban,noban@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN); // Allow empty BOOST_CHECK(NetWhitebindPermissions::TryParse( "bloom,relay,,noban@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN); BOOST_CHECK(NetWhitebindPermissions::TryParse(",@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE); BOOST_CHECK(NetWhitebindPermissions::TryParse(",,@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE); // Detect invalid flag BOOST_CHECK(!NetWhitebindPermissions::TryParse( "bloom,forcerelay,oopsie@1.2.3.4:32", whitebindPermissions, error)); BOOST_CHECK(error.original.find("Invalid P2P permission") != std::string::npos); // Check whitelist error BOOST_CHECK(!NetWhitelistPermissions::TryParse( "bloom,forcerelay,noban@1.2.3.4:32", whitelistPermissions, error)); BOOST_CHECK( error.original.find("Invalid netmask specified in -whitelist") != std::string::npos); // Happy path for whitelist parsing BOOST_CHECK(NetWhitelistPermissions::TryParse("noban@1.2.3.4", whitelistPermissions, error)); BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_NOBAN); BOOST_CHECK(NetWhitelistPermissions::TryParse( - "bloom,forcerelay,noban,relay@1.2.3.4/32", whitelistPermissions, - error)); + "bloom,forcerelay,noban,relay,bypass_proof_request_limits@1.2.3.4/32", + whitelistPermissions, error)); BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, - PF_BLOOMFILTER | PF_FORCERELAY | PF_NOBAN | PF_RELAY); + PF_BLOOMFILTER | PF_FORCERELAY | PF_NOBAN | PF_RELAY | + PF_BYPASS_PROOF_REQUEST_LIMITS); BOOST_CHECK(error.empty()); BOOST_CHECK_EQUAL(whitelistPermissions.m_subnet.ToString(), "1.2.3.4/32"); BOOST_CHECK(NetWhitelistPermissions::TryParse( "bloom,forcerelay,noban,relay,mempool@1.2.3.4/32", whitelistPermissions, error)); const auto strings = NetPermissions::ToStrings(PF_ALL); - BOOST_CHECK_EQUAL(strings.size(), 6U); + BOOST_CHECK_EQUAL(strings.size(), 7U); BOOST_CHECK(std::find(strings.begin(), strings.end(), "bloomfilter") != strings.end()); BOOST_CHECK(std::find(strings.begin(), strings.end(), "forcerelay") != strings.end()); BOOST_CHECK(std::find(strings.begin(), strings.end(), "relay") != strings.end()); BOOST_CHECK(std::find(strings.begin(), strings.end(), "noban") != strings.end()); BOOST_CHECK(std::find(strings.begin(), strings.end(), "mempool") != strings.end()); BOOST_CHECK(std::find(strings.begin(), strings.end(), "download") != strings.end()); + BOOST_CHECK(std::find(strings.begin(), strings.end(), + "bypass_proof_request_limits") != strings.end()); } BOOST_AUTO_TEST_CASE( netbase_dont_resolve_strings_with_embedded_nul_characters) { CNetAddr addr; BOOST_CHECK(LookupHost(std::string("127.0.0.1", 9), addr, false)); BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0", 10), addr, false)); BOOST_CHECK( !LookupHost(std::string("127.0.0.1\0example.com", 21), addr, false)); BOOST_CHECK( !LookupHost(std::string("127.0.0.1\0example.com\0", 22), addr, false)); CSubNet ret; BOOST_CHECK(LookupSubNet(std::string("1.2.3.0/24", 10), ret)); BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0", 11), ret)); BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com", 22), ret)); BOOST_CHECK( !LookupSubNet(std::string("1.2.3.0/24\0example.com\0", 23), ret)); // We only do subnetting for IPv4 and IPv6 BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret)); BOOST_CHECK( !LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0", 23), ret)); BOOST_CHECK(!LookupSubNet( std::string("5wyqrzbvrdsumnok.onion\0example.com", 34), ret)); BOOST_CHECK(!LookupSubNet( std::string("5wyqrzbvrdsumnok.onion\0example.com\0", 35), ret)); } // Since CNetAddr (un)ser is tested separately in net_tests.cpp here we only // try a few edge cases for port, service flags and time. static const std::vector fixture_addresses( {CAddress(CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */), NODE_NONE, 0x4966bc61U /* Fri Jan 9 02:54:25 UTC 2009 */ ), CAddress(CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */), NODE_NETWORK, 0x83766279U /* Tue Nov 22 11:22:33 UTC 2039 */ ), CAddress( CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */), static_cast(NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED), 0xffffffffU /* Sun Feb 7 06:28:15 UTC 2106 */ )}); // fixture_addresses should equal to this when serialized in V1 format. // When this is unserialized from V1 format it should equal to // fixture_addresses. static constexpr const char *stream_addrv1_hex = // number of entries "03" // time, Fri Jan 9 02:54:25 UTC 2009 "61bc6649" // service flags, NODE_NONE "0000000000000000" // address, fixed 16 bytes (IPv4 embedded in IPv6) "00000000000000000000000000000001" // port "0000" // time, Tue Nov 22 11:22:33 UTC 2039 "79627683" // service flags, NODE_NETWORK "0100000000000000" // address, fixed 16 bytes (IPv6) "00000000000000000000000000000001" // port "00f1" // time, Sun Feb 7 06:28:15 UTC 2106 "ffffffff" // service flags, NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED "4004000000000000" // address, fixed 16 bytes (IPv6) "00000000000000000000000000000001" // port "f1f2"; // fixture_addresses should equal to this when serialized in V2 format. // When this is unserialized from V2 format it should equal to // fixture_addresses. static constexpr const char *stream_addrv2_hex = // number of entries "03" // time, Fri Jan 9 02:54:25 UTC 2009 "61bc6649" // service flags, COMPACTSIZE(NODE_NONE) "00" // network id, IPv6 "02" // address length, COMPACTSIZE(16) "10" // address "00000000000000000000000000000001" // port "0000" // time, Tue Nov 22 11:22:33 UTC 2039 "79627683" // service flags, COMPACTSIZE(NODE_NETWORK) "01" // network id, IPv6 "02" // address length, COMPACTSIZE(16) "10" // address "00000000000000000000000000000001" // port "00f1" // time, Sun Feb 7 06:28:15 UTC 2106 "ffffffff" // service flags, COMPACTSIZE(NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED) "fd4004" // network id, IPv6 "02" // address length, COMPACTSIZE(16) "10" // address "00000000000000000000000000000001" // port "f1f2"; BOOST_AUTO_TEST_CASE(caddress_serialize_v1) { CDataStream s(SER_NETWORK, PROTOCOL_VERSION); s << fixture_addresses; BOOST_CHECK_EQUAL(HexStr(s), stream_addrv1_hex); } BOOST_AUTO_TEST_CASE(caddress_unserialize_v1) { CDataStream s(ParseHex(stream_addrv1_hex), SER_NETWORK, PROTOCOL_VERSION); std::vector addresses_unserialized; s >> addresses_unserialized; BOOST_CHECK(fixture_addresses == addresses_unserialized); } BOOST_AUTO_TEST_CASE(caddress_serialize_v2) { CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); s << fixture_addresses; BOOST_CHECK_EQUAL(HexStr(s), stream_addrv2_hex); } BOOST_AUTO_TEST_CASE(caddress_unserialize_v2) { CDataStream s(ParseHex(stream_addrv2_hex), SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); std::vector addresses_unserialized; s >> addresses_unserialized; BOOST_CHECK(fixture_addresses == addresses_unserialized); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 0b3fad180..a9ed31879 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -1,132 +1,139 @@ #!/usr/bin/env python3 # Copyright (c) 2015-2018 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test p2p permission message. Test that permissions are correctly calculated and applied """ from test_framework.test_node import ErrorMatch from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes, p2p_port, ) class P2PPermissionsTests(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [[], []] def run_test(self): self.checkpermission( # default permissions (no specific permissions) ["-whitelist=127.0.0.1"], # Make sure the default values in the command line documentation # match the ones here ["relay", "noban", "mempool", "download"], True) self.checkpermission( # no permission (even with forcerelay) ["-whitelist=@127.0.0.1", "-whitelistforcerelay=1"], [], False) self.checkpermission( # relay permission removed (no specific permissions) ["-whitelist=127.0.0.1", "-whitelistrelay=0"], ["noban", "mempool", "download"], True) self.checkpermission( # forcerelay and relay permission added # Legacy parameter interaction which set whitelistrelay to true # if whitelistforcerelay is true ["-whitelist=127.0.0.1", "-whitelistforcerelay"], ["forcerelay", "relay", "noban", "mempool", "download"], True) # Let's make sure permissions are merged correctly # For this, we need to use whitebind instead of bind # by modifying the configuration file. ip_port = "127.0.0.1:{}".format(p2p_port(1)) self.replaceinconfig( 1, "bind=127.0.0.1", "whitebind=bloomfilter,forcerelay@" + ip_port) self.checkpermission( ["-whitelist=noban@127.0.0.1"], # Check parameter interaction forcerelay should activate relay ["noban", "bloomfilter", "forcerelay", "relay", "download"], False) self.replaceinconfig( 1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1") self.checkpermission( # legacy whitelistrelay should be ignored ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"], ["noban", "mempool", "download"], False) self.checkpermission( # legacy whitelistforcerelay should be ignored ["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"], ["noban", "mempool", "download"], False) self.checkpermission( # missing mempool permission to be considered legacy whitelisted ["-whitelist=noban@127.0.0.1"], ["noban", "download"], False) self.checkpermission( # all permission added ["-whitelist=all@127.0.0.1"], - ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download"], + ["forcerelay", "noban", "mempool", "bloomfilter", + "relay", "download", "bypass_proof_request_limits"], + False) + + self.checkpermission( + # bypass_proof_request_limits permission + ["-whitelist=bypass_proof_request_limits@127.0.0.1"], + ["bypass_proof_request_limits"], False) self.stop_node(1) self.nodes[1].assert_start_raises_init_error( ["-whitelist=oopsie@127.0.0.1"], "Invalid P2P permission", match=ErrorMatch.PARTIAL_REGEX) self.nodes[1].assert_start_raises_init_error( ["-whitelist=noban@127.0.0.1:230"], "Invalid netmask specified in", match=ErrorMatch.PARTIAL_REGEX) self.nodes[1].assert_start_raises_init_error( ["-whitebind=noban@127.0.0.1/10"], "Cannot resolve -whitebind address", match=ErrorMatch.PARTIAL_REGEX) def checkpermission(self, args, expectedPermissions, whitelisted): self.restart_node(1, args) connect_nodes(self.nodes[0], self.nodes[1]) peerinfo = self.nodes[1].getpeerinfo()[0] assert_equal(peerinfo['whitelisted'], whitelisted) assert_equal(len(expectedPermissions), len(peerinfo['permissions'])) for p in expectedPermissions: if p not in peerinfo['permissions']: raise AssertionError( "Expected permissions {!r} is not granted.".format(p)) def replaceinconfig(self, nodeid, old, new): with open(self.nodes[nodeid].bitcoinconf, encoding="utf8") as f: newText = f.read().replace(old, new) with open(self.nodes[nodeid].bitcoinconf, 'w', encoding="utf8") as f: f.write(newText) if __name__ == '__main__': P2PPermissionsTests().main()