diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 115 |
1 files changed, 37 insertions, 78 deletions
diff --git a/src/main.cpp b/src/main.cpp index 62068d2..efff96c 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -2782,9 +2782,10 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv) | |||
| 2782 | { | 2782 | { |
| 2783 | case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash); | 2783 | case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash); |
| 2784 | case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); | 2784 | case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); |
| 2785 | case MSG_REVIEW: return true; | ||
| 2786 | case MSG_PRODUCT: return mapProducts.count(inv.hash); | ||
| 2787 | } | 2785 | } |
| 2786 | // MSG_REVIEW / MSG_PRODUCT / MSG_TABLE are the 2009 marketplace inventory | ||
| 2787 | // types. Nothing announces or serves them any more (see ProcessMessage), | ||
| 2788 | // so they fall through to the default and are never requested. | ||
| 2788 | // Don't know what it is, just say we already got one | 2789 | // Don't know what it is, just say we already got one |
| 2789 | return true; | 2790 | return true; |
| 2790 | } | 2791 | } |
| @@ -2942,7 +2943,6 @@ bool ProcessMessages(CNode* pfrom) | |||
| 2942 | 2943 | ||
| 2943 | bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | 2944 | bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) |
| 2944 | { | 2945 | { |
| 2945 | static map<unsigned int, vector<unsigned char> > mapReuseKey; | ||
| 2946 | if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), (int)vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); } | 2946 | if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), (int)vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); } |
| 2947 | if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) | 2947 | if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) |
| 2948 | { | 2948 | { |
| @@ -3181,22 +3181,18 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 3181 | } | 3181 | } |
| 3182 | 3182 | ||
| 3183 | 3183 | ||
| 3184 | else if (strCommand == "review") | 3184 | // "review" used to be handled here. It took a CReview off the wire from an |
| 3185 | { | 3185 | // unauthenticated peer, checked a signature the sender had made with a key |
| 3186 | CDataStream vMsg(vRecv); | 3186 | // of its own choosing -- which proves possession of that key and authorises |
| 3187 | CReview review; | 3187 | // nothing -- and then appended the message to reviews.dat by reading the |
| 3188 | vRecv >> review; | 3188 | // whole vector for the target hash, pushing one entry, and writing all of |
| 3189 | 3189 | // it back. That is quadratic disk for a stream an attacker controls, on a | |
| 3190 | CInv inv(MSG_REVIEW, review.GetHash()); | 3190 | // record whose mapValue is an unbounded map<string,string> read straight |
| 3191 | pfrom->AddInventoryKnown(inv); | 3191 | // from the socket, followed by AddAtomsAndPropagate walking a link graph |
| 3192 | 3192 | // the same peer supplied, and finally RelayMessage forwarding it to every | |
| 3193 | if (review.AcceptReview()) | 3193 | // other node. Unbounded remote disk growth with network amplification and |
| 3194 | { | 3194 | // no authorisation anywhere in the path. The marketplace it belonged to has |
| 3195 | // Relay the original message as-is in case it's a higher version than we know how to parse | 3195 | // not existed since 2009; the handler is gone rather than bounded. |
| 3196 | RelayMessage(inv, vMsg); | ||
| 3197 | mapAlreadyAskedFor.erase(inv); | ||
| 3198 | } | ||
| 3199 | } | ||
| 3200 | 3196 | ||
| 3201 | 3197 | ||
| 3202 | else if (strCommand == "block") | 3198 | else if (strCommand == "block") |
| @@ -3229,65 +3225,28 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 3229 | } | 3225 | } |
| 3230 | 3226 | ||
| 3231 | 3227 | ||
| 3232 | else if (strCommand == "checkorder") | 3228 | // "checkorder", "submitorder" and "reply" -- the 2009 buy-from-a-merchant |
| 3233 | { | 3229 | // exchange -- used to be handled here. All three are gone. |
| 3234 | uint256 hashReply; | 3230 | // |
| 3235 | CWalletTx order; | 3231 | // "checkorder" called GenerateNewKey() for any peer that asked, which is |
| 3236 | vRecv >> hashReply >> order; | 3232 | // AddKey() and a wallet.dat write, and handed the pubkey back. The comment |
| 3237 | 3233 | // said "keep giving the same key to the same ip until they use it", and on | |
| 3238 | /// we have a chance to check the order here | 3234 | // a 2009 network of routable IPs that held. It does not hold here: every |
| 3239 | 3235 | // inbound peer arrives through a rendezvous tunnel and is tagged with | |
| 3240 | // Keep giving the same key to the same ip until they use it | 3236 | // BtfMarkerAddr() over three random bytes (net.cpp), so addr.ip is freshly |
| 3241 | if (!mapReuseKey.count(pfrom->addr.ip)) | 3237 | // random per connection and the cache never hits. Reconnect in a loop and |
| 3242 | mapReuseKey[pfrom->addr.ip] = GenerateNewKey(); | 3238 | // the node mints a key per connection -- unbounded wallet growth, unbounded |
| 3243 | 3239 | // growth of the static map that held them, and every one of those keys | |
| 3244 | // Send back approval of order and pubkey to use | 3240 | // missing from every backup taken beforehand, which for this pre-BIP32 |
| 3245 | CScript scriptPubKey; | 3241 | // wallet is how coins are lost. |
| 3246 | scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG; | 3242 | // |
| 3247 | pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); | 3243 | // "submitorder" took a CWalletTx from an unauthenticated peer and, if it |
| 3248 | } | 3244 | // was merely a valid transaction, AddToWallet()'d it. Valid is not the same |
| 3249 | 3245 | // as ours: any peer could write chosen transactions into wallet.dat. | |
| 3250 | 3246 | // | |
| 3251 | else if (strCommand == "submitorder") | 3247 | // "reply" dispatched to a CRequestTracker callback. Nothing in this tree |
| 3252 | { | 3248 | // has ever called PushRequest, so mapRequests was permanently empty and the |
| 3253 | uint256 hashReply; | 3249 | // handler could only ever be a parser for hostile input. |
| 3254 | CWalletTx wtxNew; | ||
| 3255 | vRecv >> hashReply >> wtxNew; | ||
| 3256 | |||
| 3257 | // Broadcast | ||
| 3258 | if (!wtxNew.AcceptWalletTransaction()) | ||
| 3259 | { | ||
| 3260 | pfrom->PushMessage("reply", hashReply, (int)1); | ||
| 3261 | return error("submitorder AcceptWalletTransaction() failed, returning error 1"); | ||
| 3262 | } | ||
| 3263 | wtxNew.fTimeReceivedIsTxTime = true; | ||
| 3264 | AddToWallet(wtxNew); | ||
| 3265 | wtxNew.RelayWalletTransaction(); | ||
| 3266 | mapReuseKey.erase(pfrom->addr.ip); | ||
| 3267 | |||
| 3268 | // Send back confirmation | ||
| 3269 | pfrom->PushMessage("reply", hashReply, (int)0); | ||
| 3270 | } | ||
| 3271 | |||
| 3272 | |||
| 3273 | else if (strCommand == "reply") | ||
| 3274 | { | ||
| 3275 | uint256 hashReply; | ||
| 3276 | vRecv >> hashReply; | ||
| 3277 | |||
| 3278 | CRequestTracker tracker; | ||
| 3279 | CRITICAL_BLOCK(pfrom->cs_mapRequests) | ||
| 3280 | { | ||
| 3281 | map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply); | ||
| 3282 | if (mi != pfrom->mapRequests.end()) | ||
| 3283 | { | ||
| 3284 | tracker = (*mi).second; | ||
| 3285 | pfrom->mapRequests.erase(mi); | ||
| 3286 | } | ||
| 3287 | } | ||
| 3288 | if (!tracker.IsNull()) | ||
| 3289 | tracker.fn(tracker.param1, vRecv); | ||
| 3290 | } | ||
| 3291 | 3250 | ||
| 3292 | 3251 | ||
| 3293 | else if (strCommand == "ping") | 3252 | else if (strCommand == "ping") |