diff options
author | Andrew Chow <github@achow101.com> | 2023-10-19 12:41:44 -0400 |
---|---|---|
committer | Andrew Chow <github@achow101.com> | 2023-10-19 12:48:39 -0400 |
commit | 0655e9dd92ea4a86d3e76d5689d59a71cff61357 (patch) | |
tree | 0c9b596dfbd11a53d1c5259369b6c1d216ba8b64 /src | |
parent | 6e721c923c87abdb8d99674093d08d8c17bc52c2 (diff) | |
parent | 0e6f6ebc064c5fb425fc3699efe760ec6cd4b6af (diff) |
Merge bitcoin/bitcoin#27071: Handle CJDNS from LookupSubNet()
0e6f6ebc064c5fb425fc3699efe760ec6cd4b6af net: remove unused CConnman::FindNode(const CSubNet&) (Vasil Dimov)
9482cb780fe04c1f1d9050edd1b8e549e52c86ce netbase: possibly change the result of LookupSubNet() to CJDNS (Vasil Dimov)
53afa68026ffa1313ae4aba3664de7791d23b1c8 net: move MaybeFlipIPv6toCJDNS() from net to netbase (Vasil Dimov)
6e308651c441cbf8763c67cc099c538c333c2872 net: move IsReachable() code to netbase and encapsulate it (Vasil Dimov)
c42ded3d9bda8b273780a4a81490bbf1b9e9c261 fuzz: ConsumeNetAddr(): avoid IPv6 addresses that look like CJDNS (Vasil Dimov)
64d6f77907afd461d9b14ee10ab32335f4454734 net: put CJDNS prefix byte in a constant (Vasil Dimov)
Pull request description:
`LookupSubNet()` would treat addresses that start with `fc` as IPv6 even if `-cjdnsreachable` is set. This creates the following problems where it is called:
* `NetWhitelistPermissions::TryParse()`: otherwise `-whitelist=` fails to white list CJDNS addresses: when a CJDNS peer connects to us, it will be matched against IPv6 `fc...` subnet and the match will never succeed.
* `BanMapFromJson()`: CJDNS bans are stored as just IPv6 addresses in `banlist.json`. Upon reading from disk they have to be converted back to CJDNS, otherwise, after restart, a ban entry like (`fc00::1`, IPv6) would not match a peer (`fc00::1`, CJDNS).
* `RPCConsole::unbanSelectedNode()`: in the GUI the ban entries go through `CSubNet::ToString()` and back via `LookupSubNet()`. Then it must match whatever is stored in `BanMan`, otherwise it is impossible to unban via the GUI.
These were uncovered by https://github.com/bitcoin/bitcoin/pull/26859.
Thus, flip the result of `LookupSubNet()` to CJDNS if the network base address starts with `fc` and `-cjdnsreachable` is set. Since subnetting/masking does not make sense for CJDNS (the address is "random" bytes, like Tor and I2P, there is no hierarchy) treat `fc.../mask` as an invalid `CSubNet`.
To achieve that, `MaybeFlipIPv6toCJDNS()` has to be moved from `net` to `netbase` and thus also `IsReachable()`. In the process of moving `IsReachable()`, `SetReachable()` and `vfLimited[]` encapsulate those in a class.
ACKs for top commit:
jonatack:
Code review ACK 0e6f6ebc064c5fb425fc3699efe760ec6cd4b6af
achow101:
ACK 0e6f6ebc064c5fb425fc3699efe760ec6cd4b6af
mzumsande:
re-ACK 0e6f6ebc064c5fb425fc3699efe760ec6cd4b6af
Tree-SHA512: 4767a60dc882916de4c8b110ce8de208ff3f58daaa0b560e6547d72e604d07c4157e72cf98b237228310fc05c0a3922f446674492e2ba02e990a272d288bd566
Diffstat (limited to 'src')
-rw-r--r-- | src/httpserver.cpp | 2 | ||||
-rw-r--r-- | src/init.cpp | 26 | ||||
-rw-r--r-- | src/net.cpp | 60 | ||||
-rw-r--r-- | src/net.h | 13 | ||||
-rw-r--r-- | src/net_processing.cpp | 7 | ||||
-rw-r--r-- | src/netaddress.h | 6 | ||||
-rw-r--r-- | src/netbase.cpp | 14 | ||||
-rw-r--r-- | src/netbase.h | 65 | ||||
-rw-r--r-- | src/netgroup.cpp | 4 | ||||
-rw-r--r-- | src/rpc/net.cpp | 6 | ||||
-rw-r--r-- | src/test/fuzz/util/net.cpp | 6 | ||||
-rw-r--r-- | src/test/net_tests.cpp | 96 | ||||
-rw-r--r-- | src/torcontrol.cpp | 2 |
13 files changed, 168 insertions, 139 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp index add6494f06..647e36adb3 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -682,7 +682,7 @@ CService HTTPRequest::GetPeer() const evhttp_connection_get_peer(con, (char**)&address, &port); #endif // HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR - peer = LookupNumeric(address, port); + peer = MaybeFlipIPv6toCJDNS(LookupNumeric(address, port)); } return peer; } diff --git a/src/init.cpp b/src/init.cpp index 22100dfbf9..42331d37e8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1314,30 +1314,24 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (args.IsArgSet("-onlynet")) { - std::set<enum Network> nets; + g_reachable_nets.RemoveAll(); for (const std::string& snet : args.GetArgs("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); - nets.insert(net); - } - for (int n = 0; n < NET_MAX; n++) { - enum Network net = (enum Network)n; - assert(IsReachable(net)); - if (!nets.count(net)) - SetReachable(net, false); + g_reachable_nets.Add(net); } } if (!args.IsArgSet("-cjdnsreachable")) { - if (args.IsArgSet("-onlynet") && IsReachable(NET_CJDNS)) { + if (args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_CJDNS)) { return InitError( _("Outbound connections restricted to CJDNS (-onlynet=cjdns) but " "-cjdnsreachable is not provided")); } - SetReachable(NET_CJDNS, false); + g_reachable_nets.Remove(NET_CJDNS); } - // Now IsReachable(NET_CJDNS) is true if: + // Now g_reachable_nets.Contains(NET_CJDNS) is true if: // 1. -cjdnsreachable is given and // 2.1. -onlynet is not given or // 2.2. -onlynet=cjdns is given @@ -1345,7 +1339,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit: // If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip // the DNS seeds by adjusting -dnsseed in InitParameterInteraction. - if (args.GetBoolArg("-dnsseed") == true && !IsReachable(NET_IPV4) && !IsReachable(NET_IPV6)) { + if (args.GetBoolArg("-dnsseed") == true && !g_reachable_nets.Contains(NET_IPV4) && !g_reachable_nets.Contains(NET_IPV6)) { return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6"))); }; @@ -1375,7 +1369,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) onion_proxy = addrProxy; } - const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)}; + const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_ONION)}; // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses // -noonion (or -onion=0) disables connecting to .onion entirely @@ -1410,7 +1404,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) "reaching the Tor network is not provided: none of -proxy, -onion or " "-listenonion is given")); } - SetReachable(NET_ONION, false); + g_reachable_nets.Remove(NET_ONION); } for (const std::string& strAddr : args.GetArgs("-externalip")) { @@ -1885,12 +1879,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } SetProxy(NET_I2P, Proxy{addr.value()}); } else { - if (args.IsArgSet("-onlynet") && IsReachable(NET_I2P)) { + if (args.IsArgSet("-onlynet") && g_reachable_nets.Contains(NET_I2P)) { return InitError( _("Outbound connections restricted to i2p (-onlynet=i2p) but " "-i2psam is not provided")); } - SetReachable(NET_I2P, false); + g_reachable_nets.Remove(NET_I2P); } connOptions.m_i2p_accept_incoming = args.GetBoolArg("-i2pacceptincoming", DEFAULT_I2P_ACCEPT_INCOMING); diff --git a/src/net.cpp b/src/net.cpp index 994abd986d..fecb4205ff 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -115,7 +115,6 @@ bool fDiscover = true; bool fListen = true; GlobalMutex g_maplocalhost_mutex; std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex); -static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {}; std::string strSubVersion; size_t CSerializedNetMsg::GetMemoryUsage() const noexcept @@ -232,7 +231,7 @@ static int GetnScore(const CService& addr) { CService addrLocal = pnode->GetAddrLocal(); return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && - IsReachable(addrLocal.GetNetwork()); + g_reachable_nets.Contains(addrLocal); } std::optional<CService> GetLocalAddrForPeer(CNode& node) @@ -270,22 +269,6 @@ std::optional<CService> GetLocalAddrForPeer(CNode& node) return std::nullopt; } -/** - * If an IPv6 address belongs to the address range used by the CJDNS network and - * the CJDNS network is reachable (-cjdnsreachable config is set), then change - * the type from NET_IPV6 to NET_CJDNS. - * @param[in] service Address to potentially convert. - * @return a copy of `service` either unmodified or changed to CJDNS. - */ -CService MaybeFlipIPv6toCJDNS(const CService& service) -{ - CService ret{service}; - if (ret.IsIPv6() && ret.HasCJDNSPrefix() && IsReachable(NET_CJDNS)) { - ret.m_net = NET_CJDNS; - } - return ret; -} - // learn a new local address bool AddLocal(const CService& addr_, int nScore) { @@ -297,7 +280,7 @@ bool AddLocal(const CService& addr_, int nScore) if (!fDiscover && nScore < LOCAL_MANUAL) return false; - if (!IsReachable(addr)) + if (!g_reachable_nets.Contains(addr)) return false; LogPrintf("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore); @@ -327,25 +310,6 @@ void RemoveLocal(const CService& addr) mapLocalHost.erase(addr); } -void SetReachable(enum Network net, bool reachable) -{ - if (net == NET_UNROUTABLE || net == NET_INTERNAL) - return; - LOCK(g_maplocalhost_mutex); - vfLimited[net] = !reachable; -} - -bool IsReachable(enum Network net) -{ - LOCK(g_maplocalhost_mutex); - return !vfLimited[net]; -} - -bool IsReachable(const CNetAddr &addr) -{ - return IsReachable(addr.GetNetwork()); -} - /** vote for a local address */ bool SeenLocal(const CService& addr) { @@ -375,17 +339,6 @@ CNode* CConnman::FindNode(const CNetAddr& ip) return nullptr; } -CNode* CConnman::FindNode(const CSubNet& subNet) -{ - LOCK(m_nodes_mutex); - for (CNode* pnode : m_nodes) { - if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) { - return pnode; - } - } - return nullptr; -} - CNode* CConnman::FindNode(const std::string& addrName) { LOCK(m_nodes_mutex); @@ -2433,7 +2386,7 @@ std::unordered_set<Network> CConnman::GetReachableEmptyNetworks() const for (int n = 0; n < NET_MAX; n++) { enum Network net = (enum Network)n; if (net == NET_UNROUTABLE || net == NET_INTERNAL) continue; - if (IsReachable(net) && addrman.Size(net, std::nullopt) == 0) { + if (g_reachable_nets.Contains(net) && addrman.Size(net, std::nullopt) == 0) { networks.insert(net); } } @@ -2453,7 +2406,7 @@ bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network) LOCK(m_nodes_mutex); for (const auto net : nets) { - if (IsReachable(net) && m_network_conn_counts[net] == 0 && addrman.Size(net) != 0) { + if (g_reachable_nets.Contains(net) && m_network_conn_counts[net] == 0 && addrman.Size(net) != 0) { network = net; return true; } @@ -2683,7 +2636,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) if (anchor && !m_anchors.empty()) { const CAddress addr = m_anchors.back(); m_anchors.pop_back(); - if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) || + if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) || !HasAllDesirableServiceFlags(addr.nServices) || outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue; addrConnect = addr; @@ -2738,8 +2691,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) break; } - if (!IsReachable(addr)) + if (!g_reachable_nets.Contains(addr)) { continue; + } // only consider very recently tried nodes after 30 failed attempts if (current_time - addr_last_try < 10min && nTries < 30) { @@ -160,24 +160,12 @@ enum /** Returns a local address that we should advertise to this peer. */ std::optional<CService> GetLocalAddrForPeer(CNode& node); -/** - * Mark a network as reachable or unreachable (no automatic connects to it) - * @note Networks are reachable by default - */ -void SetReachable(enum Network net, bool reachable); -/** @returns true if the network is reachable, false otherwise */ -bool IsReachable(enum Network net); -/** @returns true if the address is in a reachable network, false otherwise */ -bool IsReachable(const CNetAddr& addr); - bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); void RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); CService GetLocalAddress(const CNode& peer); -CService MaybeFlipIPv6toCJDNS(const CService& service); - extern bool fDiscover; extern bool fListen; @@ -1341,7 +1329,6 @@ private: uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; CNode* FindNode(const CNetAddr& ip); - CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& addr); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f07769272c..3bfb606037 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3830,14 +3830,15 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, continue; } ++num_proc; - bool fReachable = IsReachable(addr); + const bool reachable{g_reachable_nets.Contains(addr)}; if (addr.nTime > current_a_time - 10min && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes - RelayAddress(pfrom.GetId(), addr, fReachable); + RelayAddress(pfrom.GetId(), addr, reachable); } // Do not store addresses outside our network - if (fReachable) + if (reachable) { vAddrOk.push_back(addr); + } } peer->m_addr_processed += num_proc; peer->m_addr_rate_limited += num_rate_limit; diff --git a/src/netaddress.h b/src/netaddress.h index ad09f16799..08dd77c0ff 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -81,6 +81,10 @@ static const std::array<uint8_t, 6> INTERNAL_IN_IPV6_PREFIX{ 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 // 0xFD + sha256("bitcoin")[0:5]. }; +/// All CJDNS addresses start with 0xFC. See +/// https://github.com/cjdelisle/cjdns/blob/master/doc/Whitepaper.md#pulling-it-all-together +static constexpr uint8_t CJDNS_PREFIX{0xFC}; + /// Size of IPv4 address (in bytes). static constexpr size_t ADDR_IPV4_SIZE = 4; @@ -174,7 +178,7 @@ public: [[nodiscard]] bool IsTor() const { return m_net == NET_ONION; } [[nodiscard]] bool IsI2P() const { return m_net == NET_I2P; } [[nodiscard]] bool IsCJDNS() const { return m_net == NET_CJDNS; } - [[nodiscard]] bool HasCJDNSPrefix() const { return m_addr[0] == 0xfc; } + [[nodiscard]] bool HasCJDNSPrefix() const { return m_addr[0] == CJDNS_PREFIX; } bool IsLocal() const; bool IsRoutable() const; bool IsInternal() const; diff --git a/src/netbase.cpp b/src/netbase.cpp index ca1a80d72f..5e1e121bfe 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -32,6 +32,8 @@ bool fNameLookup = DEFAULT_NAME_LOOKUP; std::chrono::milliseconds g_socks5_recv_timeout = 20s; static std::atomic<bool> interruptSocks5Recv(false); +ReachableNets g_reachable_nets; + std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup) { addrinfo ai_hint{}; @@ -651,9 +653,10 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out) const size_t slash_pos{subnet_str.find_last_of('/')}; const std::string str_addr{subnet_str.substr(0, slash_pos)}; - const std::optional<CNetAddr> addr{LookupHost(str_addr, /*fAllowLookup=*/false)}; + std::optional<CNetAddr> addr{LookupHost(str_addr, /*fAllowLookup=*/false)}; if (addr.has_value()) { + addr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); if (slash_pos != subnet_str.npos) { const std::string netmask_str{subnet_str.substr(slash_pos + 1)}; uint8_t netmask; @@ -772,3 +775,12 @@ bool IsBadPort(uint16_t port) } return false; } + +CService MaybeFlipIPv6toCJDNS(const CService& service) +{ + CService ret{service}; + if (ret.IsIPv6() && ret.HasCJDNSPrefix() && g_reachable_nets.Contains(NET_CJDNS)) { + ret.m_net = NET_CJDNS; + } + return ret; +} diff --git a/src/netbase.h b/src/netbase.h index 1da4f5c51d..8b7da4109f 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <string> #include <type_traits> +#include <unordered_set> #include <vector> extern int nConnectTimeout; @@ -65,6 +66,61 @@ struct ProxyCredentials }; /** + * List of reachable networks. Everything is reachable by default. + */ +class ReachableNets { +public: + void Add(Network net) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + LOCK(m_mutex); + m_reachable.insert(net); + } + + void Remove(Network net) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + LOCK(m_mutex); + m_reachable.erase(net); + } + + void RemoveAll() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + LOCK(m_mutex); + m_reachable.clear(); + } + + [[nodiscard]] bool Contains(Network net) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + LOCK(m_mutex); + return m_reachable.count(net) > 0; + } + + [[nodiscard]] bool Contains(const CNetAddr& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) + { + AssertLockNotHeld(m_mutex); + return Contains(addr.GetNetwork()); + } + +private: + mutable Mutex m_mutex; + + std::unordered_set<Network> m_reachable GUARDED_BY(m_mutex){ + NET_UNROUTABLE, + NET_IPV4, + NET_IPV6, + NET_ONION, + NET_I2P, + NET_CJDNS, + NET_INTERNAL + }; +}; + +extern ReachableNets g_reachable_nets; + +/** * Wrapper for getaddrinfo(3). Do not use directly: call Lookup/LookupHost/LookupNumeric/LookupSubNet. */ std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup); @@ -251,4 +307,13 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a */ bool IsBadPort(uint16_t port); +/** + * If an IPv6 address belongs to the address range used by the CJDNS network and + * the CJDNS network is reachable (-cjdnsreachable config is set), then change + * the type from NET_IPV6 to NET_CJDNS. + * @param[in] service Address to potentially convert. + * @return a copy of `service` either unmodified or changed to CJDNS. + */ +CService MaybeFlipIPv6toCJDNS(const CService& service); + #endif // BITCOIN_NETBASE_H diff --git a/src/netgroup.cpp b/src/netgroup.cpp index 2d4d231f2b..a03927b152 100644 --- a/src/netgroup.cpp +++ b/src/netgroup.cpp @@ -52,8 +52,8 @@ std::vector<unsigned char> NetGroupManager::GetGroup(const CNetAddr& address) co } else if (address.IsCJDNS()) { // Treat in the same way as Tor and I2P because the address in all of // them is "random" bytes (derived from a public key). However in CJDNS - // the first byte is a constant 0xfc, so the random bytes come after it. - // Thus skip the constant 8 bits at the start. + // the first byte is a constant (see CJDNS_PREFIX), so the random bytes + // come after it. Thus skip the constant 8 bits at the start. nBits = 12; } else if (address.IsHeNet()) { // for he.net, use /36 groups diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 5a68bf9e1f..63788c3a03 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -585,8 +585,8 @@ static UniValue GetNetworksInfo() UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.pushKV("name", GetNetworkName(network)); - obj.pushKV("limited", !IsReachable(network)); - obj.pushKV("reachable", IsReachable(network)); + obj.pushKV("limited", !g_reachable_nets.Contains(network)); + obj.pushKV("reachable", g_reachable_nets.Contains(network)); obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringAddrPort() : std::string()); obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials); networks.push_back(obj); @@ -730,7 +730,7 @@ static RPCHelpMan setban() if (!isSubnet) { const std::optional<CNetAddr> addr{LookupHost(request.params[0].get_str(), false)}; if (addr.has_value()) { - netAddr = addr.value(); + netAddr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); } } else diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp index d23e997719..5a286c05d2 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -36,7 +36,11 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept } else if (network == Network::NET_IPV6) { if (fuzzed_data_provider.remaining_bytes() >= 16) { in6_addr v6_addr = {}; - memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16); + auto addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(16); + if (addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS. + addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do. + } + memcpy(v6_addr.s6_addr, addr_bytes.data(), 16); net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; } } else if (network == Network::NET_INTERNAL) { diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 796716d6cb..7c98c382e4 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -718,47 +718,55 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port) BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) { - BOOST_CHECK(IsReachable(NET_IPV4)); - BOOST_CHECK(IsReachable(NET_IPV6)); - BOOST_CHECK(IsReachable(NET_ONION)); - BOOST_CHECK(IsReachable(NET_I2P)); - BOOST_CHECK(IsReachable(NET_CJDNS)); - - SetReachable(NET_IPV4, false); - SetReachable(NET_IPV6, false); - SetReachable(NET_ONION, false); - SetReachable(NET_I2P, false); - SetReachable(NET_CJDNS, false); - - BOOST_CHECK(!IsReachable(NET_IPV4)); - BOOST_CHECK(!IsReachable(NET_IPV6)); - BOOST_CHECK(!IsReachable(NET_ONION)); - BOOST_CHECK(!IsReachable(NET_I2P)); - BOOST_CHECK(!IsReachable(NET_CJDNS)); - - SetReachable(NET_IPV4, true); - SetReachable(NET_IPV6, true); - SetReachable(NET_ONION, true); - SetReachable(NET_I2P, true); - SetReachable(NET_CJDNS, true); - - BOOST_CHECK(IsReachable(NET_IPV4)); - BOOST_CHECK(IsReachable(NET_IPV6)); - BOOST_CHECK(IsReachable(NET_ONION)); - BOOST_CHECK(IsReachable(NET_I2P)); - BOOST_CHECK(IsReachable(NET_CJDNS)); + BOOST_CHECK(g_reachable_nets.Contains(NET_IPV4)); + BOOST_CHECK(g_reachable_nets.Contains(NET_IPV6)); + BOOST_CHECK(g_reachable_nets.Contains(NET_ONION)); + BOOST_CHECK(g_reachable_nets.Contains(NET_I2P)); + BOOST_CHECK(g_reachable_nets.Contains(NET_CJDNS)); + + g_reachable_nets.Remove(NET_IPV4); + g_reachable_nets.Remove(NET_IPV6); + g_reachable_nets.Remove(NET_ONION); + g_reachable_nets.Remove(NET_I2P); + g_reachable_nets.Remove(NET_CJDNS); + + BOOST_CHECK(!g_reachable_nets.Contains(NET_IPV4)); + BOOST_CHECK(!g_reachable_nets.Contains(NET_IPV6)); + BOOST_CHECK(!g_reachable_nets.Contains(NET_ONION)); + BOOST_CHECK(!g_reachable_nets.Contains(NET_I2P)); + BOOST_CHECK(!g_reachable_nets.Contains(NET_CJDNS)); + + g_reachable_nets.Add(NET_IPV4); + g_reachable_nets.Add(NET_IPV6); + g_reachable_nets.Add(NET_ONION); + g_reachable_nets.Add(NET_I2P); + g_reachable_nets.Add(NET_CJDNS); + + BOOST_CHECK(g_reachable_nets.Contains(NET_IPV4)); + BOOST_CHECK(g_reachable_nets.Contains(NET_IPV6)); + BOOST_CHECK(g_reachable_nets.Contains(NET_ONION)); + BOOST_CHECK(g_reachable_nets.Contains(NET_I2P)); + BOOST_CHECK(g_reachable_nets.Contains(NET_CJDNS)); } BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal) { - BOOST_CHECK(IsReachable(NET_UNROUTABLE)); - BOOST_CHECK(IsReachable(NET_INTERNAL)); - - SetReachable(NET_UNROUTABLE, false); - SetReachable(NET_INTERNAL, false); - - BOOST_CHECK(IsReachable(NET_UNROUTABLE)); // Ignored for both networks - BOOST_CHECK(IsReachable(NET_INTERNAL)); + // Should be reachable by default. + BOOST_CHECK(g_reachable_nets.Contains(NET_UNROUTABLE)); + BOOST_CHECK(g_reachable_nets.Contains(NET_INTERNAL)); + + g_reachable_nets.RemoveAll(); + + BOOST_CHECK(!g_reachable_nets.Contains(NET_UNROUTABLE)); + BOOST_CHECK(!g_reachable_nets.Contains(NET_INTERNAL)); + + g_reachable_nets.Add(NET_IPV4); + g_reachable_nets.Add(NET_IPV6); + g_reachable_nets.Add(NET_ONION); + g_reachable_nets.Add(NET_I2P); + g_reachable_nets.Add(NET_CJDNS); + g_reachable_nets.Add(NET_UNROUTABLE); + g_reachable_nets.Add(NET_INTERNAL); } CNetAddr UtilBuildAddress(unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4) @@ -776,13 +784,13 @@ BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr) { CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1 - SetReachable(NET_IPV4, true); - BOOST_CHECK(IsReachable(addr)); + g_reachable_nets.Add(NET_IPV4); + BOOST_CHECK(g_reachable_nets.Contains(addr)); - SetReachable(NET_IPV4, false); - BOOST_CHECK(!IsReachable(addr)); + g_reachable_nets.Remove(NET_IPV4); + BOOST_CHECK(!g_reachable_nets.Contains(addr)); - SetReachable(NET_IPV4, true); // have to reset this, because this is stateful. + g_reachable_nets.Add(NET_IPV4); // have to reset this, because this is stateful. } @@ -790,7 +798,7 @@ BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle) { CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000 - SetReachable(NET_IPV4, true); + g_reachable_nets.Add(NET_IPV4); BOOST_CHECK(!IsLocal(addr)); BOOST_CHECK(AddLocal(addr, 1000)); @@ -915,7 +923,7 @@ BOOST_AUTO_TEST_CASE(advertise_local_address) ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false); }; - SetReachable(NET_CJDNS, true); + g_reachable_nets.Add(NET_CJDNS); CAddress addr_ipv4{Lookup("1.2.3.4", 8333, false).value(), NODE_NONE}; BOOST_REQUIRE(addr_ipv4.IsValid()); diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 4c99aa5746..60cf31a964 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -409,7 +409,7 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe // // If NET_ONION is not reachable, then none of -proxy or -onion was given. // Since we are here, then -torcontrol and -torpassword were given. - SetReachable(NET_ONION, true); + g_reachable_nets.Add(NET_ONION); } } |