diff options
author | Vasil Dimov <vd@FreeBSD.org> | 2023-01-09 14:31:22 +0100 |
---|---|---|
committer | Vasil Dimov <vd@FreeBSD.org> | 2024-01-23 11:49:32 +0100 |
commit | b851c5385d0a0acec4493be1561cea285065d5dc (patch) | |
tree | f63b84cb6d02abe85703c6fb5a350a47a7a67eb2 | |
parent | 651fb034d85eb5db561bfd24b74f7271417defa5 (diff) | |
download | bitcoin-b851c5385d0a0acec4493be1561cea285065d5dc.tar.xz |
fuzz: extend ConsumeNetAddr() to return I2P and CJDNS addresses
In the process of doing so, refactor `ConsumeNetAddr()` to generate the
addresses from IPv4, IPv6, Tor, I2P and CJDNS networks in the same way -
by preparing some random stream and deserializing from it. Similar code
was already found in `RandAddr()`.
-rw-r--r-- | src/netaddress.h | 24 | ||||
-rw-r--r-- | src/test/fuzz/addrman.cpp | 25 | ||||
-rw-r--r-- | src/test/fuzz/banman.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/netaddress.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/util/net.cpp | 78 | ||||
-rw-r--r-- | src/test/fuzz/util/net.h | 10 |
6 files changed, 100 insertions, 61 deletions
diff --git a/src/netaddress.h b/src/netaddress.h index 08dd77c0ff..0bbde43dd7 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -261,6 +261,18 @@ public: } } + /** + * BIP155 network ids recognized by this software. + */ + enum BIP155Network : uint8_t { + IPV4 = 1, + IPV6 = 2, + TORV2 = 3, + TORV3 = 4, + I2P = 5, + CJDNS = 6, + }; + friend class CSubNet; private: @@ -283,18 +295,6 @@ private: bool SetI2P(const std::string& addr); /** - * BIP155 network ids recognized by this software. - */ - enum BIP155Network : uint8_t { - IPV4 = 1, - IPV6 = 2, - TORV2 = 3, - TORV3 = 4, - I2P = 5, - CJDNS = 6, - }; - - /** * Size of CNetAddr when serialized as ADDRv1 (pre-BIP155) (in bytes). */ static constexpr size_t V1_SERIALIZATION_SIZE = ADDR_IPV6_SIZE; diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index ece396aadf..8a54cc656d 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -64,26 +64,13 @@ FUZZ_TARGET(data_stream_addr_man, .init = initialize_addrman) CNetAddr RandAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext& fast_random_context) { CNetAddr addr; - if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) { - addr = ConsumeNetAddr(fuzzed_data_provider); - } else { - // The networks [1..6] correspond to CNetAddr::BIP155Network (private). - static const std::map<uint8_t, uint8_t> net_len_map = {{1, ADDR_IPV4_SIZE}, - {2, ADDR_IPV6_SIZE}, - {4, ADDR_TORV3_SIZE}, - {5, ADDR_I2P_SIZE}, - {6, ADDR_CJDNS_SIZE}}; - uint8_t net = fast_random_context.randrange(5) + 1; // [1..5] - if (net == 3) { - net = 6; + assert(!addr.IsValid()); + for (size_t i = 0; i < 8 && !addr.IsValid(); ++i) { + if (fuzzed_data_provider.remaining_bytes() > 1 && fuzzed_data_provider.ConsumeBool()) { + addr = ConsumeNetAddr(fuzzed_data_provider); + } else { + addr = ConsumeNetAddr(fuzzed_data_provider, &fast_random_context); } - - DataStream s{}; - - s << net; - s << fast_random_context.randbytes(net_len_map.at(net)); - - s >> CAddress::V2_NETWORK(addr); } // Return a dummy IPv4 5.5.5.5 if we generated an invalid address. diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index 4a040c56de..b26151f63c 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -70,11 +70,13 @@ FUZZ_TARGET(banman, .init = initialize_banman) fuzzed_data_provider, [&] { CNetAddr net_addr{ConsumeNetAddr(fuzzed_data_provider)}; - const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)}; - if (addr.has_value() && addr->IsValid()) { - net_addr = *addr; - } else { - contains_invalid = true; + if (!net_addr.IsCJDNS() || !net_addr.IsValid()) { + const std::optional<CNetAddr>& addr{LookupHost(net_addr.ToStringAddr(), /*fAllowLookup=*/false)}; + if (addr.has_value() && addr->IsValid()) { + net_addr = *addr; + } else { + contains_invalid = true; + } } ban_man.Ban(net_addr, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); }, diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index 5141d3362d..4803cdccad 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -26,6 +26,12 @@ FUZZ_TARGET(netaddress) if (net_addr.GetNetwork() == Network::NET_ONION) { assert(net_addr.IsTor()); } + if (net_addr.GetNetwork() == Network::NET_I2P) { + assert(net_addr.IsI2P()); + } + if (net_addr.GetNetwork() == Network::NET_CJDNS) { + assert(net_addr.IsCJDNS()); + } if (net_addr.GetNetwork() == Network::NET_INTERNAL) { assert(net_addr.IsInternal()); } @@ -69,6 +75,12 @@ FUZZ_TARGET(netaddress) if (net_addr.IsTor()) { assert(net_addr.GetNetwork() == Network::NET_ONION); } + if (net_addr.IsI2P()) { + assert(net_addr.GetNetwork() == Network::NET_I2P); + } + if (net_addr.IsCJDNS()) { + assert(net_addr.GetNetwork() == Network::NET_CJDNS); + } (void)net_addr.IsValid(); (void)net_addr.ToStringAddr(); diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp index eb0f14ede0..99151bb84d 100644 --- a/src/test/fuzz/util/net.cpp +++ b/src/test/fuzz/util/net.cpp @@ -25,33 +25,63 @@ class CNode; -CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept +CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand) noexcept { - const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION}); - CNetAddr net_addr; - if (network == Network::NET_IPV4) { - in_addr v4_addr = {}; - v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); - net_addr = CNetAddr{v4_addr}; - } else if (network == Network::NET_IPV6) { - if (fuzzed_data_provider.remaining_bytes() >= 16) { - in6_addr v6_addr = {}; - 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>()}; + struct NetAux { + Network net; + CNetAddr::BIP155Network bip155; + size_t len; + }; + + static constexpr std::array<NetAux, 6> nets{ + NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE}, + NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE}, + NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE}, + NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE}, + NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE}, + NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0}, + }; + + const size_t nets_index{rand == nullptr + ? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1) + : static_cast<size_t>(rand->randrange(nets.size()))}; + + const auto& aux = nets[nets_index]; + + CNetAddr addr; + + if (aux.net == Network::NET_INTERNAL) { + if (rand == nullptr) { + addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32)); + } else { + const auto v = rand->randbytes(32); + addr.SetInternal(std::string{v.begin(), v.end()}); } - } else if (network == Network::NET_INTERNAL) { - net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32)); - } else if (network == Network::NET_ONION) { - auto pub_key{fuzzed_data_provider.ConsumeBytes<uint8_t>(ADDR_TORV3_SIZE)}; - pub_key.resize(ADDR_TORV3_SIZE); - const bool ok{net_addr.SetSpecial(OnionToString(pub_key))}; - assert(ok); + return addr; + } + + DataStream s; + + s << static_cast<uint8_t>(aux.bip155); + + std::vector<uint8_t> addr_bytes; + if (rand == nullptr) { + addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len); + addr_bytes.resize(aux.len); + } else { + addr_bytes = rand->randbytes(aux.len); } - return net_addr; + if (aux.net == NET_IPV6 && 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. + } + if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid(). + addr_bytes[0] = CJDNS_PREFIX; + } + s << addr_bytes; + + s >> CAddress::V2_NETWORK(addr); + + return addr; } CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept diff --git a/src/test/fuzz/util/net.h b/src/test/fuzz/util/net.h index 47e4a2fac0..a6c9e23f2e 100644 --- a/src/test/fuzz/util/net.h +++ b/src/test/fuzz/util/net.h @@ -24,7 +24,15 @@ #include <optional> #include <string> -CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept; +/** + * Create a CNetAddr. It may have `addr.IsValid() == false`. + * @param[in,out] fuzzed_data_provider Take data for the address from this, if `rand` is `nullptr`. + * @param[in,out] rand If not nullptr, take data from it instead of from `fuzzed_data_provider`. + * Prefer generating addresses using `fuzzed_data_provider` because it is not uniform. Only use + * `rand` if `fuzzed_data_provider` is exhausted or its data is needed for other things. + * @return a "random" network address. + */ +CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand = nullptr) noexcept; class FuzzedSock : public Sock { |