aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz/util/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz/util/net.cpp')
-rw-r--r--src/test/fuzz/util/net.cpp105
1 files changed, 72 insertions, 33 deletions
diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp
index eb0f14ede0..5e7aae670e 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
@@ -163,21 +193,20 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()};
if (m_peek_data.has_value()) {
// `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`.
- random_bytes.assign({m_peek_data.value()});
+ random_bytes = m_peek_data.value();
if ((flags & MSG_PEEK) == 0) {
m_peek_data.reset();
}
pad_to_len_bytes = false;
} else if ((flags & MSG_PEEK) != 0) {
// New call with `MSG_PEEK`.
- random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1);
+ random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len);
if (!random_bytes.empty()) {
- m_peek_data = random_bytes[0];
+ m_peek_data = random_bytes;
pad_to_len_bytes = false;
}
} else {
- random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
- m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+ random_bytes = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len);
}
if (random_bytes.empty()) {
const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@@ -186,7 +215,11 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
}
return r;
}
- std::memcpy(buf, random_bytes.data(), random_bytes.size());
+ // `random_bytes` might exceed the size of `buf` if e.g. Recv is called with
+ // len=N and MSG_PEEK first and afterwards called with len=M (M < N) and
+ // without MSG_PEEK.
+ size_t recv_len{std::min(random_bytes.size(), len)};
+ std::memcpy(buf, random_bytes.data(), recv_len);
if (pad_to_len_bytes) {
if (len > random_bytes.size()) {
std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size());
@@ -196,7 +229,7 @@ ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const
if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds{2});
}
- return random_bytes.size();
+ return recv_len;
}
int FuzzedSock::Connect(const sockaddr*, socklen_t) const
@@ -350,7 +383,10 @@ bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event*
return false;
}
if (occurred != nullptr) {
- *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
+ // We simulate the requested event as occured when ConsumeBool()
+ // returns false. This avoids simulating endless waiting if the
+ // FuzzedDataProvider runs out of data.
+ *occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : requested;
}
return true;
}
@@ -359,7 +395,10 @@ bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& even
{
for (auto& [sock, events] : events_per_sock) {
(void)sock;
- events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0;
+ // We simulate the requested event as occured when ConsumeBool()
+ // returns false. This avoids simulating endless waiting if the
+ // FuzzedDataProvider runs out of data.
+ events.occurred = m_fuzzed_data_provider.ConsumeBool() ? 0 : events.requested;
}
return true;
}