upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/net.h
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 18:17:06 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 22:48:27 +0000
commit11766bec0ea465da263f78a6f473ca792da59280 (patch)
treef07c7eecabdf6a0b5f2299447dcf957472e7ef58 /src/net.h
parent88d30ade28d6836e64d0157da57896bdb320e8a2 (diff)
net: stop serving the 2009 marketplace to anonymous peers
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)
Diffstat (limited to 'src/net.h')
-rw-r--r--src/net.h138
1 files changed, 17 insertions, 121 deletions
diff --git a/src/net.h b/src/net.h
index 0317676..8b0245a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -5,7 +5,6 @@
5class CMessageHeader; 5class CMessageHeader;
6class CAddress; 6class CAddress;
7class CInv; 7class CInv;
8class CRequestTracker;
9class CNode; 8class CNode;
10// Defined in main.h, which is included after this file. Only ever used here as 9// Defined in main.h, which is included after this file. Only ever used here as
11// a pointer, so the forward declaration is enough. 10// a pointer, so the forward declaration is enough.
@@ -14,7 +13,6 @@ class CBlockIndex;
14 13
15 14
16static const unsigned short DEFAULT_PORT = htons(8433); 15static const unsigned short DEFAULT_PORT = htons(8433);
17static const unsigned int PUBLISH_HOPS = 5;
18enum 16enum
19{ 17{
20 NODE_NETWORK = (1 << 0), 18 NODE_NETWORK = (1 << 0),
@@ -214,8 +212,6 @@ void BtfChurnNoteHandshakeTimeout(const string& strBtfAddr, const string& strMee
214void BtfPexCollect(std::vector<std::string>& vDescOut); 212void BtfPexCollect(std::vector<std::string>& vDescOut);
215// Verify descriptors a peer sent and remember the good ones. Returns how many. 213// Verify descriptors a peer sent and remember the good ones. Returns how many.
216int BtfPexAccept(const std::vector<std::string>& vDesc); 214int BtfPexAccept(const std::vector<std::string>& vDesc);
217void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
218bool AnySubscribed(unsigned int nChannel);
219void ThreadBitcoinMiner(void* parg); 215void ThreadBitcoinMiner(void* parg);
220// Starts MinerThreadCount() miners; returns how many came up. 216// Starts MinerThreadCount() miners; returns how many came up.
221int StartMinerThreads(); 217int StartMinerThreads();
@@ -489,13 +485,19 @@ public:
489 485
490 486
491 487
488// MSG_REVIEW, MSG_PRODUCT and MSG_TABLE no longer have a handler, a producer
489// or a store -- the marketplace they belonged to is gone. They stay in the
490// enum, and their names stay in ppszTypeName below, because CInv serialises
491// `type` as a plain integer: dropping them would renumber nothing today but
492// would make it tempting to renumber later, and MSG_TX and MSG_BLOCK are wire
493// values shared with every other node. Reserved, never emitted, never served.
492enum 494enum
493{ 495{
494 MSG_TX = 1, 496 MSG_TX = 1,
495 MSG_BLOCK, 497 MSG_BLOCK,
496 MSG_REVIEW, 498 MSG_REVIEW, // reserved, dead
497 MSG_PRODUCT, 499 MSG_PRODUCT, // reserved, dead
498 MSG_TABLE, 500 MSG_TABLE, // reserved, dead
499}; 501};
500 502
501static const char* ppszTypeName[] = 503static const char* ppszTypeName[] =
@@ -582,23 +584,9 @@ public:
582 584
583 585
584 586
585class CRequestTracker 587// CRequestTracker and the PushRequest/"reply" round trip lived here. Nothing
586{ 588// in this tree ever called PushRequest, so the table was always empty and the
587public: 589// "reply" handler was pure inbound parser. Both removed.
588 void (*fn)(void*, CDataStream&);
589 void* param1;
590
591 explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
592 {
593 fn = fnIn;
594 param1 = param1In;
595 }
596
597 bool IsNull()
598 {
599 return fn == NULL;
600 }
601};
602 590
603 591
604 592
@@ -644,9 +632,6 @@ protected:
644public: 632public:
645 int64 nReleaseTime; 633 int64 nReleaseTime;
646 int64 nDisconnectSince; 634 int64 nDisconnectSince;
647 map<uint256, CRequestTracker> mapRequests;
648 CCriticalSection cs_mapRequests;
649
650 // inventory based relay 635 // inventory based relay
651 set<CInv> setInventoryKnown; 636 set<CInv> setInventoryKnown;
652 set<CInv> setInventoryKnown2; 637 set<CInv> setInventoryKnown2;
@@ -654,9 +639,6 @@ public:
654 CCriticalSection cs_inventory; 639 CCriticalSection cs_inventory;
655 multimap<int64, CInv> mapAskFor; 640 multimap<int64, CInv> mapAskFor;
656 641
657 // publish and subscription
658 vector<char> vfSubscribe;
659
660 // Last "btfpeers" we accepted from this node, to rate-limit the exchange. 642 // Last "btfpeers" we accepted from this node, to rate-limit the exchange.
661 int64 nLastPexRecv; 643 int64 nLastPexRecv;
662 644
@@ -723,7 +705,6 @@ public:
723 strBtfAddr.clear(); 705 strBtfAddr.clear();
724 strBtfMeeting.clear(); 706 strBtfMeeting.clear();
725 nStartingHeight = -1; 707 nStartingHeight = -1;
726 vfSubscribe.assign(256, false);
727 708
728 // Push a version message 709 // Push a version message
729 /// when NTP implemented, change to just nTime = GetAdjustedTime() 710 /// when NTP implemented, change to just nTime = GetAdjustedTime()
@@ -1002,49 +983,6 @@ public:
1002 } 983 }
1003 984
1004 985
1005 void PushRequest(const char* pszCommand,
1006 void (*fn)(void*, CDataStream&), void* param1)
1007 {
1008 uint256 hashReply;
1009 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1010
1011 CRITICAL_BLOCK(cs_mapRequests)
1012 mapRequests[hashReply] = CRequestTracker(fn, param1);
1013
1014 PushMessage(pszCommand, hashReply);
1015 }
1016
1017 template<typename T1>
1018 void PushRequest(const char* pszCommand, const T1& a1,
1019 void (*fn)(void*, CDataStream&), void* param1)
1020 {
1021 uint256 hashReply;
1022 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1023
1024 CRITICAL_BLOCK(cs_mapRequests)
1025 mapRequests[hashReply] = CRequestTracker(fn, param1);
1026
1027 PushMessage(pszCommand, hashReply, a1);
1028 }
1029
1030 template<typename T1, typename T2>
1031 void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
1032 void (*fn)(void*, CDataStream&), void* param1)
1033 {
1034 uint256 hashReply;
1035 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1036
1037 CRITICAL_BLOCK(cs_mapRequests)
1038 mapRequests[hashReply] = CRequestTracker(fn, param1);
1039
1040 PushMessage(pszCommand, hashReply, a1, a2);
1041 }
1042
1043
1044
1045 bool IsSubscribed(unsigned int nChannel);
1046 void Subscribe(unsigned int nChannel, unsigned int nHops=0);
1047 void CancelSubscribe(unsigned int nChannel);
1048 void Disconnect(); 986 void Disconnect();
1049}; 987};
1050 988
@@ -1101,50 +1039,8 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
1101 1039
1102 1040
1103 1041
1104// 1042// The publish/subscribe advert templates that used to close this file
1105// Templates for the publish and subscription system. 1043// (AdvertStartPublish / AdvertStopPublish / AdvertRemoveSource) are gone along
1106// The object being published as T& obj needs to have: 1044// with the marketplace objects they carried. Nothing ever handled an inbound
1107// a set<unsigned int> setSources member 1045// "publish" or "pub-cancel", so the machinery only ever pushed; what it pushed
1108// specializations of AdvertInsert and AdvertErase 1046// was CProduct, which no longer exists.
1109// Currently implemented for CTable and CProduct.
1110//
1111
1112template<typename T>
1113void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1114{
1115 // Add to sources
1116 obj.setSources.insert(pfrom->addr.ip);
1117
1118 if (!AdvertInsert(obj))
1119 return;
1120
1121 // Relay
1122 CRITICAL_BLOCK(cs_vNodes)
1123 foreach(CNode* pnode, vNodes)
1124 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1125 pnode->PushMessage("publish", nChannel, nHops, obj);
1126}
1127
1128template<typename T>
1129void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1130{
1131 uint256 hash = obj.GetHash();
1132
1133 CRITICAL_BLOCK(cs_vNodes)
1134 foreach(CNode* pnode, vNodes)
1135 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1136 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
1137
1138 AdvertErase(obj);
1139}
1140
1141template<typename T>
1142void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1143{
1144 // Remove a source
1145 obj.setSources.erase(pfrom->addr.ip);
1146
1147 // If no longer supported by any sources, cancel it
1148 if (obj.setSources.empty())
1149 AdvertStopPublish(pfrom, nChannel, nHops, obj);
1150}