diff --git a/src/net.cpp b/src/net.cpp index ef1135bb8c5..0c6dac572d7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -158,39 +158,34 @@ uint16_t GetListenPort() return static_cast(gArgs.GetIntArg("-port", Params().GetDefaultPort())); } -// find 'best' local address for a particular peer -bool GetLocal(CService& addr, const CNode& peer) +// Determine the "best" local address for a particular peer. +[[nodiscard]] static std::optional GetLocal(const CNode& peer) { - if (!fListen) - return false; + if (!fListen) return std::nullopt; + std::optional addr; int nBestScore = -1; int nBestReachability = -1; { LOCK(g_maplocalhost_mutex); - for (const auto& entry : mapLocalHost) - { + for (const auto& [local_addr, local_service_info] : mapLocalHost) { // For privacy reasons, don't advertise our privacy-network address // to other networks and don't advertise our other-network address // to privacy networks. - const Network our_net{entry.first.GetNetwork()}; - const Network peers_net{peer.ConnectedThroughNetwork()}; - if (our_net != peers_net && - (our_net == NET_ONION || our_net == NET_I2P || - peers_net == NET_ONION || peers_net == NET_I2P)) { + if (local_addr.GetNetwork() != peer.ConnectedThroughNetwork() + && (local_addr.IsPrivacyNet() || peer.IsConnectedThroughPrivacyNet())) { continue; } - int nScore = entry.second.nScore; - int nReachability = entry.first.GetReachabilityFrom(peer.addr); - if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) - { - addr = CService(entry.first, entry.second.nPort); + const int nScore{local_service_info.nScore}; + const int nReachability{local_addr.GetReachabilityFrom(peer.addr)}; + if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) { + addr.emplace(CService{local_addr, local_service_info.nPort}); nBestReachability = nReachability; nBestScore = nScore; } } } - return nBestScore >= 0; + return addr; } //! Convert the serialized seeds into usable address objects. @@ -216,17 +211,13 @@ static std::vector ConvertSeeds(const std::vector &vSeedsIn) return vSeedsOut; } -// get best local address for a particular peer as a CAddress -// Otherwise, return the unroutable 0.0.0.0 but filled in with +// Determine the "best" local address for a particular peer. +// If none, return the unroutable 0.0.0.0 but filled in with // the normal parameters, since the IP may be changed to a useful // one by discovery. CService GetLocalAddress(const CNode& peer) { - CService addr; - if (GetLocal(addr, peer)) { - return addr; - } - return CService{CNetAddr(), GetListenPort()}; + return GetLocal(peer).value_or(CService{CNetAddr(), GetListenPort()}); } static int GetnScore(const CService& addr) @@ -237,7 +228,7 @@ static int GetnScore(const CService& addr) } // Is our peer's addrLocal potentially useful as an external IP source? -bool IsPeerAddrLocalGood(CNode *pnode) +[[nodiscard]] static bool IsPeerAddrLocalGood(CNode *pnode) { CService addrLocal = pnode->GetAddrLocal(); return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && @@ -289,7 +280,7 @@ std::optional GetLocalAddrForPeer(CNode& node) CService MaybeFlipIPv6toCJDNS(const CService& service) { CService ret{service}; - if (ret.m_net == NET_IPV6 && ret.m_addr[0] == 0xfc && IsReachable(NET_CJDNS)) { + if (ret.IsIPv6() && ret.HasCJDNSPrefix() && IsReachable(NET_CJDNS)) { ret.m_net = NET_CJDNS; } return ret; @@ -505,7 +496,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo const bool use_proxy{GetProxy(addrConnect.GetNetwork(), proxy)}; bool proxyConnectionFailed = false; - if (addrConnect.GetNetwork() == NET_I2P && use_proxy) { + if (addrConnect.IsI2P() && use_proxy) { i2p::Connection conn; if (m_i2p_sam_session) { @@ -637,6 +628,11 @@ Network CNode::ConnectedThroughNetwork() const return m_inbound_onion ? NET_ONION : addr.GetNetClass(); } +bool CNode::IsConnectedThroughPrivacyNet() const +{ + return m_inbound_onion || addr.IsPrivacyNet(); +} + #undef X #define X(name) stats.name = name void CNode::CopyStats(CNodeStats& stats) @@ -3753,10 +3749,11 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& address) const return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup).Finalize(); } -void CaptureMessageToFile(const CAddress& addr, - const std::string& msg_type, - Span data, - bool is_incoming) +// Dump binary message to file, with timestamp. +static void CaptureMessageToFile(const CAddress& addr, + const std::string& msg_type, + Span data, + bool is_incoming) { // Note: This function captures the message at the time of processing, // not at socket receive/send time. diff --git a/src/net.h b/src/net.h index 145b5cf666f..5ab693876cf 100644 --- a/src/net.h +++ b/src/net.h @@ -151,7 +151,6 @@ enum LOCAL_MAX }; -bool IsPeerAddrLocalGood(CNode *pnode); /** Returns a local address that we should advertise to this peer. */ std::optional GetLocalAddrForPeer(CNode& node); @@ -170,7 +169,6 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); void RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); -bool GetLocal(CService& addr, const CNode& peer); CService GetLocalAddress(const CNode& peer); CService MaybeFlipIPv6toCJDNS(const CService& service); @@ -834,6 +832,9 @@ public: */ Network ConnectedThroughNetwork() const; + /** Whether this peer connected through a privacy network. */ + [[nodiscard]] bool IsConnectedThroughPrivacyNet() const; + // We selected peer as (compact blocks) high-bandwidth peer (BIP152) std::atomic m_bip152_highbandwidth_to{false}; // Peer selected us as (compact blocks) high-bandwidth peer (BIP152) @@ -1575,12 +1576,6 @@ private: friend struct ConnmanTestMsg; }; -/** Dump binary message to file, with timestamp */ -void CaptureMessageToFile(const CAddress& addr, - const std::string& msg_type, - Span data, - bool is_incoming); - /** Defaults to `CaptureMessageToFile()`, but can be overridden by unit tests. */ extern std::function{0x20, 0x01, 0x04, 0x70}); } -/** - * Check whether this object represents a TOR address. - * @see CNetAddr::SetSpecial(const std::string &) - */ -bool CNetAddr::IsTor() const { return m_net == NET_ONION; } - -/** - * Check whether this object represents an I2P address. - */ -bool CNetAddr::IsI2P() const { return m_net == NET_I2P; } - -/** - * Check whether this object represents a CJDNS address. - */ -bool CNetAddr::IsCJDNS() const { return m_net == NET_CJDNS; } - bool CNetAddr::IsLocal() const { // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) @@ -450,8 +430,7 @@ bool CNetAddr::IsValid() const return false; } - // CJDNS addresses always start with 0xfc - if (IsCJDNS() && (m_addr[0] != 0xFC)) { + if (IsCJDNS() && !HasCJDNSPrefix()) { return false; } diff --git a/src/netaddress.h b/src/netaddress.h index 7d3659a11af..ad09f167991 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -154,8 +154,8 @@ public: bool SetSpecial(const std::string& addr); bool IsBindAny() const; // INADDR_ANY equivalent - bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) - bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) + [[nodiscard]] bool IsIPv4() const { return m_net == NET_IPV4; } // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) + [[nodiscard]] bool IsIPv6() const { return m_net == NET_IPV6; } // IPv6 address (not mapped IPv4, not Tor) bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) bool IsRFC2544() const; // IPv4 inter-network communications (198.18.0.0/15) bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10) @@ -171,14 +171,22 @@ public: bool IsRFC6052() const; // IPv6 well-known prefix for IPv4-embedded address (64:FF9B::/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) (actually defined in RFC2765) bool IsHeNet() const; // IPv6 Hurricane Electric - https://he.net (2001:0470::/36) - bool IsTor() const; - bool IsI2P() const; - bool IsCJDNS() const; + [[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; } bool IsLocal() const; bool IsRoutable() const; bool IsInternal() const; bool IsValid() const; + /** + * Whether this object is a privacy network. + * TODO: consider adding IsCJDNS() here when more peers adopt CJDNS, see: + * https://github.com/bitcoin/bitcoin/pull/27411#issuecomment-1497176155 + */ + [[nodiscard]] bool IsPrivacyNet() const { return IsTor() || IsI2P(); } + /** * Check if the current object can be serialized in pre-ADDRv2/BIP155 format. */