upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.h
AgeCommit message (Collapse)Author
2026-08-19net: stop serving the 2009 marketplace to anonymous peersbitflash-maintainer
Four inherited handlers took attacker-controlled input and wrote to disk with nothing authorising it. None of them had a caller left anywhere in the tree, so all four were reachable only from the outside. checkorder called GenerateNewKey() -- AddKey(), a wallet.dat write -- for any peer that asked, and handed back the pubkey. Its comment claims the cache keeps one key per ip, and on a 2009 network of routable addresses it did. Not here: inbound peers arrive through a rendezvous tunnel and are tagged by BtfMarkerAddr() over three random bytes, so addr.ip is fresh every connection and the cache never hits. Reconnect in a loop and the node mints a key per connection, none of them in any backup taken beforehand, which for a pre-BIP32 wallet is how coins go missing. The map holding them was static and never trimmed. submitorder AddToWallet()'d a CWalletTx from any peer that sent one. It had to be a valid transaction; it did not have to be ours. review checked a signature the sender made with its own key, which proves possession and authorises nothing, then appended to reviews.dat by reading the whole vector, pushing one entry and writing it all back -- quadratic disk on an unbounded map<string,string> off the socket -- then walked a link graph the same peer supplied and relayed the message to every other node. reply dispatched into CRequestTracker. Nothing ever called PushRequest, so the table was permanently empty and the handler was a parser and nothing else. Removed with the subsystem behind them: market.cpp, CProduct, CReview, CUser, CReviewDB, the advert publish templates and the subscribe channel machinery, none of which had an inbound handler either. MSG_REVIEW, MSG_PRODUCT and MSG_TABLE stay in the inv enum, unserved: CInv puts type on the wire as an integer and MSG_TX and MSG_BLOCK are shared with every other node. Unknown commands are already ignored for extensibility, so peers still running these lose nothing but an answer they never asked for. Verified by a clean build of bitflash-node. (cherry picked from commit ad9c393866c007a115f32d70a9017ce91066a7d1)
2026-08-19net: do not consume a header until the body is there, and cap what one can claimbitflash-maintainer
Upstream #109's message-stall rework, hand-merged so it keeps the progress timing this tree already had. The old path consumed the header, found the payload short, inserted the header back at the front of vRecv, then Sleep(100) inside the shared message thread. A peer that announces a large payload and drips bytes made every pass pay an O(n) insert and a 100 ms stall -- one peer slowing the thread that serves all of them. Now the header is read from a copy and only skipped once the whole body has arrived, so there is nothing to put back and nothing to sleep for. Kept OURS, not upstream's, on the timeout: upstream restarts its clock only when the (size, command) pair changes, which drops a peer sending one big message slowly but honestly. This times the STALL -- the clock restarts on any progress -- which is the distinction that matters on a slow link. Also from #109: a header could announce 256 MB while serialize.h refuses anything over MAX_SIZE (32 MB), so the check admitted an allocation the parser would reject anyway and burned a peer slot for two minutes doing it. MAX_PROTOCOL_MESSAGE_SIZE ties the two together. 8x less a peer can make us hold, and this node takes public Stratum. And #103's other half: ~CNode closed its socket with a raw closesocket(), invisible to the accounting, and left hSocket set afterwards -- which is how a descriptor number that now belongs to somebody else gets closed a second time. (cherry picked from commit 2f25e2e07985e9bc732cadfbb3c9ac233895a814)
2026-08-19net: time the stall, not the wait, before dropping an unreadable peerbitflash-maintainer
Found auditing the previous commit for the push. Timing from the first rewind would drop a peer whose message is large and merely slow, which would be a fault of our own making rather than one we fixed. Restart the clock whenever the buffer has grown by even one byte since the last look. A transfer still making progress is never dropped however long it takes; only one that has stopped growing while the node goes on expecting more is, which is the actual failure. (cherry picked from commit 5dddb26bae02013ce87719b11953aadf0bfa2594)
2026-08-19net: give up waiting for a message body that is never going to arrivebitflash-maintainer
THIS IS THE WEDGE, and the note asking for this fix has been in the file since Bitcoin 0.1: 'need a mechanism to give up waiting for overlong message size error'. ProcessMessages reads a header, finds the body has not all arrived, pushes the header back onto the front of vRecv and breaks. Correct for a message still in flight. For one that never completes it is permanent: every later pass re-reads the same header and breaks in the same place, so that peer is never parsed again for the life of the process -- no blocks, no inv, not even its version message. Nothing rescues it: - a header may claim up to 256 MB (0x10000000) and still pass CMessageHeader::IsValid(), so a garbage or truncated header is accepted and then waited on forever; - nLastRecv is refreshed by any byte that arrives (net.cpp), whether or not it parses, so the inactivity timeout that drops a silent peer never fires on a peer that is merely unreadable; - the socket stays ESTABLISHED and select() keeps offering it, so nothing at the socket layer notices either. It also explains the signature that made no sense. A peer stuck before its version message is parsed keeps nStartingHeight == -1, so a node with a full vNodes still reports GetPeerMedianHeight() == -1 -- which is exactly what was observed, and exactly what disabled the pool's behind-the-network gate and let it fork. Evidence, from two wedges captured on the pool by the watchdog: MESSAGE-BREAK 2 ran 2014 times in the deaf window against 607 in the healthy window before it, while blocks received went to zero and the node kept processing miner traffic normally throughout. Now: a peer that announces a body and does not deliver it within two minutes is dropped, and says so in the log unconditionally. Two minutes is far beyond any legitimate header-to-body gap and well inside BTF_RECV_TIMEOUT_SECS. (cherry picked from commit ca1e99288e03ac7beb2b97cf615a3255b4635d95)
2026-08-19pool: refuse jobs when no peer has reported a height for 20 minutesbitflash-maintainer
The peer-height gate replaced a tip-age check that was wrong in both directions. It is a strict improvement and it is still blind in the one case that matters most. When the node goes deaf -- peers still in vNodes, nothing arriving -- no peer announces anything, GetPeerMedianHeight() returns -1, and the fallback mines our best chain. That fallback is right for a node that has not been told yet and wrong for a node that has stopped being able to hear, and a height nobody sent cannot tell those apart. A wedged node is exactly a node with no peer height information, so the gate was silent for the whole of heights 3966-4085: 120 blocks, 5890.50 BTF voided. Time can tell them apart. GetPeerHeightAgeSecs() measures how long since any peer reported a height, counting from first use rather than the epoch so a starting node does not refuse jobs before its first handshake. Past 20 minutes the pool stops issuing jobs and says so unconditionally in the log. /poolmineblind overrides it: without an escape hatch a genuinely isolated pool that is 90% of the hashrate could never restart its own chain, which is the deadlock the tip-age check used to cause. Also stop nStartingHeight from going stale. It was a snapshot taken once during the version handshake and never touched again, so on a long-lived connection the median is built from heights the peers had hours ago, and the behind-the-network check drifts toward 'everyone is behind us' and quietly stops firing. A peer that hands us a block is demonstrably at least at that block's height. (cherry picked from commit 0800c18faf703b4acde1b131d0b742d37a86d92b)
2026-08-04public commitbitflash-coin