diff --git a/src/avalanche/test/processor_tests.cpp b/src/avalanche/test/processor_tests.cpp
--- a/src/avalanche/test/processor_tests.cpp
+++ b/src/avalanche/test/processor_tests.cpp
@@ -170,7 +170,7 @@
 
         CAddress addr(ip(GetRand<uint32_t>()), NODE_NONE);
         auto node =
-            new CNode(id++, INVALID_SOCKET, addr,
+            new CNode(id++, /*sock=*/nullptr, addr,
                       /* nKeyedNetGroupIn */ 0,
                       /* nLocalHostNonceIn */ 0,
                       /* nLocalExtraEntropyIn */ 0, CAddress(),
diff --git a/src/net.h b/src/net.h
--- a/src/net.h
+++ b/src/net.h
@@ -466,8 +466,18 @@
     std::unique_ptr<TransportSerializer> m_serializer;
 
     const NetPermissionFlags m_permission_flags{NetPermissionFlags::None};
-    // socket
-    SOCKET hSocket GUARDED_BY(cs_hSocket);
+
+    /**
+     * Socket used for communication with the node.
+     * May not own a Sock object (after `CloseSocketDisconnect()` or during
+     * tests).
+     * `shared_ptr` (instead of `unique_ptr`) is used to avoid premature close
+     * of the underlying file descriptor by one thread while another thread is
+     * poll(2)-ing it for activity.
+     * @see https://github.com/bitcoin/bitcoin/issues/21744 for details.
+     */
+    std::shared_ptr<Sock> m_sock GUARDED_BY(m_sock_mutex);
+
     /** Total size of all vSendMsg entries. */
     size_t nSendSize GUARDED_BY(cs_vSend){0};
     /** Offset inside the first vSendMsg already sent */
@@ -475,7 +485,7 @@
     uint64_t nSendBytes GUARDED_BY(cs_vSend){0};
     std::deque<std::vector<uint8_t>> vSendMsg GUARDED_BY(cs_vSend);
     Mutex cs_vSend;
-    Mutex cs_hSocket;
+    Mutex m_sock_mutex;
     Mutex cs_vRecv;
 
     RecursiveMutex cs_vProcessMsg;
@@ -694,12 +704,11 @@
     std::atomic<std::chrono::microseconds> m_min_ping_time{
         std::chrono::microseconds::max()};
 
-    CNode(NodeId id, SOCKET hSocketIn, const CAddress &addrIn,
+    CNode(NodeId id, std::shared_ptr<Sock> sock, const CAddress &addrIn,
           uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
           uint64_t nLocalExtraEntropyIn, const CAddress &addrBindIn,
           const std::string &addrNameIn, ConnectionType conn_type_in,
           bool inbound_onion, CNodeOptions &&node_opts = {});
-    ~CNode();
     CNode(const CNode &) = delete;
     CNode &operator=(const CNode &) = delete;
 
@@ -752,7 +761,7 @@
 
     void Release() { nRefCount--; }
 
-    void CloseSocketDisconnect() EXCLUSIVE_LOCKS_REQUIRED(!cs_hSocket);
+    void CloseSocketDisconnect() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex);
 
     void copyStats(CNodeStats &stats)
         EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex,
diff --git a/src/net.cpp b/src/net.cpp
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -551,7 +551,7 @@
         addr_bind = GetBindAddress(sock->Get());
     }
     CNode *pnode = new CNode(
-        id, sock->Release(), addrConnect, CalculateKeyedNetGroup(addrConnect),
+        id, std::move(sock), addrConnect, CalculateKeyedNetGroup(addrConnect),
         nonce, extra_entropy, addr_bind, pszDest ? pszDest : "", conn_type,
         /* inbound_onion */ false,
         CNodeOptions{.permission_flags = permission_flags});
@@ -566,10 +566,10 @@
 
 void CNode::CloseSocketDisconnect() {
     fDisconnect = true;
-    LOCK(cs_hSocket);
-    if (hSocket != INVALID_SOCKET) {
+    LOCK(m_sock_mutex);
+    if (m_sock) {
         LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
-        CloseSocket(hSocket);
+        m_sock.reset();
     }
 }
 
@@ -850,13 +850,12 @@
         int nBytes = 0;
 
         {
-            LOCK(node.cs_hSocket);
-            if (node.hSocket == INVALID_SOCKET) {
+            LOCK(node.m_sock_mutex);
+            if (!node.m_sock) {
                 break;
             }
 
-            nBytes = send(
-                node.hSocket,
+            nBytes = node.m_sock->Send(
                 reinterpret_cast<const char *>(data.data()) + node.nSendOffset,
                 data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
         }
@@ -1387,7 +1386,7 @@
         std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) !=
         m_onion_binds.end();
     CNode *pnode = new CNode(
-        id, sock->Release(), addr, CalculateKeyedNetGroup(addr), nonce,
+        id, std::move(sock), addr, CalculateKeyedNetGroup(addr), nonce,
         extra_entropy, addr_bind, "", ConnectionType::INBOUND, inbound_onion,
         CNodeOptions{
             .permission_flags = permission_flags,
@@ -1596,18 +1595,18 @@
             select_send = !pnode->vSendMsg.empty();
         }
 
-        LOCK(pnode->cs_hSocket);
-        if (pnode->hSocket == INVALID_SOCKET) {
+        LOCK(pnode->m_sock_mutex);
+        if (!pnode->m_sock) {
             continue;
         }
 
-        error_set.insert(pnode->hSocket);
+        error_set.insert(pnode->m_sock->Get());
         if (select_send) {
-            send_set.insert(pnode->hSocket);
+            send_set.insert(pnode->m_sock->Get());
             continue;
         }
         if (select_recv) {
-            recv_set.insert(pnode->hSocket);
+            recv_set.insert(pnode->m_sock->Get());
         }
     }
 
@@ -1794,25 +1793,25 @@
         bool sendSet = false;
         bool errorSet = false;
         {
-            LOCK(pnode->cs_hSocket);
-            if (pnode->hSocket == INVALID_SOCKET) {
+            LOCK(pnode->m_sock_mutex);
+            if (!pnode->m_sock) {
                 continue;
             }
-            recvSet = recv_set.count(pnode->hSocket) > 0;
-            sendSet = send_set.count(pnode->hSocket) > 0;
-            errorSet = error_set.count(pnode->hSocket) > 0;
+            recvSet = recv_set.count(pnode->m_sock->Get()) > 0;
+            sendSet = send_set.count(pnode->m_sock->Get()) > 0;
+            errorSet = error_set.count(pnode->m_sock->Get()) > 0;
         }
         if (recvSet || errorSet) {
             // typical socket buffer is 8K-64K
             uint8_t pchBuf[0x10000];
             int32_t nBytes = 0;
             {
-                LOCK(pnode->cs_hSocket);
-                if (pnode->hSocket == INVALID_SOCKET) {
+                LOCK(pnode->m_sock_mutex);
+                if (!pnode->m_sock) {
                     continue;
                 }
-                nBytes = recv(pnode->hSocket, (char *)pchBuf, sizeof(pchBuf),
-                              MSG_DONTWAIT);
+                nBytes =
+                    pnode->m_sock->Recv(pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
             }
             if (nBytes > 0) {
                 bool notify = false;
@@ -3419,12 +3418,12 @@
     return availabilityScore;
 }
 
-CNode::CNode(NodeId idIn, SOCKET hSocketIn, const CAddress &addrIn,
+CNode::CNode(NodeId idIn, std::shared_ptr<Sock> sock, const CAddress &addrIn,
              uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
              uint64_t nLocalExtraEntropyIn, const CAddress &addrBindIn,
              const std::string &addrNameIn, ConnectionType conn_type_in,
              bool inbound_onion, CNodeOptions &&node_opts)
-    : m_permission_flags{node_opts.permission_flags},
+    : m_permission_flags{node_opts.permission_flags}, m_sock{sock},
       m_connected(GetTime<std::chrono::seconds>()), addr(addrIn),
       addrBind(addrBindIn),
       m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn},
@@ -3438,7 +3437,6 @@
     if (inbound_onion) {
         assert(conn_type_in == ConnectionType::INBOUND);
     }
-    hSocket = hSocketIn;
 
     for (const std::string &msg : getAllNetMessageTypes()) {
         mapRecvBytesPerMsgCmd[msg] = 0;
@@ -3459,10 +3457,6 @@
         std::make_unique<V1TransportSerializer>(V1TransportSerializer());
 }
 
-CNode::~CNode() {
-    CloseSocket(hSocket);
-}
-
 bool CConnman::NodeFullyConnected(const CNode *pnode) {
     return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
 }
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -73,7 +73,7 @@
 
     // Mock an outbound peer
     CAddress addr1(ip(0xa0b0c001), NODE_NONE);
-    CNode dummyNode1(id++, INVALID_SOCKET, addr1,
+    CNode dummyNode1(id++, /*sock=*/nullptr, addr1,
                      /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0,
                      /* nLocalExtraEntropyIn */ 0, CAddress(), /* pszDest */ "",
                      ConnectionType::OUTBOUND_FULL_RELAY,
@@ -129,7 +129,7 @@
                                   PeerManager &peerLogic,
                                   CConnmanTest *connman) {
     CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
-    vNodes.emplace_back(new CNode(id++, INVALID_SOCKET, addr,
+    vNodes.emplace_back(new CNode(id++, /*sock=*/nullptr, addr,
                                   /* nKeyedNetGroupIn */ 0,
                                   /* nLocalHostNonceIn */ 0,
                                   /* nLocalExtraEntropyIn */ 0, CAddress(),
@@ -244,7 +244,7 @@
 
     banman->ClearBanned();
     CAddress addr1(ip(0xa0b0c001), NODE_NONE);
-    CNode dummyNode1(id++, INVALID_SOCKET, addr1,
+    CNode dummyNode1(id++, /*sock=*/nullptr, addr1,
                      /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0,
                      /* nLocalExtraEntropyIn */ 0, CAddress(), /* pszDest */ "",
                      ConnectionType::INBOUND, /* inbound_onion */ false);
@@ -260,7 +260,7 @@
     BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001 | 0x0000ff00)));
 
     CAddress addr2(ip(0xa0b0c002), NODE_NONE);
-    CNode dummyNode2(id++, INVALID_SOCKET, addr2,
+    CNode dummyNode2(id++, /*sock=*/nullptr, addr2,
                      /* nKeyedNetGroupIn */ 1, /* nLocalHostNonceIn */ 1,
                      /* nLocalExtraEntropyIn */ 1, CAddress(),
                      /* pszDest */ "", ConnectionType::INBOUND,
@@ -305,7 +305,7 @@
     SetMockTime(nStartTime);
 
     CAddress addr(ip(0xa0b0c001), NODE_NONE);
-    CNode dummyNode(id++, INVALID_SOCKET, addr,
+    CNode dummyNode(id++, /*sock=*/nullptr, addr,
                     /* nKeyedNetGroupIn */ 4, /* nLocalHostNonceIn */ 4,
                     /* nLocalExtraEntropyIn */ 4, CAddress(), /* pszDest */ "",
                     ConnectionType::INBOUND, /* inbound_onion */ false);
diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt
--- a/src/test/fuzz/CMakeLists.txt
+++ b/src/test/fuzz/CMakeLists.txt
@@ -98,6 +98,7 @@
 	tx_in.cpp
 	tx_out.cpp
 	txrequest.cpp
+	util.cpp
 	validation_load_mempool.cpp
 )
 
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -43,9 +43,10 @@
         return;
     }
 
+    const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
     CNode node{
         fuzzed_data_provider.ConsumeIntegral<NodeId>(),
-        INVALID_SOCKET,
+        sock,
         *address,
         fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
         fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -38,6 +38,33 @@
 
 using namespace fuzzer;
 
+class FuzzedSock : public Sock {
+    FuzzedDataProvider &m_fuzzed_data_provider;
+
+public:
+    explicit FuzzedSock(FuzzedDataProvider &fuzzed_data_provider);
+
+    ~FuzzedSock() override {}
+
+    FuzzedSock &operator=(Sock &&other) override;
+
+    SOCKET Get() const override;
+
+    SOCKET Release() override;
+
+    void Reset() override;
+
+    ssize_t Send(const void *data, size_t len, int flags) const override;
+
+    ssize_t Recv(void *buf, size_t len, int flags) const override;
+
+    std::unique_ptr<Sock> Accept(sockaddr *addr,
+                                 socklen_t *addr_len) const override;
+
+    bool Wait(std::chrono::milliseconds timeout, Event requested,
+              Event *occurred = nullptr) const override;
+};
+
 template <typename... Callables>
 void CallOneOf(FuzzedDataProvider &fuzzed_data_provider,
                Callables... callables) {
@@ -324,7 +351,7 @@
     const std::optional<NodeId> &node_id_in = std::nullopt) noexcept {
     const NodeId node_id =
         node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>());
-    const SOCKET socket = INVALID_SOCKET;
+    const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
     const CAddress address = ConsumeAddress(fuzzed_data_provider);
     const uint64_t keyed_net_group =
         fuzzed_data_provider.ConsumeIntegral<uint64_t>();
@@ -339,15 +366,16 @@
         fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
     const bool inbound_onion = fuzzed_data_provider.ConsumeBool();
     if constexpr (ReturnUniquePtr) {
-        return std::make_unique<CNode>(node_id, socket, address,
-                                       keyed_net_group, local_host_nonce,
-                                       local_extra_entropy, addr_bind,
-                                       addr_name, conn_type, inbound_onion);
+        return std::make_unique<CNode>(node_id, sock, address, keyed_net_group,
+                                       local_host_nonce, local_extra_entropy,
+                                       addr_bind, addr_name, conn_type,
+                                       inbound_onion);
     } else {
-        return CNode{node_id,         socket,           address,
-                     keyed_net_group, local_host_nonce, local_extra_entropy,
-                     addr_bind,       addr_name,        conn_type,
-                     inbound_onion};
+        return CNode{node_id,          sock,
+                     address,          keyed_net_group,
+                     local_host_nonce, local_extra_entropy,
+                     addr_bind,        addr_name,
+                     conn_type,        inbound_onion};
     }
 }
 inline std::unique_ptr<CNode>
@@ -566,124 +594,6 @@
     }
 }
 
-class FuzzedSock : public Sock {
-    FuzzedDataProvider &m_fuzzed_data_provider;
-
-public:
-    explicit FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
-        : m_fuzzed_data_provider{fuzzed_data_provider} {}
-
-    ~FuzzedSock() override {}
-
-    FuzzedSock &operator=(Sock &&other) override {
-        assert(false && "Not implemented yet.");
-        return *this;
-    }
-
-    SOCKET Get() const override { assert(false && "Not implemented yet."); }
-
-    SOCKET Release() override { assert(false && "Not implemented yet."); }
-
-    void Reset() override { assert(false && "Not implemented yet."); }
-
-    ssize_t Send(const void *data, size_t len, int flags) const override {
-        constexpr std::array<int, 18> send_errnos{{
-            EACCES,
-            EAGAIN,
-            EALREADY,
-            EBADF,
-            ECONNRESET,
-            EDESTADDRREQ,
-            EFAULT,
-            EINTR,
-            EINVAL,
-            EISCONN,
-            EMSGSIZE,
-            ENOBUFS,
-            ENOMEM,
-            ENOTCONN,
-            ENOTSOCK,
-            EOPNOTSUPP,
-            EPIPE,
-            EWOULDBLOCK,
-        }};
-        if (m_fuzzed_data_provider.ConsumeBool()) {
-            return len;
-        }
-        const ssize_t r =
-            m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
-        if (r == -1) {
-            SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);
-        }
-        return r;
-    }
-
-    ssize_t Recv(void *buf, size_t len, int flags) const override {
-        constexpr std::array<int, 10> recv_errnos{{
-            EAGAIN,
-            EBADF,
-            ECONNREFUSED,
-            EFAULT,
-            EINTR,
-            EINVAL,
-            ENOMEM,
-            ENOTCONN,
-            ENOTSOCK,
-            EWOULDBLOCK,
-        }};
-        assert(buf != nullptr || len == 0);
-        if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
-            const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
-            if (r == -1) {
-                SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
-            }
-            return r;
-        }
-        const std::vector<uint8_t> random_bytes =
-            m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
-                m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
-        if (random_bytes.empty()) {
-            const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
-            if (r == -1) {
-                SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
-            }
-            return r;
-        }
-        std::memcpy(buf, random_bytes.data(), random_bytes.size());
-        if (m_fuzzed_data_provider.ConsumeBool()) {
-            if (len > random_bytes.size()) {
-                std::memset((char *)buf + random_bytes.size(), 0,
-                            len - random_bytes.size());
-            }
-            return len;
-        }
-        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();
-    }
-
-    std::unique_ptr<Sock> Accept(sockaddr *addr,
-                                 socklen_t *addr_len) const override {
-        constexpr std::array<int, 3> accept_errnos{{
-            ECONNABORTED,
-            EINTR,
-            ENOMEM,
-        }};
-        if (m_fuzzed_data_provider.ConsumeBool()) {
-            SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
-            return std::unique_ptr<FuzzedSock>();
-        }
-        return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
-    }
-
-    bool Wait(std::chrono::milliseconds timeout, Event requested,
-              Event *occurred = nullptr) const override {
-        return m_fuzzed_data_provider.ConsumeBool();
-    }
-};
-
 [[nodiscard]] inline FuzzedSock
 ConsumeSock(FuzzedDataProvider &fuzzed_data_provider) {
     return FuzzedSock{fuzzed_data_provider};
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
new file mode 100644
--- /dev/null
+++ b/src/test/fuzz/util.cpp
@@ -0,0 +1,122 @@
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/util.h>
+
+FuzzedSock::FuzzedSock(FuzzedDataProvider &fuzzed_data_provider)
+    : m_fuzzed_data_provider{fuzzed_data_provider} {}
+
+FuzzedSock &FuzzedSock::operator=(Sock &&other) {
+    assert(false && "Not implemented yet.");
+    return *this;
+}
+
+SOCKET FuzzedSock::Get() const {
+    assert(false && "Not implemented yet.");
+}
+
+SOCKET FuzzedSock::Release() {
+    assert(false && "Not implemented yet.");
+}
+
+void FuzzedSock::Reset() {
+    assert(false && "Not implemented yet.");
+}
+
+ssize_t FuzzedSock::Send(const void *data, size_t len, int flags) const {
+    constexpr std::array<int, 18> send_errnos{{
+        EACCES,
+        EAGAIN,
+        EALREADY,
+        EBADF,
+        ECONNRESET,
+        EDESTADDRREQ,
+        EFAULT,
+        EINTR,
+        EINVAL,
+        EISCONN,
+        EMSGSIZE,
+        ENOBUFS,
+        ENOMEM,
+        ENOTCONN,
+        ENOTSOCK,
+        EOPNOTSUPP,
+        EPIPE,
+        EWOULDBLOCK,
+    }};
+    if (m_fuzzed_data_provider.ConsumeBool()) {
+        return len;
+    }
+    const ssize_t r =
+        m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len);
+    if (r == -1) {
+        SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos);
+    }
+    return r;
+}
+
+ssize_t FuzzedSock::Recv(void *buf, size_t len, int flags) const {
+    constexpr std::array<int, 10> recv_errnos{{
+        EAGAIN,
+        EBADF,
+        ECONNREFUSED,
+        EFAULT,
+        EINTR,
+        EINVAL,
+        ENOMEM,
+        ENOTCONN,
+        ENOTSOCK,
+        EWOULDBLOCK,
+    }};
+    assert(buf != nullptr || len == 0);
+    if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) {
+        const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+        if (r == -1) {
+            SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+        }
+        return r;
+    }
+    const std::vector<uint8_t> random_bytes =
+        m_fuzzed_data_provider.ConsumeBytes<uint8_t>(
+            m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len));
+    if (random_bytes.empty()) {
+        const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
+        if (r == -1) {
+            SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos);
+        }
+        return r;
+    }
+    std::memcpy(buf, random_bytes.data(), random_bytes.size());
+    if (m_fuzzed_data_provider.ConsumeBool()) {
+        if (len > random_bytes.size()) {
+            std::memset((char *)buf + random_bytes.size(), 0,
+                        len - random_bytes.size());
+        }
+        return len;
+    }
+    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();
+}
+
+std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr *addr,
+                                         socklen_t *addr_len) const {
+    constexpr std::array<int, 3> accept_errnos{{
+        ECONNABORTED,
+        EINTR,
+        ENOMEM,
+    }};
+    if (m_fuzzed_data_provider.ConsumeBool()) {
+        SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos);
+        return std::unique_ptr<FuzzedSock>();
+    }
+    return std::make_unique<FuzzedSock>(m_fuzzed_data_provider);
+}
+
+bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested,
+                      Event *occurred) const {
+    return m_fuzzed_data_provider.ConsumeBool();
+}
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
@@ -72,7 +72,7 @@
     }
 
     void AddNode(const CAddress &addr, ConnectionType type) {
-        CNode *pnode = new CNode(nodeid++, INVALID_SOCKET, addr,
+        CNode *pnode = new CNode(nodeid++, /*sock=*/nullptr, addr,
                                  CalculateKeyedNetGroup(addr),
                                  /* nLocalHostNonceIn */ 0,
                                  /* nLocalExtraEntropyIn */ 0, addr,
@@ -269,7 +269,6 @@
 }
 
 BOOST_AUTO_TEST_CASE(cnode_simple_test) {
-    SOCKET hSocket = INVALID_SOCKET;
     NodeId id = 0;
 
     in_addr ipv4Addr;
@@ -279,7 +278,7 @@
     std::string pszDest;
 
     auto pnode1 =
-        std::make_unique<CNode>(id++, hSocket, addr,
+        std::make_unique<CNode>(id++, /*sock=*/nullptr, addr,
                                 /* nKeyedNetGroupIn = */ 0,
                                 /* nLocalHostNonceIn = */ 0,
                                 /* nLocalExtraEntropyIn */ 0, CAddress(),
@@ -294,9 +293,9 @@
     BOOST_CHECK(pnode1->m_inbound_onion == false);
     BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
 
-    auto pnode2 =
-        std::make_unique<CNode>(id++, hSocket, addr, 1, 1, 1, CAddress(),
-                                pszDest, ConnectionType::INBOUND, false);
+    auto pnode2 = std::make_unique<CNode>(id++, /*sock=*/nullptr, addr, 1, 1, 1,
+                                          CAddress(), pszDest,
+                                          ConnectionType::INBOUND, false);
     BOOST_CHECK(pnode2->IsFullOutboundConn() == false);
     BOOST_CHECK(pnode2->IsManualConn() == false);
     BOOST_CHECK(pnode2->IsBlockOnlyConn() == false);
@@ -307,7 +306,7 @@
     BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
 
     auto pnode3 = std::make_unique<CNode>(
-        id++, hSocket, addr, 0, 0, 0, CAddress(), pszDest,
+        id++, /*sock=*/nullptr, addr, 0, 0, 0, CAddress(), pszDest,
         ConnectionType::OUTBOUND_FULL_RELAY, false);
     BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
     BOOST_CHECK(pnode3->IsManualConn() == false);
@@ -318,9 +317,9 @@
     BOOST_CHECK(pnode3->m_inbound_onion == false);
     BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
 
-    auto pnode4 =
-        std::make_unique<CNode>(id++, hSocket, addr, 1, 1, 1, CAddress(),
-                                pszDest, ConnectionType::INBOUND, true);
+    auto pnode4 = std::make_unique<CNode>(id++, /*sock=*/nullptr, addr, 1, 1, 1,
+                                          CAddress(), pszDest,
+                                          ConnectionType::INBOUND, true);
     BOOST_CHECK(pnode4->IsFullOutboundConn() == false);
     BOOST_CHECK(pnode4->IsManualConn() == false);
     BOOST_CHECK(pnode4->IsBlockOnlyConn() == false);
@@ -908,7 +907,7 @@
     ipv4AddrPeer.s_addr = 0xa0b0c001;
     CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
     std::unique_ptr<CNode> pnode = std::make_unique<CNode>(
-        0, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0,
+        0, /*sock=*/nullptr, addr, /* nKeyedNetGroupIn */ 0,
         /* nLocalHostNonceIn */ 0, /* nLocalExtraEntropyIn */ 0, CAddress{},
         /* pszDest */ std::string{}, ConnectionType::OUTBOUND_FULL_RELAY,
         /* inbound_onion = */ false);
@@ -964,7 +963,7 @@
     peer_out_in_addr.s_addr = htonl(0x01020304);
     CNode peer_out{
         /*id=*/0,
-        /*hSocketIn=*/INVALID_SOCKET,
+        /*sock=*/nullptr,
         /*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK},
         /*nKeyedNetGroupIn=*/0,
         /*nLocalHostNonceIn=*/0,
@@ -988,7 +987,7 @@
     peer_in_in_addr.s_addr = htonl(0x05060708);
     CNode peer_in{
         /*id=*/0,
-        /*hSocketIn=*/INVALID_SOCKET,
+        /*sock=*/nullptr,
         /*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK},
         /*nKeyedNetGroupIn=*/0,
         /*nLocalHostNonceIn=*/0,
@@ -1023,7 +1022,7 @@
         ipv4Addr.s_addr = 0xa0b0c001;
         CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
         std::unique_ptr<CNode> pnode = std::make_unique<CNode>(
-            0, INVALID_SOCKET, addr, 0, 0, 0, CAddress(), std::string{},
+            0, /*sock=*/nullptr, addr, 0, 0, 0, CAddress(), std::string{},
             ConnectionType::OUTBOUND_FULL_RELAY, false);
         pnode->m_avalanche_enabled = true;
 
@@ -1280,7 +1279,7 @@
     in_addr peer_in_addr;
     peer_in_addr.s_addr = htonl(0x01020304);
     CNode peer{/*id=*/0,
-               /*hSocketIn=*/INVALID_SOCKET,
+               /*sock=*/nullptr,
                /*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK},
                /*nKeyedNetGroupIn=*/0,
                /*nLocalHostNonceIn=*/0,