Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <test/fuzz/util/net.h>7#include <compat/compat.h>8#include <netaddress.h>9#include <node/protocol_version.h>10#include <protocol.h>11#include <test/fuzz/FuzzedDataProvider.h>12#include <test/fuzz/util.h>13#include <test/util/net.h>14#include <util/sock.h>15#include <util/time.h>17#include <array>18#include <cassert>19#include <cerrno>20#include <cstdint>21#include <cstdlib>22#include <cstring>23#include <ranges>24#include <thread>25#include <vector>27class CNode;29CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand) noexcept30{31struct NetAux {32Network net;33CNetAddr::BIP155Network bip155;34size_t len;35};37static constexpr std::array<NetAux, 6> nets{38NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE},39NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE},40NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE},41NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE},42NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE},43NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0},44};46const size_t nets_index{rand == nullptr47? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1)48: static_cast<size_t>(rand->randrange(nets.size()))};50const auto& aux = nets[nets_index];52CNetAddr addr;54if (aux.net == Network::NET_INTERNAL) {55if (rand == nullptr) {56addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));57} else {58const auto v = rand->randbytes(32);59addr.SetInternal(std::string{v.begin(), v.end()});60}61return addr;62}64DataStream s;66s << static_cast<uint8_t>(aux.bip155);68std::vector<uint8_t> addr_bytes;69if (rand == nullptr) {70addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len);71addr_bytes.resize(aux.len);72} else {73addr_bytes = rand->randbytes(aux.len);74}75if (aux.net == NET_IPV6 && addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS.76addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do.77}78if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid().79addr_bytes[0] = CJDNS_PREFIX;80}81s << addr_bytes;83s >> CAddress::V2_NETWORK(addr);85return addr;86}88CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept89{90return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};91}93template <typename P>94P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept95{96constexpr std::array ADDR_ENCODINGS{97CNetAddr::Encoding::V1,98CNetAddr::Encoding::V2,99};100constexpr std::array ADDR_FORMATS{101CAddress::Format::Disk,102CAddress::Format::Network,103};104if constexpr (std::is_same_v<P, CNetAddr::SerParams>) {105return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)};106}107if constexpr (std::is_same_v<P, CAddress::SerParams>) {108return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)};109}110}111template CNetAddr::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept;112template CAddress::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept;114FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider, FakeSteadyClock& clock)115: Sock{fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET)},116m_fuzzed_data_provider{fuzzed_data_provider},117m_selectable{fuzzed_data_provider.ConsumeBool()},118m_clock{clock}119{120}122FuzzedSock::~FuzzedSock()123{124// Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call125// close(m_socket) if m_socket is not INVALID_SOCKET.126// Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which127// theoretically may concide with a real opened file descriptor).128m_socket = INVALID_SOCKET;129}131FuzzedSock& FuzzedSock::operator=(Sock&& other)132{133assert(false && "Move of Sock into FuzzedSock not allowed.");134return *this;135}137ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const138{139constexpr std::array send_errnos{140EACCES,141EAGAIN,142EALREADY,143EBADF,144ECONNRESET,145EDESTADDRREQ,146EFAULT,147EINTR,148EINVAL,149EISCONN,150EMSGSIZE,151ENOBUFS,152ENOMEM,153ENOTCONN,154ENOTSOCK,155EOPNOTSUPP,156EPIPE,157EWOULDBLOCK,158};159if (m_fuzzed_data_provider.ConsumeBool()) {160return len;161}162const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);163if (r == -1) {164SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);165}166return r;167}169ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const170{171// Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted172// SetFuzzedErrNo() will always return the first element and we want to avoid Recv()173// returning -1 and setting errno to EAGAIN repeatedly.174constexpr std::array recv_errnos{175ECONNREFUSED,176EAGAIN,177EBADF,178EFAULT,179EINTR,180EINVAL,181ENOMEM,182ENOTCONN,183ENOTSOCK,184EWOULDBLOCK,185};186assert(buf != nullptr || len == 0);188// Do the latency before any of the "return" statements.189if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) {190std::this_thread::sleep_for(std::chrono::milliseconds{2});191}193if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {194const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;195if (r == -1) {196SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);197}198return r;199}201size_t copied_so_far{0};203if (!m_peek_data.empty()) {204// `MSG_PEEK` was used in the preceding `Recv()` call, copy the first bytes from `m_peek_data`.205const size_t copy_len{std::min(len, m_peek_data.size())};206std::memcpy(buf, m_peek_data.data(), copy_len);207copied_so_far += copy_len;208if ((flags & MSG_PEEK) == 0) {209m_peek_data.erase(m_peek_data.begin(), m_peek_data.begin() + copy_len);210}211}213if (copied_so_far == len) {214return copied_so_far;215}217auto new_data = ConsumeRandomLengthByteVector(m_fuzzed_data_provider, len - copied_so_far);218if (new_data.empty()) return copied_so_far;220std::memcpy(reinterpret_cast<uint8_t*>(buf) + copied_so_far, new_data.data(), new_data.size());221copied_so_far += new_data.size();223if ((flags & MSG_PEEK) != 0) {224m_peek_data.insert(m_peek_data.end(), new_data.begin(), new_data.end());225}227if (copied_so_far == len || m_fuzzed_data_provider.ConsumeBool()) {228return copied_so_far;229}231// Pad to len bytes.232std::memset(reinterpret_cast<uint8_t*>(buf) + copied_so_far, 0x0, len - copied_so_far);234return len;235}237int FuzzedSock::Connect(const sockaddr*, socklen_t) const238{239// Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted240// SetFuzzedErrNo() will always return the first element and we want to avoid Connect()241// returning -1 and setting errno to EAGAIN repeatedly.242constexpr std::array connect_errnos{243ECONNREFUSED,244EAGAIN,245ECONNRESET,246EHOSTUNREACH,247EINPROGRESS,248EINTR,249ENETUNREACH,250ETIMEDOUT,
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.