Improve the code by static code analysis [3/3]: Style
[amule.git] / src / kademlia / net / KademliaUDPListener.cpp
blob084eef53938c92e9b941cbc8b9e4374a89ada1ed
1 //
2 // This file is part of aMule Project
3 //
4 // Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2003-2011 Barry Dunne ( http://www.emule-project.net )
7 // Copyright (C)2007-2011 Merkur ( strEmail.Format("%s@%s", "devteam", "emule-project.net") / http://www.emule-project.net )
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 // Note To Mods //
25 Please do not change anything here and release it..
26 There is going to be a new forum created just for the Kademlia side of the client..
27 If you feel there is an error or a way to improve something, please
28 post it in the forum first and let us look at it.. If it is a real improvement,
29 it will be added to the offical client.. Changing something without knowing
30 what all it does can cause great harm to the network if released in mass form..
31 Any mod that changes anything within the Kademlia side will not be allowed to advertise
32 there client on the eMule forum..
35 #include <wx/wx.h>
37 #include "KademliaUDPListener.h"
39 #include <protocol/Protocols.h>
40 #include <protocol/kad/Constants.h>
41 #include <protocol/kad/Client2Client/UDP.h>
42 #include <protocol/kad2/Constants.h>
43 #include <protocol/kad2/Client2Client/UDP.h>
44 #include <protocol/ed2k/Client2Client/TCP.h> // OP_CALLBACK is sent in some cases.
45 #include <common/Macros.h>
46 #include <common/Format.h>
47 #include <tags/FileTags.h>
49 #include "../routing/Contact.h"
50 #include "../routing/RoutingZone.h"
51 #include "../kademlia/Indexed.h"
52 #include "../kademlia/Defines.h"
53 #include "../kademlia/UDPFirewallTester.h"
54 #include "../utils/KadUDPKey.h"
55 #include "../utils/KadClientSearcher.h"
56 #include "../../amule.h"
57 #include "../../ClientUDPSocket.h"
58 #include "../../Packet.h"
59 #include "../../ClientList.h"
60 #include "../../Statistics.h"
61 #include "../../MemFile.h"
62 #include "../../updownclient.h"
63 #include "../../ClientTCPSocket.h"
64 #include "../../Logger.h"
65 #include "../../Preferences.h"
66 #include "../../ScopedPtr.h"
67 #include "../../IPFilter.h"
68 #include "../../RandomFunctions.h" // Needed for GetRandomUint128()
69 #include "../../CompilerSpecific.h" // Needed for __FUNCTION__
71 #include <wx/tokenzr.h>
73 #define THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX 0
75 #define CHECK_PACKET_SIZE(OP, SIZE) \
76 if (lenPacket OP (uint32_t)(SIZE)) \
77 throw wxString(CFormat(wxT("***NOTE: Received wrong size (%u) packet in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__))
79 #define CHECK_PACKET_MIN_SIZE(SIZE) CHECK_PACKET_SIZE(<, SIZE)
80 #define CHECK_PACKET_EXACT_SIZE(SIZE) CHECK_PACKET_SIZE(!=, SIZE)
82 #define CHECK_TRACKED_PACKET(OPCODE) \
83 if (!IsOnOutTrackList(ip, OPCODE)) \
84 throw wxString(CFormat(wxT("***NOTE: Received unrequested response packet, size (%u) in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__))
87 ////////////////////////////////////////
88 using namespace Kademlia;
89 ////////////////////////////////////////
91 CKademliaUDPListener::~CKademliaUDPListener()
93 // report timeout to all pending FetchNodeIDRequests
94 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
95 it->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
99 // Used by Kad1.0 and Kad2.0
100 void CKademliaUDPListener::Bootstrap(uint32_t ip, uint16_t port, uint8_t kadVersion, const CUInt128* cryptTargetID)
102 wxASSERT(ip);
104 DebugSend(Kad2BootstrapReq, ip, port);
105 CMemFile bio(0);
106 if (kadVersion >= 6) {
107 SendPacket(bio, KADEMLIA2_BOOTSTRAP_REQ, ip, port, 0, cryptTargetID);
108 } else {
109 SendPacket(bio, KADEMLIA2_BOOTSTRAP_REQ, ip, port, 0, NULL);
113 // Used by Kad1.0 and Kad2.0
114 void CKademliaUDPListener::SendMyDetails(uint8_t opcode, uint32_t ip, uint16_t port, uint8_t kadVersion, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID, bool requestAckPacket)
116 CMemFile packetdata;
117 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
119 if (kadVersion > 1) {
120 packetdata.WriteUInt16(thePrefs::GetPort());
121 packetdata.WriteUInt8(KADEMLIA_VERSION);
122 // Tag Count.
123 uint8_t tagCount = 0;
124 if (!CKademlia::GetPrefs()->GetUseExternKadPort()) {
125 tagCount++;
127 if (kadVersion >= 8 && (requestAckPacket || CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true))) {
128 tagCount++;
130 packetdata.WriteUInt8(tagCount);
131 if (!CKademlia::GetPrefs()->GetUseExternKadPort()) {
132 packetdata.WriteTag(CTagVarInt(TAG_SOURCEUPORT, CKademlia::GetPrefs()->GetInternKadPort()));
134 if (kadVersion >= 8 && (requestAckPacket || CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true))) {
135 // if we're firewalled we send this tag, so the other client doesn't add us to his routing table (if UDP firewalled) and for statistics reasons (TCP firewalled)
136 // 5 - reserved (!)
137 // 1 - requesting HELLO_RES_ACK
138 // 1 - TCP firewalled
139 // 1 - UDP firewalled
140 packetdata.WriteTag(CTagVarInt(TAG_KADMISCOPTIONS, (uint8_t)(
141 (requestAckPacket ? 1 : 0) << 2 |
142 (CKademlia::GetPrefs()->GetFirewalled() ? 1 : 0) << 1 |
143 (CUDPFirewallTester::IsFirewalledUDP(true) ? 1 : 0)
144 )));
146 if (kadVersion >= 6) {
147 if (cryptTargetID == NULL || *cryptTargetID == 0) {
148 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Sending hello response to crypt enabled Kad Node which provided an empty NodeID: %s (%u)")) % KadIPToString(ip) % kadVersion);
149 SendPacket(packetdata, opcode, ip, port, targetKey, NULL);
150 } else {
151 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
153 } else {
154 SendPacket(packetdata, opcode, ip, port, 0, NULL);
155 wxASSERT(targetKey.IsEmpty());
157 } else {
158 wxFAIL;
162 // Kad1.0 and Kad2.0 currently.
163 void CKademliaUDPListener::FirewalledCheck(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, uint8_t kadVersion)
165 if (kadVersion > 6) {
166 // new opcode since 0.49a with extended informations to support obfuscated connections properly
167 CMemFile packetdata(19);
168 packetdata.WriteUInt16(thePrefs::GetPort());
169 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
170 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false));
171 DebugSend(KadFirewalled2Req, ip, port);
172 SendPacket(packetdata, KADEMLIA_FIREWALLED2_REQ, ip, port, senderKey, NULL);
173 } else {
174 CMemFile packetdata(2);
175 packetdata.WriteUInt16(thePrefs::GetPort());
176 DebugSend(KadFirewalledReq, ip, port);
177 SendPacket(packetdata, KADEMLIA_FIREWALLED_REQ, ip, port, senderKey, NULL);
179 theApp->clientlist->AddKadFirewallRequest(wxUINT32_SWAP_ALWAYS(ip));
182 void CKademliaUDPListener::SendNullPacket(uint8_t opcode, uint32_t ip, uint16_t port, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
184 CMemFile packetdata(0);
185 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
188 void CKademliaUDPListener::SendPublishSourcePacket(const CContact& contact, const CUInt128 &targetID, const CUInt128 &contactID, const TagPtrList& tags)
190 uint8_t opcode;
191 CMemFile packetdata;
192 packetdata.WriteUInt128(targetID);
193 if (contact.GetVersion() >= 4/*47c*/) {
194 opcode = KADEMLIA2_PUBLISH_SOURCE_REQ;
195 packetdata.WriteUInt128(contactID);
196 packetdata.WriteTagPtrList(tags);
197 DebugSend(Kad2PublishSrcReq, contact.GetIPAddress(), contact.GetUDPPort());
198 } else {
199 opcode = KADEMLIA_PUBLISH_REQ;
200 //We only use this for publishing sources now.. So we always send one here..
201 packetdata.WriteUInt16(1);
202 packetdata.WriteUInt128(contactID);
203 packetdata.WriteTagPtrList(tags);
204 DebugSend(KadPublishReq, contact.GetIPAddress(), contact.GetUDPPort());
206 if (contact.GetVersion() >= 6) { // obfuscated ?
207 CUInt128 clientID = contact.GetClientID();
208 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), contact.GetUDPKey(), &clientID);
209 } else {
210 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), 0, NULL);
214 void CKademliaUDPListener::ProcessPacket(const uint8_t* data, uint32_t lenData, uint32_t ip, uint16_t port, bool validReceiverKey, const CKadUDPKey& senderKey)
216 // we do not accept (<= 0.48a) unencrypted incoming packets from port 53 (DNS) to avoid attacks based on DNS protocol confusion
217 if (port == 53 && senderKey.IsEmpty()) {
218 AddDebugLogLineN(logKadPacketTracking, wxT("Dropping incoming unencrypted packet on port 53 (DNS), IP: ") + KadIPToString(ip));
219 return;
222 //Update connection state only when it changes.
223 bool curCon = CKademlia::GetPrefs()->HasHadContact();
224 CKademlia::GetPrefs()->SetLastContact();
225 CUDPFirewallTester::Connected();
226 if( curCon != CKademlia::GetPrefs()->HasHadContact()) {
227 theApp->ShowConnectionState();
230 uint8_t opcode = data[1];
231 const uint8_t *packetData = data + 2;
232 uint32_t lenPacket = lenData - 2;
234 if (!InTrackListIsAllowedPacket(ip, opcode, validReceiverKey)) {
235 return;
238 switch (opcode) {
239 case KADEMLIA2_BOOTSTRAP_REQ:
240 DebugRecv(Kad2BootstrapReq, ip, port);
241 Process2BootstrapRequest(ip, port, senderKey);
242 break;
243 case KADEMLIA2_BOOTSTRAP_RES:
244 DebugRecv(Kad2BootstrapRes, ip, port);
245 Process2BootstrapResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
246 break;
247 case KADEMLIA2_HELLO_REQ:
248 DebugRecv(Kad2HelloReq, ip, port);
249 Process2HelloRequest(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
250 break;
251 case KADEMLIA2_HELLO_RES:
252 DebugRecv(Kad2HelloRes, ip, port);
253 Process2HelloResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
254 break;
255 case KADEMLIA2_HELLO_RES_ACK:
256 DebugRecv(Kad2HelloResAck, ip, port);
257 Process2HelloResponseAck(packetData, lenPacket, ip, validReceiverKey);
258 break;
259 case KADEMLIA2_REQ:
260 DebugRecv(Kad2Req, ip, port);
261 ProcessKademlia2Request(packetData, lenPacket, ip, port, senderKey);
262 break;
263 case KADEMLIA2_RES:
264 DebugRecv(Kad2Res, ip, port);
265 ProcessKademlia2Response(packetData, lenPacket, ip, port, senderKey);
266 break;
267 case KADEMLIA2_SEARCH_NOTES_REQ:
268 DebugRecv(Kad2SearchNotesReq, ip, port);
269 Process2SearchNotesRequest(packetData, lenPacket, ip, port, senderKey);
270 break;
271 case KADEMLIA2_SEARCH_KEY_REQ:
272 DebugRecv(Kad2SearchKeyReq, ip, port);
273 Process2SearchKeyRequest(packetData, lenPacket, ip, port, senderKey);
274 break;
275 case KADEMLIA2_SEARCH_SOURCE_REQ:
276 DebugRecv(Kad2SearchSourceReq, ip, port);
277 Process2SearchSourceRequest(packetData, lenPacket, ip, port, senderKey);
278 break;
279 case KADEMLIA_SEARCH_RES:
280 DebugRecv(KadSearchRes, ip, port);
281 ProcessSearchResponse(packetData, lenPacket);
282 break;
283 case KADEMLIA_SEARCH_NOTES_RES:
284 DebugRecv(KadSearchNotesRes, ip, port);
285 ProcessSearchNotesResponse(packetData, lenPacket, ip);
286 break;
287 case KADEMLIA2_SEARCH_RES:
288 DebugRecv(Kad2SearchRes, ip, port);
289 Process2SearchResponse(packetData, lenPacket, senderKey);
290 break;
291 case KADEMLIA2_PUBLISH_NOTES_REQ:
292 DebugRecv(Kad2PublishNotesReq, ip, port);
293 Process2PublishNotesRequest(packetData, lenPacket, ip, port, senderKey);
294 break;
295 case KADEMLIA2_PUBLISH_KEY_REQ:
296 DebugRecv(Kad2PublishKeyReq, ip, port);
297 Process2PublishKeyRequest(packetData, lenPacket, ip, port, senderKey);
298 break;
299 case KADEMLIA2_PUBLISH_SOURCE_REQ:
300 DebugRecv(Kad2PublishSourceReq, ip, port);
301 Process2PublishSourceRequest(packetData, lenPacket, ip, port, senderKey);
302 break;
303 case KADEMLIA_PUBLISH_RES:
304 DebugRecv(KadPublishRes, ip, port);
305 ProcessPublishResponse(packetData, lenPacket, ip);
306 break;
307 case KADEMLIA2_PUBLISH_RES:
308 DebugRecv(Kad2PublishRes, ip, port);
309 Process2PublishResponse(packetData, lenPacket, ip, port, senderKey);
310 break;
311 case KADEMLIA_FIREWALLED_REQ:
312 DebugRecv(KadFirewalledReq, ip, port);
313 ProcessFirewalledRequest(packetData, lenPacket, ip, port, senderKey);
314 break;
315 case KADEMLIA_FIREWALLED2_REQ:
316 DebugRecv(KadFirewalled2Req, ip, port);
317 ProcessFirewalled2Request(packetData, lenPacket, ip, port, senderKey);
318 break;
319 case KADEMLIA_FIREWALLED_RES:
320 DebugRecv(KadFirewalledRes, ip, port);
321 ProcessFirewalledResponse(packetData, lenPacket, ip, senderKey);
322 break;
323 case KADEMLIA_FIREWALLED_ACK_RES:
324 DebugRecv(KadFirewalledAck, ip, port);
325 ProcessFirewalledAckResponse(lenPacket);
326 break;
327 case KADEMLIA_FINDBUDDY_REQ:
328 DebugRecv(KadFindBuddyReq, ip, port);
329 ProcessFindBuddyRequest(packetData, lenPacket, ip, port, senderKey);
330 break;
331 case KADEMLIA_FINDBUDDY_RES:
332 DebugRecv(KadFindBuddyRes, ip, port);
333 ProcessFindBuddyResponse(packetData, lenPacket, ip, port, senderKey);
334 break;
335 case KADEMLIA_CALLBACK_REQ:
336 DebugRecv(KadCallbackReq, ip, port);
337 ProcessCallbackRequest(packetData, lenPacket, ip, port, senderKey);
338 break;
339 case KADEMLIA2_PING:
340 DebugRecv(Kad2Ping, ip, port);
341 Process2Ping(ip, port, senderKey);
342 break;
343 case KADEMLIA2_PONG:
344 DebugRecv(Kad2Pong, ip, port);
345 Process2Pong(packetData, lenPacket, ip);
346 break;
347 case KADEMLIA2_FIREWALLUDP:
348 DebugRecv(Kad2FirewallUDP, ip, port);
349 Process2FirewallUDP(packetData, lenPacket, ip);
350 break;
352 // old Kad1 opcodes which we don't handle anymore
353 case KADEMLIA_BOOTSTRAP_REQ_DEPRECATED:
354 case KADEMLIA_BOOTSTRAP_RES_DEPRECATED:
355 case KADEMLIA_HELLO_REQ_DEPRECATED:
356 case KADEMLIA_HELLO_RES_DEPRECATED:
357 case KADEMLIA_REQ_DEPRECATED:
358 case KADEMLIA_RES_DEPRECATED:
359 case KADEMLIA_PUBLISH_NOTES_REQ_DEPRECATED:
360 case KADEMLIA_PUBLISH_NOTES_RES_DEPRECATED:
361 case KADEMLIA_SEARCH_REQ:
362 case KADEMLIA_PUBLISH_REQ:
363 case KADEMLIA_SEARCH_NOTES_REQ:
364 break;
366 default: {
367 throw wxString(CFormat(wxT("Unknown opcode %02x on CKademliaUDPListener::ProcessPacket()")) % opcode);
372 // Used only for Kad2.0
373 bool CKademliaUDPListener::AddContact2(const uint8_t *data, uint32_t lenData, uint32_t ip, uint16_t& port, uint8_t *outVersion, const CKadUDPKey& udpKey, bool& ipVerified, bool update, bool fromHelloReq, bool* outRequestsACK, CUInt128* outContactID)
375 if (outRequestsACK != 0) {
376 *outRequestsACK = false;
379 CMemFile bio(data, lenData);
380 CUInt128 id = bio.ReadUInt128();
381 if (outContactID != NULL) {
382 *outContactID = id;
384 uint16_t tport = bio.ReadUInt16();
385 uint8_t version = bio.ReadUInt8();
386 if (version == 0) {
387 throw wxString(CFormat(wxT("***NOTE: Received invalid Kademlia2 version (%u) in %s")) % version % wxString::FromAscii(__FUNCTION__));
389 if (outVersion != NULL) {
390 *outVersion = version;
392 bool udpFirewalled = false;
393 bool tcpFirewalled = false;
394 uint8_t tags = bio.ReadUInt8();
395 while (tags) {
396 CTag *tag = bio.ReadTag();
397 if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
398 if (tag->IsInt() && (uint16_t)tag->GetInt() > 0) {
399 port = tag->GetInt();
401 } else if (!tag->GetName().Cmp(TAG_KADMISCOPTIONS)) {
402 if (tag->IsInt() && tag->GetInt() > 0) {
403 udpFirewalled = (tag->GetInt() & 0x01) > 0;
404 tcpFirewalled = (tag->GetInt() & 0x02) > 0;
405 if ((tag->GetInt() & 0x04) > 0) {
406 if (outRequestsACK != NULL) {
407 if (version >= 8) {
408 *outRequestsACK = true;
410 } else {
411 wxFAIL;
416 delete tag;
417 --tags;
420 // check if we are waiting for informations (nodeid) about this client and if so inform the requester
421 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
422 if (it->ip == ip && it->tcpPort == tport) {
423 //AddDebugLogLineN(logKadMain, wxT("Result Addcontact: ") + id.ToHexString());
424 uint8_t uchID[16];
425 id.ToByteArray(uchID);
426 it->requester->KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, uchID);
427 m_fetchNodeIDRequests.erase(it);
428 break;
432 if (fromHelloReq && version >= 8) {
433 // this is just for statistic calculations. We try to determine the ratio of (UDP) firewalled users,
434 // by counting how many of all nodes which have us in their routing table (our own routing table is supposed
435 // to have no UDP firewalled nodes at all) and support the firewalled tag are firewalled themself.
436 // Obviously this only works if we are not firewalled ourself
437 CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(udpFirewalled);
438 CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(tcpFirewalled);
441 if (!udpFirewalled) { // do not add (or update) UDP firewalled sources to our routing table
442 return CKademlia::GetRoutingZone()->Add(id, ip, port, tport, version, udpKey, ipVerified, update, true);
443 } else {
444 AddDebugLogLineN(logKadRouting, wxT("Not adding firewalled client to routing table (") + KadIPToString(ip) + wxT(")"));
445 return false;
449 // KADEMLIA2_BOOTSTRAP_REQ
450 // Used only for Kad2.0
451 void CKademliaUDPListener::Process2BootstrapRequest(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
453 // Get some contacts to return
454 ContactList contacts;
455 uint16_t numContacts = (uint16_t)CKademlia::GetRoutingZone()->GetBootstrapContacts(&contacts, 20);
457 // Create response packet
458 //We only collect a max of 20 contacts here.. Max size is 521.
459 //2 + 25(20) + 19
460 CMemFile packetdata(521);
462 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
463 packetdata.WriteUInt16(thePrefs::GetPort());
464 packetdata.WriteUInt8(KADEMLIA_VERSION);
466 // Write packet info
467 packetdata.WriteUInt16(numContacts);
468 CContact *contact;
469 for (ContactList::const_iterator it = contacts.begin(); it != contacts.end(); ++it) {
470 contact = *it;
471 packetdata.WriteUInt128(contact->GetClientID());
472 packetdata.WriteUInt32(contact->GetIPAddress());
473 packetdata.WriteUInt16(contact->GetUDPPort());
474 packetdata.WriteUInt16(contact->GetTCPPort());
475 packetdata.WriteUInt8(contact->GetVersion());
478 // Send response
479 DebugSend(Kad2BootstrapRes, ip, port);
480 SendPacket(packetdata, KADEMLIA2_BOOTSTRAP_RES, ip, port, senderKey, NULL);
483 // KADEMLIA2_BOOTSTRAP_RES
484 // Used only for Kad2.0
485 void CKademliaUDPListener::Process2BootstrapResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
487 CHECK_TRACKED_PACKET(KADEMLIA2_BOOTSTRAP_REQ);
489 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
491 // How many contacts were given
492 CMemFile bio(packetData, lenPacket);
493 CUInt128 contactID = bio.ReadUInt128();
494 uint16_t tport = bio.ReadUInt16();
495 uint8_t version = bio.ReadUInt8();
496 // if we don't know any Contacts yet and try to Bootstrap, we assume that all contacts are verified,
497 // in order to speed up the connecting process. The attackvectors to exploit this are very small with no
498 // major effects, so that's a good trade
499 bool assumeVerified = CKademlia::GetRoutingZone()->GetNumContacts() == 0;
501 if (CKademlia::s_bootstrapList.empty()) {
502 routingZone->Add(contactID, ip, port, tport, version, senderKey, validReceiverKey, true, false);
504 //AddDebugLogLineN(logClientKadUDP, wxT("Inc Kad2 Bootstrap packet from ") + KadIPToString(ip));
506 uint16_t numContacts = bio.ReadUInt16();
507 while (numContacts) {
508 contactID = bio.ReadUInt128();
509 ip = bio.ReadUInt32();
510 port = bio.ReadUInt16();
511 tport = bio.ReadUInt16();
512 version = bio.ReadUInt8();
513 bool verified = assumeVerified;
514 routingZone->Add(contactID, ip, port, tport, version, 0, verified, false, false);
515 numContacts--;
519 // KADEMLIA2_HELLO_REQ
520 // Used in Kad2.0 only
521 void CKademliaUDPListener::Process2HelloRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
523 DEBUG_ONLY( uint16_t dbgOldUDPPort = port; )
524 uint8_t contactVersion = 0;
525 CUInt128 contactID;
526 bool addedOrUpdated = AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true, true, NULL, &contactID); // might change (udp)port, validReceiverKey
527 wxASSERT(contactVersion >= 2);
528 #ifdef __DEBUG__
529 if (dbgOldUDPPort != port) {
530 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("KadContact %s uses his internal (%u) instead external (%u) UDP Port")) % KadIPToString(ip) % port % dbgOldUDPPort);
532 #endif
534 DebugSend(Kad2HelloRes, ip, port);
535 // if this contact was added or updated (so with other words not filtered or invalid) to our routing table and did not already send a valid
536 // receiver key or is already verified in the routing table, we request an additional ACK package to complete a three-way-handshake and
537 // verify the remote IP
538 SendMyDetails(KADEMLIA2_HELLO_RES, ip, port, contactVersion, senderKey, &contactID, addedOrUpdated && !validReceiverKey);
540 if (addedOrUpdated && !validReceiverKey && contactVersion == 7 && !HasActiveLegacyChallenge(ip)) {
541 // Kad Version 7 doesn't support HELLO_RES_ACK but sender/receiver keys, so send a ping to validate
542 DebugSend(Kad2Ping, ip, port);
543 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
544 #ifdef __DEBUG__
545 CContact* contact = CKademlia::GetRoutingZone()->GetContact(contactID);
546 if (contact != NULL) {
547 if (contact->GetType() < 2) {
548 AddDebugLogLineN(logKadRouting, wxT("Sending (ping) challenge to a long known contact (should be verified already) - ") + KadIPToString(ip));
550 } else {
551 wxFAIL;
553 #endif
554 } else if (CKademlia::GetPrefs()->FindExternKadPort(false) && contactVersion > 5) { // do we need to find out our extern port?
555 DebugSend(Kad2Ping, ip, port);
556 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
559 if (addedOrUpdated && !validReceiverKey && contactVersion < 7 && !HasActiveLegacyChallenge(ip)) {
560 // we need to verify this contact but it doesn't support HELLO_RES_ACK nor keys, do a little workaround
561 SendLegacyChallenge(ip, port, contactID);
564 // Check if firewalled
565 if (CKademlia::GetPrefs()->GetRecheckIP()) {
566 FirewalledCheck(ip, port, senderKey, contactVersion);
570 // KADEMLIA2_HELLO_RES_ACK
571 // Used in Kad2.0 only
572 void CKademliaUDPListener::Process2HelloResponseAck(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, bool validReceiverKey)
574 CHECK_PACKET_MIN_SIZE(17);
575 CHECK_TRACKED_PACKET(KADEMLIA2_HELLO_RES);
577 if (!validReceiverKey) {
578 AddDebugLogLineN(logClientKadUDP, wxT("Receiver key is invalid! (sender: ") + KadIPToString(ip) + wxT(")"));
579 return;
582 // Additional packet to complete a three-way-handshake, making sure the remote contact is not using a spoofed ip.
583 CMemFile bio(packetData, lenPacket);
584 CUInt128 remoteID = bio.ReadUInt128();
585 // cppcheck-suppress duplicateBranch
586 if (!CKademlia::GetRoutingZone()->VerifyContact(remoteID, ip)) {
587 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
588 } else {
589 AddDebugLogLineN(logKadRouting, wxT("Verified contact (") + KadIPToString(ip) + wxT(") by HELLO_RES_ACK"));
593 // KADEMLIA2_HELLO_RES
594 // Used in Kad2.0 only
595 void CKademliaUDPListener::Process2HelloResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
597 CHECK_TRACKED_PACKET(KADEMLIA2_HELLO_REQ);
599 // Add or Update contact.
600 uint8_t contactVersion;
601 CUInt128 contactID;
602 bool sendACK = false;
603 bool addedOrUpdated = AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true, false, &sendACK, &contactID);
605 if (sendACK) {
606 // the client requested us to send an ACK packet, which proves that we're not a spoofed fake contact
607 // fulfill his wish
608 if (senderKey.IsEmpty()) {
609 // but we don't have a valid sender key - there is no point to reply in this case
610 // most likely a bug in the remote client
611 AddDebugLogLineN(logClientKadUDP, wxT("Remote client demands ACK, but didn't send any sender key! (sender: ") + KadIPToString(ip) + wxT(")"));
612 } else {
613 CMemFile packet(17);
614 packet.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
615 packet.WriteUInt8(0); // no tags at this time
616 DebugSend(Kad2HelloResAck, ip, port);
617 SendPacket(packet, KADEMLIA2_HELLO_RES_ACK, ip, port, senderKey, NULL);
619 } else if (addedOrUpdated && !validReceiverKey && contactVersion < 7) {
620 // even though this is supposably an answer to a request from us, there are still possibilities to spoof
621 // it, as long as the attacker knows that we would send a HELLO_REQ (which in this case is quite often),
622 // so for old Kad Version which doesn't support keys, we need
623 SendLegacyChallenge(ip, port, contactID);
626 // do we need to find out our extern port?
627 if (CKademlia::GetPrefs()->FindExternKadPort(false) && contactVersion > 5) {
628 DebugSend(Kad2Ping, ip, port);
629 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
632 // Check if firewalled
633 if (CKademlia::GetPrefs()->GetRecheckIP()) {
634 FirewalledCheck(ip, port, senderKey, contactVersion);
638 // KADEMLIA2_REQ
639 // Used in Kad2.0 only
640 void CKademliaUDPListener::ProcessKademlia2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
642 // Get target and type
643 CMemFile bio(packetData, lenPacket);
644 uint8_t type = bio.ReadUInt8();
645 type &= 0x1F;
646 if (type == 0) {
647 throw wxString(CFormat(wxT("***NOTE: Received wrong type (0x%02x) in %s")) % type % wxString::FromAscii(__FUNCTION__));
650 // This is the target node trying to be found.
651 CUInt128 target = bio.ReadUInt128();
652 // Convert Target to Distance as this is how we store contacts.
653 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
654 distance ^= target;
656 // This makes sure we are not mistaken identify. Some client may have fresh installed and have a new KadID.
657 CUInt128 check = bio.ReadUInt128();
658 if (CKademlia::GetPrefs()->GetKadID() == check) {
659 // Get required number closest to target
660 ContactMap results;
661 CKademlia::GetRoutingZone()->GetClosestTo(2, target, distance, type, &results);
662 uint8_t count = (uint8_t)results.size();
664 // Write response
665 // Max count is 32. size 817..
666 // 16 + 1 + 25(32)
667 CMemFile packetdata(817);
668 packetdata.WriteUInt128(target);
669 packetdata.WriteUInt8(count);
670 CContact *c;
671 for (ContactMap::const_iterator it = results.begin(); it != results.end(); ++it) {
672 c = it->second;
673 packetdata.WriteUInt128(c->GetClientID());
674 packetdata.WriteUInt32(c->GetIPAddress());
675 packetdata.WriteUInt16(c->GetUDPPort());
676 packetdata.WriteUInt16(c->GetTCPPort());
677 packetdata.WriteUInt8(c->GetVersion()); //<- Kad Version inserted to allow backward compatibility.
680 DebugSendF(CFormat(wxT("Kad2Res (count=%u)")) % count, ip, port);
681 SendPacket(packetdata, KADEMLIA2_RES, ip, port, senderKey, NULL);
685 // KADEMLIA2_RES
686 // Used in Kad2.0 only
687 void CKademliaUDPListener::ProcessKademlia2Response(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
689 CHECK_TRACKED_PACKET(KADEMLIA2_REQ);
691 // Used Pointers
692 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
694 // What search does this relate to
695 CMemFile bio(packetData, lenPacket);
696 CUInt128 target = bio.ReadUInt128();
697 uint8_t numContacts = bio.ReadUInt8();
699 // Is this one of our legacy challenge packets?
700 CUInt128 contactID;
701 if (IsLegacyChallenge(target, ip, KADEMLIA2_REQ, contactID)) {
702 // yup it is, set the contact as verified
703 // cppcheck-suppress duplicateBranch
704 if (!routingZone->VerifyContact(contactID, ip)) {
705 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
706 } else {
707 AddDebugLogLineN(logKadRouting, wxT("Verified contact with legacy challenge (Kad2Req) - ") + KadIPToString(ip));
709 return; // we do not actually care for its other content
711 // Verify packet is expected size
712 CHECK_PACKET_EXACT_SIZE(16+1 + (16+4+2+2+1)*numContacts);
714 // is this a search for firewallcheck ips?
715 bool isFirewallUDPCheckSearch = false;
716 if (CUDPFirewallTester::IsFWCheckUDPRunning() && CSearchManager::IsFWCheckUDPSearch(target)) {
717 isFirewallUDPCheckSearch = true;
720 DEBUG_ONLY( uint32_t ignoredCount = 0; )
721 DEBUG_ONLY( uint32_t kad1Count = 0; )
722 CScopedPtr<ContactList> results;
723 for (uint8_t i = 0; i < numContacts; i++) {
724 CUInt128 id = bio.ReadUInt128();
725 uint32_t contactIP = bio.ReadUInt32();
726 uint16_t contactPort = bio.ReadUInt16();
727 uint16_t tport = bio.ReadUInt16();
728 uint8_t version = bio.ReadUInt8();
729 uint32_t hostIP = wxUINT32_SWAP_ALWAYS(contactIP);
730 if (version > 1) { // Kad1 nodes are no longer accepted and ignored
731 if (::IsGoodIPPort(hostIP, contactPort)) {
732 if (!theApp->ipfilter->IsFiltered(hostIP) && !(contactPort == 53 && version <= 5) /*No DNS Port without encryption*/) {
733 if (isFirewallUDPCheckSearch) {
734 // UDP FirewallCheck searches are special. The point is we need an IP which we didn't sent a UDP message yet
735 // (or in the near future), so we do not try to add those contacts to our routingzone and we also don't
736 // deliver them back to the searchmanager (because he would UDP-ask them for further results), but only report
737 // them to FirewallChecker - this will of course cripple the search but thats not the point, since we only
738 // care for IPs and not the random set target
739 CUDPFirewallTester::AddPossibleTestContact(id, contactIP, contactPort, tport, target, version, 0, false);
740 } else {
741 bool verified = false;
742 bool wasAdded = routingZone->AddUnfiltered(id, contactIP, contactPort, tport, version, 0, verified, false, false);
743 CContact *temp = new CContact(id, contactIP, contactPort, tport, version, 0, false, target);
744 if (wasAdded || routingZone->IsAcceptableContact(temp)) {
745 results->push_back(temp);
746 } else {
747 DEBUG_ONLY( ignoredCount++; )
748 delete temp;
753 } else {
754 DEBUG_ONLY( kad1Count++; )
758 #ifdef __DEBUG__
759 if (ignoredCount > 0) {
760 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignored %u bad %s in routing answer from %s")) % ignoredCount % (ignoredCount > 1 ? wxT("contacts") : wxT("contact")) % KadIPToString(ip));
762 if (kad1Count > 0) {
763 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignored %u kad1 %s in routing answer from %s")) % kad1Count % (kad1Count > 1 ? wxT("contacts") : wxT("contact")) % KadIPToString(ip));
765 #endif
767 CSearchManager::ProcessResponse(target, ip, port, results.release());
770 void CKademliaUDPListener::Free(SSearchTerm* pSearchTerms)
772 if (pSearchTerms) {
773 Free(pSearchTerms->left);
774 Free(pSearchTerms->right);
775 delete pSearchTerms;
779 SSearchTerm* CKademliaUDPListener::CreateSearchExpressionTree(CMemFile& bio, int iLevel)
781 // the max. depth has to match our own limit for creating the search expression
782 // (see also 'ParsedSearchExpression' and 'GetSearchPacket')
783 if (iLevel >= 24){
784 AddDebugLogLineN(logKadSearch, wxT("***NOTE: Search expression tree exceeds depth limit!"));
785 return NULL;
787 iLevel++;
789 uint8_t op = bio.ReadUInt8();
790 if (op == 0x00) {
791 uint8_t boolop = bio.ReadUInt8();
792 if (boolop == 0x00) { // AND
793 SSearchTerm* pSearchTerm = new SSearchTerm;
794 pSearchTerm->type = SSearchTerm::AND;
795 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
796 delete pSearchTerm;
797 return NULL;
799 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
800 Free(pSearchTerm->left);
801 delete pSearchTerm;
802 return NULL;
804 return pSearchTerm;
805 } else if (boolop == 0x01) { // OR
806 SSearchTerm* pSearchTerm = new SSearchTerm;
807 pSearchTerm->type = SSearchTerm::OR;
808 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
809 delete pSearchTerm;
810 return NULL;
812 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
813 Free(pSearchTerm->left);
814 delete pSearchTerm;
815 return NULL;
817 return pSearchTerm;
818 } else if (boolop == 0x02) { // NOT
819 SSearchTerm* pSearchTerm = new SSearchTerm;
820 pSearchTerm->type = SSearchTerm::NOT;
821 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
822 delete pSearchTerm;
823 return NULL;
825 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL) {
826 Free(pSearchTerm->left);
827 delete pSearchTerm;
828 return NULL;
830 return pSearchTerm;
831 } else {
832 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown boolean search operator 0x%02x (CreateSearchExpressionTree)")) % boolop);
833 return NULL;
835 } else if (op == 0x01) { // String
836 wxString str(bio.ReadString(true));
838 // Make lowercase, the search code expects lower case strings!
839 str.MakeLower();
841 SSearchTerm* pSearchTerm = new SSearchTerm;
842 pSearchTerm->type = SSearchTerm::String;
843 pSearchTerm->astr = new wxArrayString;
845 // pre-tokenize the string term
846 //#warning TODO: TokenizeOptQuotedSearchTerm
847 wxStringTokenizer token(str, CSearchManager::GetInvalidKeywordChars(), wxTOKEN_DEFAULT );
848 while (token.HasMoreTokens()) {
849 wxString strTok(token.GetNextToken());
850 if (!strTok.IsEmpty()) {
851 pSearchTerm->astr->Add(strTok);
855 return pSearchTerm;
856 } else if (op == 0x02) { // Meta tag
857 // read tag value
858 wxString strValue(bio.ReadString(true));
859 // Make lowercase, the search code expects lower case strings!
860 strValue.MakeLower();
862 // read tag name
863 wxString strTagName = bio.ReadString(false);
865 SSearchTerm* pSearchTerm = new SSearchTerm;
866 pSearchTerm->type = SSearchTerm::MetaTag;
867 pSearchTerm->tag = new CTagString(strTagName, strValue);
868 return pSearchTerm;
870 else if (op == 0x03 || op == 0x08) { // Numeric relation (0x03=32-bit or 0x08=64-bit)
871 static const struct {
872 SSearchTerm::ESearchTermType eSearchTermOp;
873 wxString pszOp;
874 } _aOps[] =
876 { SSearchTerm::OpEqual, wxT("=") }, // mmop=0x00
877 { SSearchTerm::OpGreater, wxT(">") }, // mmop=0x01
878 { SSearchTerm::OpLess, wxT("<") }, // mmop=0x02
879 { SSearchTerm::OpGreaterEqual, wxT(">=") }, // mmop=0x03
880 { SSearchTerm::OpLessEqual, wxT("<=") }, // mmop=0x04
881 { SSearchTerm::OpNotEqual, wxT("<>") } // mmop=0x05
884 // read tag value
885 uint64_t ullValue = (op == 0x03) ? bio.ReadUInt32() : bio.ReadUInt64();
887 // read integer operator
888 uint8_t mmop = bio.ReadUInt8();
889 if (mmop >= itemsof(_aOps)){
890 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown integer search op=0x%02x (CreateSearchExpressionTree)")) % mmop);
891 return NULL;
894 // read tag name
895 wxString strTagName = bio.ReadString(false);
897 SSearchTerm* pSearchTerm = new SSearchTerm;
898 pSearchTerm->type = _aOps[mmop].eSearchTermOp;
899 pSearchTerm->tag = new CTagVarInt(strTagName, ullValue);
901 return pSearchTerm;
902 } else {
903 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown search op=0x%02x (CreateSearchExpressionTree)")) % op);
904 return NULL;
908 // KADEMLIA2_SEARCH_KEY_REQ
909 // Used in Kad2.0 only
910 void CKademliaUDPListener::Process2SearchKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
912 CMemFile bio(packetData, lenPacket);
913 CUInt128 target = bio.ReadUInt128();
914 uint16_t startPosition = bio.ReadUInt16();
915 bool restrictive = ((startPosition & 0x8000) == 0x8000);
916 startPosition &= 0x7FFF;
917 SSearchTerm* pSearchTerms = NULL;
918 if (restrictive) {
919 pSearchTerms = CreateSearchExpressionTree(bio, 0);
920 if (pSearchTerms == NULL) {
921 throw wxString(wxT("Invalid search expression"));
924 CKademlia::GetIndexed()->SendValidKeywordResult(target, pSearchTerms, ip, port, false, startPosition, senderKey);
925 if (pSearchTerms) {
926 Free(pSearchTerms);
930 // KADEMLIA2_SEARCH_SOURCE_REQ
931 // Used in Kad2.0 only
932 void CKademliaUDPListener::Process2SearchSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
934 CMemFile bio(packetData, lenPacket);
935 CUInt128 target = bio.ReadUInt128();
936 uint16_t startPosition = (bio.ReadUInt16() & 0x7FFF);
937 uint64_t fileSize = bio.ReadUInt64();
938 CKademlia::GetIndexed()->SendValidSourceResult(target, ip, port, startPosition, fileSize, senderKey);
941 void CKademliaUDPListener::ProcessSearchResponse(CMemFile& bio)
943 // What search does this relate to
944 CUInt128 target = bio.ReadUInt128();
946 // How many results..
947 uint16_t count = bio.ReadUInt16();
948 while (count > 0) {
949 // What is the answer
950 CUInt128 answer = bio.ReadUInt128();
952 // Get info about answer
953 // NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
954 // case we did not receive an UTF8 string. this is for backward compatibility for search results which are
955 // supposed to be 'viewed' by user only and not feed into the Kad engine again!
956 // If that tag list is once used for something else than for viewing, special care has to be taken for any
957 // string conversion!
958 CScopedContainer<TagPtrList> tags;
959 bio.ReadTagPtrList(tags.get(), true/*bOptACP*/);
960 CSearchManager::ProcessResult(target, answer, tags.get());
961 count--;
966 // KADEMLIA_SEARCH_RES
967 // Used in Kad1.0 only
968 void CKademliaUDPListener::ProcessSearchResponse(const uint8_t *packetData, uint32_t lenPacket)
970 // Verify packet is expected size
971 CHECK_PACKET_MIN_SIZE(37);
973 CMemFile bio(packetData, lenPacket);
974 ProcessSearchResponse(bio);
977 // KADEMLIA2_SEARCH_RES
978 // Used in Kad2.0 only
979 void CKademliaUDPListener::Process2SearchResponse(const uint8_t *packetData, uint32_t lenPacket, const CKadUDPKey& WXUNUSED(senderKey))
981 CMemFile bio(packetData, lenPacket);
983 // Who sent this packet.
984 bio.ReadUInt128();
986 ProcessSearchResponse(bio);
989 // KADEMLIA2_PUBLISH_KEY_REQ
990 // Used in Kad2.0 only
991 void CKademliaUDPListener::Process2PublishKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
993 //Used Pointers
994 CIndexed *indexed = CKademlia::GetIndexed();
996 // check if we are UDP firewalled
997 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
998 //We are firewalled. We should not index this entry and give publisher a false report.
999 return;
1002 CMemFile bio(packetData, lenPacket);
1003 CUInt128 file = bio.ReadUInt128();
1005 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1006 distance ^= file;
1008 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1009 return;
1012 DEBUG_ONLY( wxString strInfo; )
1013 uint16_t count = bio.ReadUInt16();
1014 uint8_t load = 0;
1015 while (count > 0) {
1016 DEBUG_ONLY( strInfo.Clear(); )
1018 CUInt128 target = bio.ReadUInt128();
1020 Kademlia::CKeyEntry* entry = new Kademlia::CKeyEntry();
1023 entry->m_uIP = ip;
1024 entry->m_uUDPport = port;
1025 entry->m_uKeyID = file;
1026 entry->m_uSourceID = target;
1027 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMEK;
1028 entry->m_bSource = false;
1029 uint32_t tags = bio.ReadUInt8();
1030 while (tags > 0) {
1031 CTag* tag = bio.ReadTag();
1032 if (tag) {
1033 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1034 if (entry->GetCommonFileName().IsEmpty()) {
1035 entry->SetFileName(tag->GetStr());
1036 DEBUG_ONLY( strInfo += CFormat(wxT(" Name=\"%s\"")) % entry->GetCommonFileName(); )
1038 delete tag; // tag is no longer stored, but membervar is used
1039 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1040 if (entry->m_uSize == 0) {
1041 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1042 entry->m_uSize = PeekUInt64(tag->GetBsob());
1043 } else {
1044 entry->m_uSize = tag->GetInt();
1046 DEBUG_ONLY( strInfo += CFormat(wxT(" Size=%u")) % entry->m_uSize; )
1048 delete tag; // tag is no longer stored, but membervar is used
1049 } else {
1050 //TODO: Filter tags
1051 entry->AddTag(tag);
1054 tags--;
1056 #ifdef __DEBUG__
1057 if (!strInfo.IsEmpty()) {
1058 AddDebugLogLineN(logClientKadUDP, strInfo);
1060 #endif
1061 } catch(...) {
1062 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishKeyRequest"),ip,port,packetData,lenPacket);
1063 delete entry;
1064 throw;
1067 if (!indexed->AddKeyword(file, target, entry, load)) {
1068 //We already indexed the maximum number of keywords.
1069 //We do not index anymore but we still send a success..
1070 //Reason: Because if a VERY busy node tells the publisher it failed,
1071 //this busy node will spread to all the surrounding nodes causing popular
1072 //keywords to be stored on MANY nodes..
1073 //So, once we are full, we will periodically clean our list until we can
1074 //begin storing again..
1075 delete entry;
1076 entry = NULL;
1078 count--;
1080 CMemFile packetdata(17);
1081 packetdata.WriteUInt128(file);
1082 packetdata.WriteUInt8(load);
1083 DebugSend(Kad2PublishRes, ip, port);
1084 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1087 // KADEMLIA2_PUBLISH_SOURCE_REQ
1088 // Used in Kad2.0 only
1089 void CKademliaUDPListener::Process2PublishSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1091 //Used Pointers
1092 CIndexed *indexed = CKademlia::GetIndexed();
1094 // check if we are UDP firewalled
1095 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1096 //We are firewalled. We should not index this entry and give publisher a false report.
1097 return;
1100 CMemFile bio(packetData, lenPacket);
1101 CUInt128 file = bio.ReadUInt128();
1103 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1104 distance ^= file;
1106 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1107 return;
1110 DEBUG_ONLY( wxString strInfo; )
1111 uint8_t load = 0;
1112 bool flag = false;
1113 CUInt128 target = bio.ReadUInt128();
1114 Kademlia::CEntry* entry = new Kademlia::CEntry();
1115 try {
1116 entry->m_uIP = ip;
1117 entry->m_uUDPport = port;
1118 entry->m_uKeyID = file;
1119 entry->m_uSourceID = target;
1120 entry->m_bSource = false;
1121 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMES;
1122 bool addUDPPortTag = true;
1123 uint32_t tags = bio.ReadUInt8();
1124 while (tags > 0) {
1125 CTag* tag = bio.ReadTag();
1126 if (tag) {
1127 if (!tag->GetName().Cmp(TAG_SOURCETYPE)) {
1128 if (entry->m_bSource == false) {
1129 entry->AddTag(new CTagVarInt(TAG_SOURCEIP, entry->m_uIP));
1130 entry->AddTag(tag);
1131 entry->m_bSource = true;
1132 } else {
1133 //More than one sourcetype tag found.
1134 delete tag;
1136 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1137 if (entry->m_uSize == 0) {
1138 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1139 entry->m_uSize = PeekUInt64(tag->GetBsob());
1140 } else {
1141 entry->m_uSize = tag->GetInt();
1143 DEBUG_ONLY( strInfo += CFormat(wxT(" Size=%u")) % entry->m_uSize; )
1145 delete tag;
1146 } else if (!tag->GetName().Cmp(TAG_SOURCEPORT)) {
1147 if (entry->m_uTCPport == 0) {
1148 entry->m_uTCPport = (uint16_t)tag->GetInt();
1149 entry->AddTag(tag);
1150 } else {
1151 //More than one port tag found
1152 delete tag;
1154 } else if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
1155 if (addUDPPortTag && tag->IsInt() && tag->GetInt() != 0) {
1156 entry->m_uUDPport = (uint16_t)tag->GetInt();
1157 entry->AddTag(tag);
1158 addUDPPortTag = false;
1159 } else {
1160 //More than one udp port tag found
1161 delete tag;
1163 } else {
1164 //TODO: Filter tags
1165 entry->AddTag(tag);
1168 tags--;
1170 if (addUDPPortTag) {
1171 entry->AddTag(new CTagVarInt(TAG_SOURCEUPORT, entry->m_uUDPport));
1173 #ifdef __DEBUG__
1174 if (!strInfo.IsEmpty()) {
1175 AddDebugLogLineN(logClientKadUDP, strInfo);
1177 #endif
1178 } catch(...) {
1179 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishSourceRequest"),ip,port,packetData,lenPacket);
1180 delete entry;
1181 throw;
1184 if (entry->m_bSource == true) {
1185 if (indexed->AddSources(file, target, entry, load)) {
1186 flag = true;
1187 } else {
1188 delete entry;
1189 entry = NULL;
1191 } else {
1192 delete entry;
1193 entry = NULL;
1195 if (flag) {
1196 CMemFile packetdata(17);
1197 packetdata.WriteUInt128(file);
1198 packetdata.WriteUInt8(load);
1199 DebugSend(Kad2PublishRes, ip, port);
1200 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1204 // KADEMLIA_PUBLISH_RES
1205 // Used only by Kad1.0
1206 void CKademliaUDPListener::ProcessPublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1208 // Verify packet is expected size
1209 CHECK_PACKET_MIN_SIZE(16);
1210 CHECK_TRACKED_PACKET(KADEMLIA_PUBLISH_REQ);
1212 CMemFile bio(packetData, lenPacket);
1213 CUInt128 file = bio.ReadUInt128();
1215 bool loadResponse = false;
1216 uint8_t load = 0;
1217 if (bio.GetLength() > bio.GetPosition()) {
1218 loadResponse = true;
1219 load = bio.ReadUInt8();
1222 CSearchManager::ProcessPublishResult(file, load, loadResponse);
1225 // KADEMLIA2_PUBLISH_RES
1226 // Used only by Kad2.0
1227 void CKademliaUDPListener::Process2PublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1229 if (!IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_KEY_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_SOURCE_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_NOTES_REQ)) {
1230 throw wxString(CFormat(wxT("***NOTE: Received unrequested response packet, size (%u) in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__));
1232 CMemFile bio(packetData, lenPacket);
1233 CUInt128 file = bio.ReadUInt128();
1234 uint8_t load = bio.ReadUInt8();
1235 CSearchManager::ProcessPublishResult(file, load, true);
1236 if (bio.GetLength() > bio.GetPosition()) {
1237 // for future use
1238 uint8_t options = bio.ReadUInt8();
1239 bool requestACK = (options & 0x01) > 0;
1240 if (requestACK && !senderKey.IsEmpty()) {
1241 DebugSend(Kad2PublishResAck, ip, port);
1242 SendNullPacket(KADEMLIA2_PUBLISH_RES_ACK, ip, port, senderKey, NULL);
1247 // KADEMLIA2_SEARCH_NOTES_REQ
1248 // Used only by Kad2.0
1249 void CKademliaUDPListener::Process2SearchNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1251 CMemFile bio(packetData, lenPacket);
1252 CUInt128 target = bio.ReadUInt128();
1253 uint64_t fileSize = bio.ReadUInt64();
1254 CKademlia::GetIndexed()->SendValidNoteResult(target, ip, port, fileSize, senderKey);
1257 // KADEMLIA_SEARCH_NOTES_RES
1258 // Used only by Kad1.0
1259 void CKademliaUDPListener::ProcessSearchNotesResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1261 // Verify packet is expected size
1262 CHECK_PACKET_MIN_SIZE(37);
1263 CHECK_TRACKED_PACKET(KADEMLIA_SEARCH_NOTES_REQ);
1265 // What search does this relate to
1266 CMemFile bio(packetData, lenPacket);
1267 ProcessSearchResponse(bio);
1270 // KADEMLIA2_PUBLISH_NOTES_REQ
1271 // Used only by Kad2.0
1272 void CKademliaUDPListener::Process2PublishNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1274 // check if we are UDP firewalled
1275 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1276 //We are firewalled. We should not index this entry and give publisher a false report.
1277 return;
1280 CMemFile bio(packetData, lenPacket);
1281 CUInt128 target = bio.ReadUInt128();
1283 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1284 distance ^= target;
1286 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1287 return;
1290 CUInt128 source = bio.ReadUInt128();
1292 Kademlia::CEntry* entry = new Kademlia::CEntry();
1293 try {
1294 entry->m_uIP = ip;
1295 entry->m_uUDPport = port;
1296 entry->m_uKeyID = target;
1297 entry->m_uSourceID = source;
1298 entry->m_bSource = false;
1299 uint32_t tags = bio.ReadUInt8();
1300 while (tags > 0) {
1301 CTag* tag = bio.ReadTag();
1302 if(tag) {
1303 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1304 if (entry->GetCommonFileName().IsEmpty()) {
1305 entry->SetFileName(tag->GetStr());
1307 delete tag;
1308 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1309 if (entry->m_uSize == 0) {
1310 entry->m_uSize = tag->GetInt();
1312 delete tag;
1313 } else {
1314 //TODO: Filter tags
1315 entry->AddTag(tag);
1318 tags--;
1320 } catch(...) {
1321 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishNotesRequest"),ip,port,packetData,lenPacket);
1322 delete entry;
1323 entry = NULL;
1324 throw;
1327 uint8_t load = 0;
1328 if (CKademlia::GetIndexed()->AddNotes(target, source, entry, load)) {
1329 CMemFile packetdata(17);
1330 packetdata.WriteUInt128(target);
1331 packetdata.WriteUInt8(load);
1332 DebugSend(Kad2PublishRes, ip, port);
1333 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1334 } else {
1335 delete entry;
1339 // KADEMLIA_FIREWALLED_REQ
1340 // Used by Kad1.0 and Kad2.0
1341 void CKademliaUDPListener::ProcessFirewalledRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1343 // Verify packet is expected size
1344 CHECK_PACKET_EXACT_SIZE(2);
1346 CMemFile bio(packetData, lenPacket);
1347 uint16_t tcpport = bio.ReadUInt16();
1349 CUInt128 zero;
1350 CContact contact(zero, ip, port, tcpport, 0, 0, false, zero);
1351 if (!theApp->clientlist->RequestTCP(&contact, 0)) {
1352 return; // cancelled for some reason, don't send a response
1355 // Send response
1356 CMemFile packetdata(4);
1357 packetdata.WriteUInt32(ip);
1358 DebugSend(KadFirewalledRes, ip, port);
1359 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1362 // KADEMLIA_FIREWALLED2_REQ
1363 // Used by Kad2.0 Prot.Version 7+
1364 void CKademliaUDPListener::ProcessFirewalled2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1366 // Verify packet is expected size
1367 CHECK_PACKET_MIN_SIZE(19);
1369 CMemFile bio(packetData, lenPacket);
1370 uint16_t tcpPort = bio.ReadUInt16();
1371 CUInt128 userID = bio.ReadUInt128();
1372 uint8_t connectOptions = bio.ReadUInt8();
1374 CUInt128 zero;
1375 CContact contact(userID, ip, port, tcpPort, 0, 0, false, zero);
1376 if (!theApp->clientlist->RequestTCP(&contact, connectOptions)) {
1377 return; // cancelled for some reason, don't send a response
1380 // Send response
1381 CMemFile packetdata(4);
1382 packetdata.WriteUInt32(ip);
1383 DebugSend(KadFirewalledRes, ip, port);
1384 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1387 // KADEMLIA_FIREWALLED_RES
1388 // Used by Kad1.0 and Kad2.0
1389 void CKademliaUDPListener::ProcessFirewalledResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, const CKadUDPKey& WXUNUSED(senderKey))
1391 // Verify packet is expected size
1392 CHECK_PACKET_EXACT_SIZE(4);
1394 if (!theApp->clientlist->IsKadFirewallCheckIP(wxUINT32_SWAP_ALWAYS(ip))) { /* KADEMLIA_FIREWALLED2_REQ + KADEMLIA_FIREWALLED_REQ */
1395 throw wxString(wxT("Received unrequested firewall response packet in ")) + wxString::FromAscii(__FUNCTION__);
1398 CMemFile bio(packetData, lenPacket);
1399 uint32_t firewalledIP = bio.ReadUInt32();
1401 // Update con state only if something changes.
1402 if (CKademlia::GetPrefs()->GetIPAddress() != firewalledIP) {
1403 CKademlia::GetPrefs()->SetIPAddress(firewalledIP);
1404 theApp->ShowConnectionState();
1406 CKademlia::GetPrefs()->IncRecheckIP();
1409 // KADEMLIA_FIREWALLED_ACK_RES
1410 // Used by Kad1.0 and Kad2.0
1411 void CKademliaUDPListener::ProcessFirewalledAckResponse(uint32_t lenPacket)
1413 // Deprecated since KadVersion 7+, the result is now sent per TCP instead of UDP, because this will fail if our intern UDP port is unreachable.
1414 // But we want the TCP testresult regardless if UDP is firewalled, the new UDP state and test takes care of the rest.
1416 // Verify packet is expected size
1417 CHECK_PACKET_EXACT_SIZE(0);
1419 CKademlia::GetPrefs()->IncFirewalled();
1422 // KADEMLIA_FINDBUDDY_REQ
1423 // Used by Kad1.0 and Kad2.0
1424 void CKademliaUDPListener::ProcessFindBuddyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1426 // Verify packet is expected size
1427 CHECK_PACKET_MIN_SIZE(34);
1429 if (CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true) || !CUDPFirewallTester::IsVerified()) {
1430 // We are firewalled but somehow we still got this packet.. Don't send a response..
1431 return;
1432 } else if (theApp->clientlist->GetBuddyStatus() == Connected) {
1433 // we already have a buddy
1434 return;
1437 CMemFile bio(packetData, lenPacket);
1438 CUInt128 BuddyID = bio.ReadUInt128();
1439 CUInt128 userID = bio.ReadUInt128();
1440 uint16_t tcpport = bio.ReadUInt16();
1442 CUInt128 zero;
1443 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1444 if (!theApp->clientlist->IncomingBuddy(&contact, &BuddyID)) {
1445 return; // cancelled for some reason, don't send a response
1448 CMemFile packetdata(34);
1449 packetdata.WriteUInt128(BuddyID);
1450 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
1451 packetdata.WriteUInt16(thePrefs::GetPort());
1452 if (!senderKey.IsEmpty()) { // remove check for later versions
1453 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false)); // new since 0.49a, old mules will ignore it (hopefully ;) )
1456 DebugSend(KadFindBuddyRes, ip, port);
1457 SendPacket(packetdata, KADEMLIA_FINDBUDDY_RES, ip, port, senderKey, NULL);
1460 // KADEMLIA_FINDBUDDY_RES
1461 // Used by Kad1.0 and Kad2.0
1462 void CKademliaUDPListener::ProcessFindBuddyResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
1464 // Verify packet is expected size
1465 CHECK_PACKET_MIN_SIZE(34);
1466 CHECK_TRACKED_PACKET(KADEMLIA_FINDBUDDY_REQ);
1468 CMemFile bio(packetData, lenPacket);
1469 CUInt128 check = bio.ReadUInt128();
1470 check ^= CUInt128(true);
1471 if (CKademlia::GetPrefs()->GetKadID() == check) {
1472 CUInt128 userID = bio.ReadUInt128();
1473 uint16_t tcpport = bio.ReadUInt16();
1474 uint8_t connectOptions = 0;
1475 if (lenPacket > 34) {
1476 // 0.49+ (kad version 7) sends additionally its connect options so we know whether to use an obfuscated connection
1477 connectOptions = bio.ReadUInt8();
1480 CUInt128 zero;
1481 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1482 theApp->clientlist->RequestBuddy(&contact, connectOptions);
1486 // KADEMLIA_CALLBACK_REQ
1487 // Used by Kad1.0 and Kad2.0
1488 void CKademliaUDPListener::ProcessCallbackRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t WXUNUSED(port), const CKadUDPKey& WXUNUSED(senderKey))
1490 // Verify packet is expected size
1491 CHECK_PACKET_MIN_SIZE(34);
1493 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1494 if (buddy != NULL) {
1495 CMemFile bio(packetData, lenPacket);
1496 CUInt128 check = bio.ReadUInt128();
1497 // JOHNTODO: Begin filtering bad buddy ID's..
1498 // CUInt128 bud(buddy->GetBuddyID());
1499 CUInt128 file = bio.ReadUInt128();
1500 uint16_t tcp = bio.ReadUInt16();
1502 if (buddy->GetSocket()) {
1503 CMemFile packetdata(lenPacket + 6);
1504 packetdata.WriteUInt128(check);
1505 packetdata.WriteUInt128(file);
1506 packetdata.WriteUInt32(ip);
1507 packetdata.WriteUInt16(tcp);
1508 CPacket* packet = new CPacket(packetdata, OP_EMULEPROT, OP_CALLBACK);
1509 AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_CALLBACK to ") + KadIPToString(ip));
1510 buddy->GetSocket()->SendPacket(packet);
1511 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1512 } else {
1513 throw wxString::FromAscii(__FUNCTION__) + wxT(": Buddy has no valid socket");
1518 // KADEMLIA2_PING
1519 void CKademliaUDPListener::Process2Ping(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1521 // can be used just as PING, currently it is however only used to determine one's external port
1522 CMemFile packetdata(2);
1523 packetdata.WriteUInt16(port);
1524 DebugSend(Kad2Pong, ip, port);
1525 SendPacket(packetdata, KADEMLIA2_PONG, ip, port, senderKey, NULL);
1528 // KADEMLIA2_PONG
1529 void CKademliaUDPListener::Process2Pong(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1531 CHECK_PACKET_MIN_SIZE(2);
1532 CHECK_TRACKED_PACKET(KADEMLIA2_PING);
1534 // Is this one of our legacy challenge packets?
1535 CUInt128 contactID;
1536 if (IsLegacyChallenge(CUInt128((uint32_t)0), ip, KADEMLIA2_PING, contactID)) {
1537 // yup it is, set the contact as verified
1538 // cppcheck-suppress duplicateBranch
1539 if (!CKademlia::GetRoutingZone()->VerifyContact(contactID, ip)) {
1540 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
1541 } else {
1542 AddDebugLogLineN(logKadRouting, wxT("Verified contact with legacy challenge (Kad2Ping) - ") + KadIPToString(ip));
1544 return; // we do not actually care for its other content
1547 if (CKademlia::GetPrefs()->FindExternKadPort(false)) {
1548 // the reported port doesn't always have to be our true external port, esp. if we used our intern port
1549 // and communicated recently with the client some routers might remember this and assign the intern port as source
1550 // but this shouldn't be a problem because we prefer intern ports anyway.
1551 // might have to be reviewed in later versions when more data is available
1552 CKademlia::GetPrefs()->SetExternKadPort(PeekUInt16(packetData), ip);
1554 if (CUDPFirewallTester::IsFWCheckUDPRunning()) {
1555 CUDPFirewallTester::QueryNextClient();
1558 theApp->ShowConnectionState();
1561 // KADEMLIA2_FIREWALLUDP
1562 void CKademliaUDPListener::Process2FirewallUDP(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1564 // Verify packet is expected size
1565 CHECK_PACKET_MIN_SIZE(3);
1567 uint8_t errorCode = PeekUInt8(packetData);
1568 uint16_t incomingPort = PeekUInt16(packetData + 1);
1569 if ((incomingPort != CKademlia::GetPrefs()->GetExternalKadPort() && incomingPort != CKademlia::GetPrefs()->GetInternKadPort()) || incomingPort == 0) {
1570 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck on unexpected incoming port %u from %s")) % incomingPort % KadIPToString(ip));
1571 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
1572 } else if (errorCode == 0) {
1573 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck packet from %s with incoming port %u")) % KadIPToString(ip) % incomingPort);
1574 CUDPFirewallTester::SetUDPFWCheckResult(true, false, ip, incomingPort);
1575 } else {
1576 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck packet from %s with incoming port %u with remote errorcode %u - ignoring result"))
1577 % KadIPToString(ip) % incomingPort % errorCode);
1578 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
1582 void CKademliaUDPListener::SendPacket(const CMemFile &data, uint8_t opcode, uint32_t destinationHost, uint16_t destinationPort, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
1584 AddTrackedOutPacket(destinationHost, opcode);
1585 CPacket* packet = new CPacket(data, OP_KADEMLIAHEADER, opcode);
1586 if (packet->GetPacketSize() > 200) {
1587 packet->PackPacket();
1589 uint8_t cryptData[16];
1590 uint8_t *cryptKey;
1591 if (cryptTargetID != NULL) {
1592 cryptKey = (uint8_t *)&cryptData;
1593 cryptTargetID->StoreCryptValue(cryptKey);
1594 } else {
1595 cryptKey = NULL;
1597 theStats::AddUpOverheadKad(packet->GetPacketSize());
1598 theApp->clientudp->SendPacket(packet, wxUINT32_SWAP_ALWAYS(destinationHost), destinationPort, true, cryptKey, true, targetKey.GetKeyValue(theApp->GetPublicIP(false)));
1601 bool CKademliaUDPListener::FindNodeIDByIP(CKadClientSearcher* requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort)
1603 // send a hello packet to the given IP in order to get a HELLO_RES with the NodeID
1604 AddDebugLogLineN(logClientKadUDP, wxT("FindNodeIDByIP: Requesting NodeID from ") + KadIPToString(ip) + wxT(" by sending Kad2HelloReq"));
1605 DebugSend(Kad2HelloReq, ip, udpPort);
1606 SendMyDetails(KADEMLIA2_HELLO_REQ, ip, udpPort, 1, 0, NULL, false); // todo: we send this unobfuscated, which is not perfect, see this can be avoided in the future
1607 FetchNodeID_Struct sRequest = { ip, tcpPort, ::GetTickCount() + SEC2MS(60), requester };
1608 m_fetchNodeIDRequests.push_back(sRequest);
1609 return true;
1612 void CKademliaUDPListener::ExpireClientSearch(CKadClientSearcher* expireImmediately)
1614 uint32_t now = ::GetTickCount();
1615 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end();) {
1616 FetchNodeIDList::iterator it2 = it++;
1617 if (it2->requester == expireImmediately) {
1618 m_fetchNodeIDRequests.erase(it2);
1620 else if (it2->expire < now) {
1621 it2->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
1622 m_fetchNodeIDRequests.erase(it2);
1627 void CKademliaUDPListener::SendLegacyChallenge(uint32_t ip, uint16_t port, const CUInt128& contactID)
1629 // We want to verify that a pre-0.49a contact is valid and not sent from a spoofed IP.
1630 // Because those versions don't support any direct validating, we send a KAD_REQ with a random ID,
1631 // which is our challenge. If we receive an answer packet for this request, we can be sure the
1632 // contact is not spoofed
1633 #ifdef __DEBUG__
1634 CContact* contact = CKademlia::GetRoutingZone()->GetContact(contactID);
1635 if (contact != NULL) {
1636 if (contact->GetType() < 2) {
1637 AddDebugLogLineN(logKadRouting, wxT("Sending challenge to a long known contact (should be verified already) - ") + KadIPToString(ip));
1639 } else {
1640 wxFAIL;
1642 #endif
1644 if (HasActiveLegacyChallenge(ip)) {
1645 // don't send more than one challenge at a time
1646 return;
1648 CMemFile packetdata(33);
1649 packetdata.WriteUInt8(KADEMLIA_FIND_VALUE);
1650 CUInt128 challenge(GetRandomUint128());
1651 if (challenge == 0) {
1652 // hey there is a 2^128 chance that this happens ;)
1653 wxFAIL;
1654 challenge = 1;
1656 // Put the target we want into the packet. This is our challenge
1657 packetdata.WriteUInt128(challenge);
1658 // Add the ID of the contact we are contacting for sanity checks on the other end.
1659 packetdata.WriteUInt128(contactID);
1660 DebugSendF(wxT("Kad2Req(SendLegacyChallenge)"), ip, port);
1661 // those versions we send those requests to don't support encryption / obfuscation
1662 SendPacket(packetdata, KADEMLIA2_REQ, ip, port, 0, NULL);
1663 AddLegacyChallenge(contactID, challenge, ip, KADEMLIA2_REQ);
1666 void CKademliaUDPListener::DebugClientOutput(const wxString& place, uint32 kad_ip, uint32 port, const byte* data, int len)
1668 #if THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX
1669 uint32 ip = wxUINT32_SWAP_ALWAYS(kad_ip);
1670 printf("Error on %s received from: %s\n",(const char*)unicode2char(place),(const char*)unicode2char(Uint32_16toStringIP_Port(ip,port)));
1671 if (data) {
1672 printf("Packet dump:\n");
1673 DumpMem(data, len);
1675 CClientList::SourceList clientslist = theApp->clientlist->GetClientsByIP(ip);
1676 if (!clientslist.empty()) {
1677 for (CClientList::SourceList::iterator it = clientslist.begin(); it != clientslist.end(); ++it) {
1678 printf("Ip Matches: %s\n",(const char*)unicode2char((*it)->GetClientFullInfo()));
1680 } else {
1681 printf("No ip match, trying to create a client connection:\n");
1682 printf("Trying port %d\n", port - 10);
1683 CUpDownClient* client = new CUpDownClient(port-10,kad_ip,0,0,NULL,false,false);
1684 client->SetConnectionReason(wxT("Error on ") + place);
1685 client->TryToConnect(true);
1687 #else
1688 // No need for warnings for the rest of us.
1689 (void)place;
1690 (void)kad_ip;
1691 (void)port;
1692 (void)data;
1693 (void)len;
1694 #endif
1696 // File_checked_for_headers