diff --git a/src/netaddress.h b/src/netaddress.h --- a/src/netaddress.h +++ b/src/netaddress.h @@ -30,10 +30,8 @@ /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ class CNetAddr { protected: - // in network byte order - uint8_t ip[16]; - // for scoped/link-local ipv6 addresses - uint32_t scopeId; + uint8_t ip[16]; // in network byte order + uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses public: CNetAddr(); @@ -54,39 +52,25 @@ */ bool SetInternal(const std::string &name); - // for Tor addresses - bool SetSpecial(const std::string &strName); - // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) - bool IsIPv4() const; - // IPv6 address (not mapped IPv4, not Tor) - bool IsIPv6() const; - // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) - bool IsRFC1918() const; - // IPv4 inter-network communications (192.18.0.0/15) - bool IsRFC2544() const; - // IPv4 ISP-level NAT (100.64.0.0/10) - bool IsRFC6598() const; - // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, - // 203.0.113.0/24) - bool IsRFC5737() const; - // IPv6 documentation address (2001:0DB8::/32) - bool IsRFC3849() const; - // IPv4 autoconfig (169.254.0.0/16) - bool IsRFC3927() const; - // IPv6 6to4 tunnelling (2002::/16) - bool IsRFC3964() const; - // IPv6 unique local (FC00::/7) - bool IsRFC4193() const; - // IPv6 Teredo tunnelling (2001::/32) - bool IsRFC4380() const; - // IPv6 ORCHID (2001:10::/28) - bool IsRFC4843() const; - // IPv6 autoconfig (FE80::/64) - bool IsRFC4862() const; - // IPv6 well-known prefix (64:FF9B::/96) - bool IsRFC6052() const; - // IPv6 IPv4-translated address (::FFFF:0:0:0/96) - bool IsRFC6145() const; + bool SetSpecial(const std::string &strName); // for Tor addresses + 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) + 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 (192.18.0.0/15) + bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10) + bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, + // 198.51.100.0/24, 203.0.113.0/24) + bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) + bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) + bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) + bool IsRFC4193() const; // IPv6 unique local (FC00::/7) + bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) + bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) + bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) + bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) + bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsTor() const; bool IsLocal() const; bool IsRoutable() const; diff --git a/src/netaddress.cpp b/src/netaddress.cpp --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -20,7 +20,6 @@ CNetAddr::CNetAddr() { memset(ip, 0, sizeof(ip)); - scopeId = 0; } void CNetAddr::SetIP(const CNetAddr &ipIn) { diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -296,4 +296,45 @@ BOOST_CHECK_EQUAL(IsLocal(addr), false); } +// prior to PR #14728, this test triggers an undefined behavior +BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) { + // set up local addresses; all that's necessary to reproduce the bug is + // that a normal IPv4 address is among the entries, but if this address is + // !IsRoutable the undefined behavior is easier to trigger deterministically + { + LOCK(cs_mapLocalHost); + in_addr ipv4AddrLocal; + ipv4AddrLocal.s_addr = 0x0100007f; + CNetAddr addr = CNetAddr(ipv4AddrLocal); + LocalServiceInfo lsi; + lsi.nScore = 23; + lsi.nPort = 42; + mapLocalHost[addr] = lsi; + } + + // create a peer with an IPv4 address + in_addr ipv4AddrPeer; + ipv4AddrPeer.s_addr = 0xa0b0c001; + CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); + std::unique_ptr pnode = + std::make_unique(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, + CAddress{}, std::string{}, false); + pnode->fSuccessfullyConnected.store(true); + + // the peer claims to be reaching us via IPv6 + in6_addr ipv6AddrLocal; + memset(ipv6AddrLocal.s6_addr, 0, 16); + ipv6AddrLocal.s6_addr[0] = 0xcc; + CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK); + pnode->SetAddrLocal(addrLocal); + + // before patch, this causes undefined behavior detectable with clang's + // -fsanitize=memory + AdvertiseLocal(&*pnode); + + // suppress no-checks-run warning; if this test fails, it's by triggering a + // sanitizer + BOOST_CHECK(1); +} + BOOST_AUTO_TEST_SUITE_END()