Improve speed of category tab title updates
[amule.git] / src / kademlia / net / KademliaUDPListener.cpp
blob6b2a1dec304fdfa4444a9cb241cab6a664e538b8
1 //
2 // This file is part of aMule Project
3 //
4 // Copyright (c) 2004-2008 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2003-2008 Barry Dunne ( http://www.emule-project.net )
7 // Copyright (C)2007-2008 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()
70 #include <wx/tokenzr.h>
72 #define THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX 0
74 #if defined(__SUNPRO_CC)
75 #define __FUNCTION__ __FILE__+__LINE__
76 #endif
78 #define CHECK_PACKET_SIZE(OP, SIZE) \
79 if (lenPacket OP (uint32_t)(SIZE)) \
80 throw wxString(CFormat(wxT("***NOTE: Received wrong size (%u) packet in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__))
82 #define CHECK_PACKET_MIN_SIZE(SIZE) CHECK_PACKET_SIZE(<, SIZE)
83 #define CHECK_PACKET_EXACT_SIZE(SIZE) CHECK_PACKET_SIZE(!=, SIZE)
85 #define CHECK_TRACKED_PACKET(OPCODE) \
86 if (!IsOnOutTrackList(ip, OPCODE)) \
87 throw wxString(CFormat(wxT("***NOTE: Received unrequested response packet, size (%u) in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__))
90 ////////////////////////////////////////
91 using namespace Kademlia;
92 ////////////////////////////////////////
94 CKademliaUDPListener::~CKademliaUDPListener()
96 // report timeout to all pending FetchNodeIDRequests
97 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
98 it->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
102 // Used by Kad1.0 and Kad2.0
103 void CKademliaUDPListener::Bootstrap(uint32_t ip, uint16_t port, uint8_t kadVersion, const CUInt128* cryptTargetID)
105 wxASSERT(ip);
107 DebugSend(Kad2BootstrapReq, ip, port);
108 CMemFile bio(0);
109 if (kadVersion >= 6) {
110 SendPacket(bio, KADEMLIA2_BOOTSTRAP_REQ, ip, port, 0, cryptTargetID);
111 } else {
112 SendPacket(bio, KADEMLIA2_BOOTSTRAP_REQ, ip, port, 0, NULL);
116 // Used by Kad1.0 and Kad2.0
117 void CKademliaUDPListener::SendMyDetails(uint8_t opcode, uint32_t ip, uint16_t port, uint8_t kadVersion, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID, bool requestAckPacket)
119 CMemFile packetdata;
120 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
122 if (kadVersion > 1) {
123 packetdata.WriteUInt16(thePrefs::GetPort());
124 packetdata.WriteUInt8(KADEMLIA_VERSION);
125 // Tag Count.
126 uint8_t tagCount = 0;
127 if (!CKademlia::GetPrefs()->GetUseExternKadPort()) {
128 tagCount++;
130 if (kadVersion >= 8 && (requestAckPacket || CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true))) {
131 tagCount++;
133 packetdata.WriteUInt8(tagCount);
134 if (!CKademlia::GetPrefs()->GetUseExternKadPort()) {
135 packetdata.WriteTag(CTagVarInt(TAG_SOURCEUPORT, CKademlia::GetPrefs()->GetInternKadPort()));
137 if (kadVersion >= 8 && (requestAckPacket || CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true))) {
138 // 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)
139 // 5 - reserved (!)
140 // 1 - requesting HELLO_RES_ACK
141 // 1 - TCP firewalled
142 // 1 - UDP firewalled
143 packetdata.WriteTag(CTagVarInt(TAG_KADMISCOPTIONS, (uint8_t)(
144 (requestAckPacket ? 1 : 0) << 2 |
145 (CKademlia::GetPrefs()->GetFirewalled() ? 1 : 0) << 1 |
146 (CUDPFirewallTester::IsFirewalledUDP(true) ? 1 : 0)
147 )));
149 if (kadVersion >= 6) {
150 if (cryptTargetID == NULL || *cryptTargetID == 0) {
151 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Sending hello response to crypt enabled Kad Node which provided an empty NodeID: %s (%u)")) % KadIPToString(ip) % kadVersion);
152 SendPacket(packetdata, opcode, ip, port, targetKey, NULL);
153 } else {
154 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
156 } else {
157 SendPacket(packetdata, opcode, ip, port, 0, NULL);
158 wxASSERT(targetKey.IsEmpty());
160 } else {
161 wxFAIL;
165 // Kad1.0 and Kad2.0 currently.
166 void CKademliaUDPListener::FirewalledCheck(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, uint8_t kadVersion)
168 if (kadVersion > 6) {
169 // new opcode since 0.49a with extended informations to support obfuscated connections properly
170 CMemFile packetdata(19);
171 packetdata.WriteUInt16(thePrefs::GetPort());
172 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
173 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false));
174 DebugSend(KadFirewalled2Req, ip, port);
175 SendPacket(packetdata, KADEMLIA_FIREWALLED2_REQ, ip, port, senderKey, NULL);
176 } else {
177 CMemFile packetdata(2);
178 packetdata.WriteUInt16(thePrefs::GetPort());
179 DebugSend(KadFirewalledReq, ip, port);
180 SendPacket(packetdata, KADEMLIA_FIREWALLED_REQ, ip, port, senderKey, NULL);
182 theApp->clientlist->AddKadFirewallRequest(wxUINT32_SWAP_ALWAYS(ip));
185 void CKademliaUDPListener::SendNullPacket(uint8_t opcode, uint32_t ip, uint16_t port, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
187 CMemFile packetdata(0);
188 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
191 void CKademliaUDPListener::SendPublishSourcePacket(const CContact& contact, const CUInt128 &targetID, const CUInt128 &contactID, const TagPtrList& tags)
193 uint8_t opcode;
194 CMemFile packetdata;
195 packetdata.WriteUInt128(targetID);
196 if (contact.GetVersion() >= 4/*47c*/) {
197 opcode = KADEMLIA2_PUBLISH_SOURCE_REQ;
198 packetdata.WriteUInt128(contactID);
199 packetdata.WriteTagPtrList(tags);
200 DebugSend(Kad2PublishSrcReq, contact.GetIPAddress(), contact.GetUDPPort());
201 } else {
202 opcode = KADEMLIA_PUBLISH_REQ;
203 //We only use this for publishing sources now.. So we always send one here..
204 packetdata.WriteUInt16(1);
205 packetdata.WriteUInt128(contactID);
206 packetdata.WriteTagPtrList(tags);
207 DebugSend(KadPublishReq, contact.GetIPAddress(), contact.GetUDPPort());
209 if (contact.GetVersion() >= 6) { // obfuscated ?
210 CUInt128 clientID = contact.GetClientID();
211 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), contact.GetUDPKey(), &clientID);
212 } else {
213 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), 0, NULL);
217 void CKademliaUDPListener::ProcessPacket(const uint8_t* data, uint32_t lenData, uint32_t ip, uint16_t port, bool validReceiverKey, const CKadUDPKey& senderKey)
219 // we do not accept (<= 0.48a) unencrypted incoming packets from port 53 (DNS) to avoid attacks based on DNS protocol confusion
220 if (port == 53 && senderKey.IsEmpty()) {
221 AddDebugLogLineN(logKadPacketTracking, wxT("Dropping incoming unencrypted packet on port 53 (DNS), IP: ") + KadIPToString(ip));
222 return;
225 //Update connection state only when it changes.
226 bool curCon = CKademlia::GetPrefs()->HasHadContact();
227 CKademlia::GetPrefs()->SetLastContact();
228 CUDPFirewallTester::Connected();
229 if( curCon != CKademlia::GetPrefs()->HasHadContact()) {
230 theApp->ShowConnectionState();
233 uint8_t opcode = data[1];
234 const uint8_t *packetData = data + 2;
235 uint32_t lenPacket = lenData - 2;
237 if (!InTrackListIsAllowedPacket(ip, opcode, validReceiverKey)) {
238 return;
241 switch (opcode) {
242 case KADEMLIA2_BOOTSTRAP_REQ:
243 DebugRecv(Kad2BootstrapReq, ip, port);
244 Process2BootstrapRequest(ip, port, senderKey);
245 break;
246 case KADEMLIA2_BOOTSTRAP_RES:
247 DebugRecv(Kad2BootstrapRes, ip, port);
248 Process2BootstrapResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
249 break;
250 case KADEMLIA2_HELLO_REQ:
251 DebugRecv(Kad2HelloReq, ip, port);
252 Process2HelloRequest(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
253 break;
254 case KADEMLIA2_HELLO_RES:
255 DebugRecv(Kad2HelloRes, ip, port);
256 Process2HelloResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
257 break;
258 case KADEMLIA2_HELLO_RES_ACK:
259 DebugRecv(Kad2HelloResAck, ip, port);
260 Process2HelloResponseAck(packetData, lenPacket, ip, validReceiverKey);
261 break;
262 case KADEMLIA2_REQ:
263 DebugRecv(Kad2Req, ip, port);
264 ProcessKademlia2Request(packetData, lenPacket, ip, port, senderKey);
265 break;
266 case KADEMLIA2_RES:
267 DebugRecv(Kad2Res, ip, port);
268 ProcessKademlia2Response(packetData, lenPacket, ip, port, senderKey);
269 break;
270 case KADEMLIA2_SEARCH_NOTES_REQ:
271 DebugRecv(Kad2SearchNotesReq, ip, port);
272 Process2SearchNotesRequest(packetData, lenPacket, ip, port, senderKey);
273 break;
274 case KADEMLIA2_SEARCH_KEY_REQ:
275 DebugRecv(Kad2SearchKeyReq, ip, port);
276 Process2SearchKeyRequest(packetData, lenPacket, ip, port, senderKey);
277 break;
278 case KADEMLIA2_SEARCH_SOURCE_REQ:
279 DebugRecv(Kad2SearchSourceReq, ip, port);
280 Process2SearchSourceRequest(packetData, lenPacket, ip, port, senderKey);
281 break;
282 case KADEMLIA_SEARCH_RES:
283 DebugRecv(KadSearchRes, ip, port);
284 ProcessSearchResponse(packetData, lenPacket);
285 break;
286 case KADEMLIA_SEARCH_NOTES_RES:
287 DebugRecv(KadSearchNotesRes, ip, port);
288 ProcessSearchNotesResponse(packetData, lenPacket, ip);
289 break;
290 case KADEMLIA2_SEARCH_RES:
291 DebugRecv(Kad2SearchRes, ip, port);
292 Process2SearchResponse(packetData, lenPacket, senderKey);
293 break;
294 case KADEMLIA2_PUBLISH_NOTES_REQ:
295 DebugRecv(Kad2PublishNotesReq, ip, port);
296 Process2PublishNotesRequest(packetData, lenPacket, ip, port, senderKey);
297 break;
298 case KADEMLIA2_PUBLISH_KEY_REQ:
299 DebugRecv(Kad2PublishKeyReq, ip, port);
300 Process2PublishKeyRequest(packetData, lenPacket, ip, port, senderKey);
301 break;
302 case KADEMLIA2_PUBLISH_SOURCE_REQ:
303 DebugRecv(Kad2PublishSourceReq, ip, port);
304 Process2PublishSourceRequest(packetData, lenPacket, ip, port, senderKey);
305 break;
306 case KADEMLIA_PUBLISH_RES:
307 DebugRecv(KadPublishRes, ip, port);
308 ProcessPublishResponse(packetData, lenPacket, ip);
309 break;
310 case KADEMLIA2_PUBLISH_RES:
311 DebugRecv(Kad2PublishRes, ip, port);
312 Process2PublishResponse(packetData, lenPacket, ip, port, senderKey);
313 break;
314 case KADEMLIA_FIREWALLED_REQ:
315 DebugRecv(KadFirewalledReq, ip, port);
316 ProcessFirewalledRequest(packetData, lenPacket, ip, port, senderKey);
317 break;
318 case KADEMLIA_FIREWALLED2_REQ:
319 DebugRecv(KadFirewalled2Req, ip, port);
320 ProcessFirewalled2Request(packetData, lenPacket, ip, port, senderKey);
321 break;
322 case KADEMLIA_FIREWALLED_RES:
323 DebugRecv(KadFirewalledRes, ip, port);
324 ProcessFirewalledResponse(packetData, lenPacket, ip, senderKey);
325 break;
326 case KADEMLIA_FIREWALLED_ACK_RES:
327 DebugRecv(KadFirewalledAck, ip, port);
328 ProcessFirewalledAckResponse(lenPacket);
329 break;
330 case KADEMLIA_FINDBUDDY_REQ:
331 DebugRecv(KadFindBuddyReq, ip, port);
332 ProcessFindBuddyRequest(packetData, lenPacket, ip, port, senderKey);
333 break;
334 case KADEMLIA_FINDBUDDY_RES:
335 DebugRecv(KadFindBuddyRes, ip, port);
336 ProcessFindBuddyResponse(packetData, lenPacket, ip, port, senderKey);
337 break;
338 case KADEMLIA_CALLBACK_REQ:
339 DebugRecv(KadCallbackReq, ip, port);
340 ProcessCallbackRequest(packetData, lenPacket, ip, port, senderKey);
341 break;
342 case KADEMLIA2_PING:
343 DebugRecv(Kad2Ping, ip, port);
344 Process2Ping(ip, port, senderKey);
345 break;
346 case KADEMLIA2_PONG:
347 DebugRecv(Kad2Pong, ip, port);
348 Process2Pong(packetData, lenPacket, ip);
349 break;
350 case KADEMLIA2_FIREWALLUDP:
351 DebugRecv(Kad2FirewallUDP, ip, port);
352 Process2FirewallUDP(packetData, lenPacket, ip);
353 break;
355 // old Kad1 opcodes which we don't handle anymore
356 case KADEMLIA_BOOTSTRAP_REQ_DEPRECATED:
357 case KADEMLIA_BOOTSTRAP_RES_DEPRECATED:
358 case KADEMLIA_HELLO_REQ_DEPRECATED:
359 case KADEMLIA_HELLO_RES_DEPRECATED:
360 case KADEMLIA_REQ_DEPRECATED:
361 case KADEMLIA_RES_DEPRECATED:
362 case KADEMLIA_PUBLISH_NOTES_REQ_DEPRECATED:
363 case KADEMLIA_PUBLISH_NOTES_RES_DEPRECATED:
364 case KADEMLIA_SEARCH_REQ:
365 case KADEMLIA_PUBLISH_REQ:
366 case KADEMLIA_SEARCH_NOTES_REQ:
367 break;
369 default: {
370 throw wxString(CFormat(wxT("Unknown opcode %02x on CKademliaUDPListener::ProcessPacket()")) % opcode);
375 // Used only for Kad2.0
376 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)
378 if (outRequestsACK != 0) {
379 *outRequestsACK = false;
382 CMemFile bio(data, lenData);
383 CUInt128 id = bio.ReadUInt128();
384 if (outContactID != NULL) {
385 *outContactID = id;
387 uint16_t tport = bio.ReadUInt16();
388 uint8_t version = bio.ReadUInt8();
389 if (version == 0) {
390 throw wxString(CFormat(wxT("***NOTE: Received invalid Kademlia2 version (%u) in %s")) % version % wxString::FromAscii(__FUNCTION__));
392 if (outVersion != NULL) {
393 *outVersion = version;
395 bool udpFirewalled = false;
396 bool tcpFirewalled = false;
397 uint8_t tags = bio.ReadUInt8();
398 while (tags) {
399 CTag *tag = bio.ReadTag();
400 if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
401 if (tag->IsInt() && (uint16_t)tag->GetInt() > 0) {
402 port = tag->GetInt();
404 } else if (!tag->GetName().Cmp(TAG_KADMISCOPTIONS)) {
405 if (tag->IsInt() && tag->GetInt() > 0) {
406 udpFirewalled = (tag->GetInt() & 0x01) > 0;
407 tcpFirewalled = (tag->GetInt() & 0x02) > 0;
408 if ((tag->GetInt() & 0x04) > 0) {
409 if (outRequestsACK != NULL) {
410 if (version >= 8) {
411 *outRequestsACK = true;
413 } else {
414 wxFAIL;
419 delete tag;
420 --tags;
423 // check if we are waiting for informations (nodeid) about this client and if so inform the requester
424 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
425 if (it->ip == ip && it->tcpPort == tport) {
426 //AddDebugLogLineN(logKadMain, wxT("Result Addcontact: ") + id.ToHexString());
427 uint8_t uchID[16];
428 id.ToByteArray(uchID);
429 it->requester->KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, uchID);
430 m_fetchNodeIDRequests.erase(it);
431 break;
435 if (fromHelloReq && version >= 8) {
436 // this is just for statistic calculations. We try to determine the ratio of (UDP) firewalled users,
437 // by counting how many of all nodes which have us in their routing table (our own routing table is supposed
438 // to have no UDP firewalled nodes at all) and support the firewalled tag are firewalled themself.
439 // Obviously this only works if we are not firewalled ourself
440 CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(udpFirewalled);
441 CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(tcpFirewalled);
444 if (!udpFirewalled) { // do not add (or update) UDP firewalled sources to our routing table
445 return CKademlia::GetRoutingZone()->Add(id, ip, port, tport, version, udpKey, ipVerified, update, true);
446 } else {
447 AddDebugLogLineN(logKadRouting, wxT("Not adding firewalled client to routing table (") + KadIPToString(ip) + wxT(")"));
448 return false;
452 // KADEMLIA2_BOOTSTRAP_REQ
453 // Used only for Kad2.0
454 void CKademliaUDPListener::Process2BootstrapRequest(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
456 // Get some contacts to return
457 ContactList contacts;
458 uint16_t numContacts = (uint16_t)CKademlia::GetRoutingZone()->GetBootstrapContacts(&contacts, 20);
460 // Create response packet
461 //We only collect a max of 20 contacts here.. Max size is 521.
462 //2 + 25(20) + 19
463 CMemFile packetdata(521);
465 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
466 packetdata.WriteUInt16(thePrefs::GetPort());
467 packetdata.WriteUInt8(KADEMLIA_VERSION);
469 // Write packet info
470 packetdata.WriteUInt16(numContacts);
471 CContact *contact;
472 for (ContactList::const_iterator it = contacts.begin(); it != contacts.end(); ++it) {
473 contact = *it;
474 packetdata.WriteUInt128(contact->GetClientID());
475 packetdata.WriteUInt32(contact->GetIPAddress());
476 packetdata.WriteUInt16(contact->GetUDPPort());
477 packetdata.WriteUInt16(contact->GetTCPPort());
478 packetdata.WriteUInt8(contact->GetVersion());
481 // Send response
482 DebugSend(Kad2BootstrapRes, ip, port);
483 SendPacket(packetdata, KADEMLIA2_BOOTSTRAP_RES, ip, port, senderKey, NULL);
486 // KADEMLIA2_BOOTSTRAP_RES
487 // Used only for Kad2.0
488 void CKademliaUDPListener::Process2BootstrapResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
490 CHECK_TRACKED_PACKET(KADEMLIA2_BOOTSTRAP_REQ);
492 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
494 // How many contacts were given
495 CMemFile bio(packetData, lenPacket);
496 CUInt128 contactID = bio.ReadUInt128();
497 uint16_t tport = bio.ReadUInt16();
498 uint8_t version = bio.ReadUInt8();
499 // if we don't know any Contacts yet and try to Bootstrap, we assume that all contacts are verified,
500 // in order to speed up the connecting process. The attackvectors to exploit this are very small with no
501 // major effects, so that's a good trade
502 bool assumeVerified = CKademlia::GetRoutingZone()->GetNumContacts() == 0;
504 if (CKademlia::s_bootstrapList.empty()) {
505 routingZone->Add(contactID, ip, port, tport, version, senderKey, validReceiverKey, true, false);
507 //AddDebugLogLineN(logClientKadUDP, wxT("Inc Kad2 Bootstrap packet from ") + KadIPToString(ip));
509 uint16_t numContacts = bio.ReadUInt16();
510 while (numContacts) {
511 contactID = bio.ReadUInt128();
512 ip = bio.ReadUInt32();
513 port = bio.ReadUInt16();
514 tport = bio.ReadUInt16();
515 version = bio.ReadUInt8();
516 bool verified = assumeVerified;
517 routingZone->Add(contactID, ip, port, tport, version, 0, verified, false, false);
518 numContacts--;
522 // KADEMLIA2_HELLO_REQ
523 // Used in Kad2.0 only
524 void CKademliaUDPListener::Process2HelloRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
526 DEBUG_ONLY( uint16_t dbgOldUDPPort = port; )
527 uint8_t contactVersion = 0;
528 CUInt128 contactID;
529 bool addedOrUpdated = AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true, true, NULL, &contactID); // might change (udp)port, validReceiverKey
530 wxASSERT(contactVersion >= 2);
531 #ifdef __DEBUG__
532 if (dbgOldUDPPort != port) {
533 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("KadContact %s uses his internal (%u) instead external (%u) UDP Port")) % KadIPToString(ip) % port % dbgOldUDPPort);
535 #endif
537 DebugSend(Kad2HelloRes, ip, port);
538 // 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
539 // receiver key or is already verified in the routing table, we request an additional ACK package to complete a three-way-handshake and
540 // verify the remote IP
541 SendMyDetails(KADEMLIA2_HELLO_RES, ip, port, contactVersion, senderKey, &contactID, addedOrUpdated && !validReceiverKey);
543 if (addedOrUpdated && !validReceiverKey && contactVersion == 7 && !HasActiveLegacyChallenge(ip)) {
544 // Kad Version 7 doesn't support HELLO_RES_ACK but sender/receiver keys, so send a ping to validate
545 DebugSend(Kad2Ping, ip, port);
546 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
547 #ifdef __DEBUG__
548 CContact* contact = CKademlia::GetRoutingZone()->GetContact(contactID);
549 if (contact != NULL) {
550 if (contact->GetType() < 2) {
551 AddDebugLogLineN(logKadRouting, wxT("Sending (ping) challenge to a long known contact (should be verified already) - ") + KadIPToString(ip));
553 } else {
554 wxFAIL;
556 #endif
557 } else if (CKademlia::GetPrefs()->FindExternKadPort(false) && contactVersion > 5) { // do we need to find out our extern port?
558 DebugSend(Kad2Ping, ip, port);
559 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
562 if (addedOrUpdated && !validReceiverKey && contactVersion < 7 && !HasActiveLegacyChallenge(ip)) {
563 // we need to verify this contact but it doesn't support HELLO_RES_ACK nor keys, do a little workaround
564 SendLegacyChallenge(ip, port, contactID);
567 // Check if firewalled
568 if (CKademlia::GetPrefs()->GetRecheckIP()) {
569 FirewalledCheck(ip, port, senderKey, contactVersion);
573 // KADEMLIA2_HELLO_RES_ACK
574 // Used in Kad2.0 only
575 void CKademliaUDPListener::Process2HelloResponseAck(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, bool validReceiverKey)
577 CHECK_PACKET_MIN_SIZE(17);
578 CHECK_TRACKED_PACKET(KADEMLIA2_HELLO_RES);
580 if (!validReceiverKey) {
581 AddDebugLogLineN(logClientKadUDP, wxT("Receiver key is invalid! (sender: ") + KadIPToString(ip) + wxT(")"));
582 return;
585 // Additional packet to complete a three-way-handshake, making sure the remote contact is not using a spoofed ip.
586 CMemFile bio(packetData, lenPacket);
587 CUInt128 remoteID = bio.ReadUInt128();
588 if (!CKademlia::GetRoutingZone()->VerifyContact(remoteID, ip)) {
589 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
590 } else {
591 AddDebugLogLineN(logKadRouting, wxT("Verified contact (") + KadIPToString(ip) + wxT(") by HELLO_RES_ACK"));
595 // KADEMLIA2_HELLO_RES
596 // Used in Kad2.0 only
597 void CKademliaUDPListener::Process2HelloResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
599 CHECK_TRACKED_PACKET(KADEMLIA2_HELLO_REQ);
601 // Add or Update contact.
602 uint8_t contactVersion;
603 CUInt128 contactID;
604 bool sendACK = false;
605 bool addedOrUpdated = AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true, false, &sendACK, &contactID);
607 if (sendACK) {
608 // the client requested us to send an ACK packet, which proves that we're not a spoofed fake contact
609 // fulfill his wish
610 if (senderKey.IsEmpty()) {
611 // but we don't have a valid sender key - there is no point to reply in this case
612 // most likely a bug in the remote client
613 AddDebugLogLineN(logClientKadUDP, wxT("Remote client demands ACK, but didn't send any sender key! (sender: ") + KadIPToString(ip) + wxT(")"));
614 } else {
615 CMemFile packet(17);
616 packet.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
617 packet.WriteUInt8(0); // no tags at this time
618 DebugSend(Kad2HelloResAck, ip, port);
619 SendPacket(packet, KADEMLIA2_HELLO_RES_ACK, ip, port, senderKey, NULL);
621 } else if (addedOrUpdated && !validReceiverKey && contactVersion < 7) {
622 // even though this is supposably an answer to a request from us, there are still possibilities to spoof
623 // it, as long as the attacker knows that we would send a HELLO_REQ (which in this case is quite often),
624 // so for old Kad Version which doesn't support keys, we need
625 SendLegacyChallenge(ip, port, contactID);
628 // do we need to find out our extern port?
629 if (CKademlia::GetPrefs()->FindExternKadPort(false) && contactVersion > 5) {
630 DebugSend(Kad2Ping, ip, port);
631 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
634 // Check if firewalled
635 if (CKademlia::GetPrefs()->GetRecheckIP()) {
636 FirewalledCheck(ip, port, senderKey, contactVersion);
640 // KADEMLIA2_REQ
641 // Used in Kad2.0 only
642 void CKademliaUDPListener::ProcessKademlia2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
644 // Get target and type
645 CMemFile bio(packetData, lenPacket);
646 uint8_t type = bio.ReadUInt8();
647 type &= 0x1F;
648 if (type == 0) {
649 throw wxString(CFormat(wxT("***NOTE: Received wrong type (0x%02x) in %s")) % type % wxString::FromAscii(__FUNCTION__));
652 // This is the target node trying to be found.
653 CUInt128 target = bio.ReadUInt128();
654 // Convert Target to Distance as this is how we store contacts.
655 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
656 distance.XOR(target);
658 // This makes sure we are not mistaken identify. Some client may have fresh installed and have a new KadID.
659 CUInt128 check = bio.ReadUInt128();
660 if (CKademlia::GetPrefs()->GetKadID() == check) {
661 // Get required number closest to target
662 ContactMap results;
663 CKademlia::GetRoutingZone()->GetClosestTo(2, target, distance, type, &results);
664 uint8_t count = (uint8_t)results.size();
666 // Write response
667 // Max count is 32. size 817..
668 // 16 + 1 + 25(32)
669 CMemFile packetdata(817);
670 packetdata.WriteUInt128(target);
671 packetdata.WriteUInt8(count);
672 CContact *c;
673 for (ContactMap::const_iterator it = results.begin(); it != results.end(); ++it) {
674 c = it->second;
675 packetdata.WriteUInt128(c->GetClientID());
676 packetdata.WriteUInt32(c->GetIPAddress());
677 packetdata.WriteUInt16(c->GetUDPPort());
678 packetdata.WriteUInt16(c->GetTCPPort());
679 packetdata.WriteUInt8(c->GetVersion()); //<- Kad Version inserted to allow backward compatibility.
682 DebugSendF(CFormat(wxT("Kad2Res (count=%u)")) % count, ip, port);
683 SendPacket(packetdata, KADEMLIA2_RES, ip, port, senderKey, NULL);
687 // KADEMLIA2_RES
688 // Used in Kad2.0 only
689 void CKademliaUDPListener::ProcessKademlia2Response(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
691 CHECK_TRACKED_PACKET(KADEMLIA2_REQ);
693 // Used Pointers
694 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
696 // What search does this relate to
697 CMemFile bio(packetData, lenPacket);
698 CUInt128 target = bio.ReadUInt128();
699 uint8_t numContacts = bio.ReadUInt8();
701 // Is this one of our legacy challenge packets?
702 CUInt128 contactID;
703 if (IsLegacyChallenge(target, ip, KADEMLIA2_REQ, contactID)) {
704 // yup it is, set the contact as verified
705 if (!routingZone->VerifyContact(contactID, ip)) {
706 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
707 } else {
708 AddDebugLogLineN(logKadRouting, wxT("Verified contact with legacy challenge (Kad2Req) - ") + KadIPToString(ip));
710 return; // we do not actually care for its other content
712 // Verify packet is expected size
713 CHECK_PACKET_EXACT_SIZE(16+1 + (16+4+2+2+1)*numContacts);
715 // is this a search for firewallcheck ips?
716 bool isFirewallUDPCheckSearch = false;
717 if (CUDPFirewallTester::IsFWCheckUDPRunning() && CSearchManager::IsFWCheckUDPSearch(target)) {
718 isFirewallUDPCheckSearch = true;
721 DEBUG_ONLY( uint32_t ignoredCount = 0; )
722 DEBUG_ONLY( uint32_t kad1Count = 0; )
723 CScopedPtr<ContactList> results;
724 for (uint8_t i = 0; i < numContacts; i++) {
725 CUInt128 id = bio.ReadUInt128();
726 uint32_t contactIP = bio.ReadUInt32();
727 uint16_t contactPort = bio.ReadUInt16();
728 uint16_t tport = bio.ReadUInt16();
729 uint8_t version = bio.ReadUInt8();
730 uint32_t hostIP = wxUINT32_SWAP_ALWAYS(contactIP);
731 if (version > 1) { // Kad1 nodes are no longer accepted and ignored
732 if (::IsGoodIPPort(hostIP, contactPort)) {
733 if (!theApp->ipfilter->IsFiltered(hostIP) && !(contactPort == 53 && version <= 5) /*No DNS Port without encryption*/) {
734 if (isFirewallUDPCheckSearch) {
735 // UDP FirewallCheck searches are special. The point is we need an IP which we didn't sent a UDP message yet
736 // (or in the near future), so we do not try to add those contacts to our routingzone and we also don't
737 // deliver them back to the searchmanager (because he would UDP-ask them for further results), but only report
738 // them to FirewallChecker - this will of course cripple the search but thats not the point, since we only
739 // care for IPs and not the random set target
740 CUDPFirewallTester::AddPossibleTestContact(id, contactIP, contactPort, tport, target, version, 0, false);
741 } else {
742 bool verified = false;
743 bool wasAdded = routingZone->AddUnfiltered(id, contactIP, contactPort, tport, version, 0, verified, false, false);
744 CContact *temp = new CContact(id, contactIP, contactPort, tport, version, 0, false, target);
745 if (wasAdded || routingZone->IsAcceptableContact(temp)) {
746 results->push_back(temp);
747 } else {
748 DEBUG_ONLY( ignoredCount++; )
749 delete temp;
754 } else {
755 DEBUG_ONLY( kad1Count++; )
759 #ifdef __DEBUG__
760 if (ignoredCount > 0) {
761 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignored %u bad %s in routing answer from %s")) % ignoredCount % (ignoredCount > 1 ? wxT("contacts") : wxT("contact")) % KadIPToString(ip));
763 if (kad1Count > 0) {
764 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignored %u kad1 %s in routing answer from %s")) % kad1Count % (kad1Count > 1 ? wxT("contacts") : wxT("contact")) % KadIPToString(ip));
766 #endif
768 CSearchManager::ProcessResponse(target, ip, port, results.release());
771 void CKademliaUDPListener::Free(SSearchTerm* pSearchTerms)
773 if (pSearchTerms) {
774 Free(pSearchTerms->left);
775 Free(pSearchTerms->right);
776 delete pSearchTerms;
780 SSearchTerm* CKademliaUDPListener::CreateSearchExpressionTree(CMemFile& bio, int iLevel)
782 // the max. depth has to match our own limit for creating the search expression
783 // (see also 'ParsedSearchExpression' and 'GetSearchPacket')
784 if (iLevel >= 24){
785 AddDebugLogLineN(logKadSearch, wxT("***NOTE: Search expression tree exceeds depth limit!"));
786 return NULL;
788 iLevel++;
790 uint8_t op = bio.ReadUInt8();
791 if (op == 0x00) {
792 uint8_t boolop = bio.ReadUInt8();
793 if (boolop == 0x00) { // AND
794 SSearchTerm* pSearchTerm = new SSearchTerm;
795 pSearchTerm->type = SSearchTerm::AND;
796 //TRACE(" AND");
797 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
798 wxFAIL;
799 delete pSearchTerm;
800 return NULL;
802 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
803 wxFAIL;
804 Free(pSearchTerm->left);
805 delete pSearchTerm;
806 return NULL;
808 return pSearchTerm;
809 } else if (boolop == 0x01) { // OR
810 SSearchTerm* pSearchTerm = new SSearchTerm;
811 pSearchTerm->type = SSearchTerm::OR;
812 //TRACE(" OR");
813 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
814 wxFAIL;
815 delete pSearchTerm;
816 return NULL;
818 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
819 wxFAIL;
820 Free(pSearchTerm->left);
821 delete pSearchTerm;
822 return NULL;
824 return pSearchTerm;
825 } else if (boolop == 0x02) { // NOT
826 SSearchTerm* pSearchTerm = new SSearchTerm;
827 pSearchTerm->type = SSearchTerm::NOT;
828 //TRACE(" NOT");
829 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
830 wxFAIL;
831 delete pSearchTerm;
832 return NULL;
834 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
835 wxFAIL;
836 Free(pSearchTerm->left);
837 delete pSearchTerm;
838 return NULL;
840 return pSearchTerm;
841 } else {
842 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown boolean search operator 0x%02x (CreateSearchExpressionTree)")) % boolop);
843 return NULL;
845 } else if (op == 0x01) { // String
846 wxString str(bio.ReadString(true));
848 // Make lowercase, the search code expects lower case strings!
849 str.MakeLower();
851 SSearchTerm* pSearchTerm = new SSearchTerm;
852 pSearchTerm->type = SSearchTerm::String;
853 pSearchTerm->astr = new wxArrayString;
855 // pre-tokenize the string term
856 //#warning TODO: TokenizeOptQuotedSearchTerm
857 wxStringTokenizer token(str, CSearchManager::GetInvalidKeywordChars(),wxTOKEN_DEFAULT );
858 while (token.HasMoreTokens()) {
859 wxString strTok(token.GetNextToken());
860 if (!strTok.IsEmpty()) {
861 pSearchTerm->astr->Add(strTok);
865 return pSearchTerm;
866 } else if (op == 0x02) { // Meta tag
867 // read tag value
868 wxString strValue(bio.ReadString(true));
869 // Make lowercase, the search code expects lower case strings!
870 strValue.MakeLower();
872 // read tag name
873 wxString strTagName = bio.ReadString(false);
875 SSearchTerm* pSearchTerm = new SSearchTerm;
876 pSearchTerm->type = SSearchTerm::MetaTag;
877 pSearchTerm->tag = new CTagString(strTagName, strValue);
878 return pSearchTerm;
880 else if (op == 0x03 || op == 0x08) { // Numeric relation (0x03=32-bit or 0x08=64-bit)
881 static const struct {
882 SSearchTerm::ESearchTermType eSearchTermOp;
883 wxString pszOp;
884 } _aOps[] =
886 { SSearchTerm::OpEqual, wxT("=") }, // mmop=0x00
887 { SSearchTerm::OpGreater, wxT(">") }, // mmop=0x01
888 { SSearchTerm::OpLess, wxT("<") }, // mmop=0x02
889 { SSearchTerm::OpGreaterEqual, wxT(">=") }, // mmop=0x03
890 { SSearchTerm::OpLessEqual, wxT("<=") }, // mmop=0x04
891 { SSearchTerm::OpNotEqual, wxT("<>") } // mmop=0x05
894 // read tag value
895 uint64_t ullValue = (op == 0x03) ? bio.ReadUInt32() : bio.ReadUInt64();
897 // read integer operator
898 uint8_t mmop = bio.ReadUInt8();
899 if (mmop >= itemsof(_aOps)){
900 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown integer search op=0x%02x (CreateSearchExpressionTree)")) % mmop);
901 return NULL;
904 // read tag name
905 wxString strTagName = bio.ReadString(false);
907 SSearchTerm* pSearchTerm = new SSearchTerm;
908 pSearchTerm->type = _aOps[mmop].eSearchTermOp;
909 pSearchTerm->tag = new CTagVarInt(strTagName, ullValue);
911 return pSearchTerm;
912 } else {
913 AddDebugLogLineN(logKadSearch, CFormat(wxT("*** Unknown search op=0x%02x (CreateSearchExpressionTree)")) % op);
914 return NULL;
918 // KADEMLIA2_SEARCH_KEY_REQ
919 // Used in Kad2.0 only
920 void CKademliaUDPListener::Process2SearchKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
922 CMemFile bio(packetData, lenPacket);
923 CUInt128 target = bio.ReadUInt128();
924 uint16_t startPosition = bio.ReadUInt16();
925 bool restrictive = ((startPosition & 0x8000) == 0x8000);
926 startPosition &= 0x7FFF;
927 SSearchTerm* pSearchTerms = NULL;
928 if (restrictive) {
929 pSearchTerms = CreateSearchExpressionTree(bio, 0);
930 if (pSearchTerms == NULL) {
931 throw wxString(wxT("Invalid search expression"));
934 CKademlia::GetIndexed()->SendValidKeywordResult(target, pSearchTerms, ip, port, false, startPosition, senderKey);
935 if (pSearchTerms) {
936 Free(pSearchTerms);
940 // KADEMLIA2_SEARCH_SOURCE_REQ
941 // Used in Kad2.0 only
942 void CKademliaUDPListener::Process2SearchSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
944 CMemFile bio(packetData, lenPacket);
945 CUInt128 target = bio.ReadUInt128();
946 uint16_t startPosition = (bio.ReadUInt16() & 0x7FFF);
947 uint64_t fileSize = bio.ReadUInt64();
948 CKademlia::GetIndexed()->SendValidSourceResult(target, ip, port, startPosition, fileSize, senderKey);
951 void CKademliaUDPListener::ProcessSearchResponse(CMemFile& bio)
953 // What search does this relate to
954 CUInt128 target = bio.ReadUInt128();
956 // How many results..
957 uint16_t count = bio.ReadUInt16();
958 while (count > 0) {
959 // What is the answer
960 CUInt128 answer = bio.ReadUInt128();
962 // Get info about answer
963 // NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
964 // case we did not receive an UTF8 string. this is for backward compatibility for search results which are
965 // supposed to be 'viewed' by user only and not feed into the Kad engine again!
966 // If that tag list is once used for something else than for viewing, special care has to be taken for any
967 // string conversion!
968 CScopedContainer<TagPtrList> tags;
969 bio.ReadTagPtrList(tags.get(), true/*bOptACP*/);
970 CSearchManager::ProcessResult(target, answer, tags.get());
971 count--;
976 // KADEMLIA_SEARCH_RES
977 // Used in Kad1.0 only
978 void CKademliaUDPListener::ProcessSearchResponse(const uint8_t *packetData, uint32_t lenPacket)
980 // Verify packet is expected size
981 CHECK_PACKET_MIN_SIZE(37);
983 CMemFile bio(packetData, lenPacket);
984 ProcessSearchResponse(bio);
987 // KADEMLIA2_SEARCH_RES
988 // Used in Kad2.0 only
989 void CKademliaUDPListener::Process2SearchResponse(const uint8_t *packetData, uint32_t lenPacket, const CKadUDPKey& WXUNUSED(senderKey))
991 CMemFile bio(packetData, lenPacket);
993 // Who sent this packet.
994 CUInt128 source = bio.ReadUInt128();
996 ProcessSearchResponse(bio);
999 // KADEMLIA2_PUBLISH_KEY_REQ
1000 // Used in Kad2.0 only
1001 void CKademliaUDPListener::Process2PublishKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1003 //Used Pointers
1004 CIndexed *indexed = CKademlia::GetIndexed();
1006 // check if we are UDP firewalled
1007 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1008 //We are firewalled. We should not index this entry and give publisher a false report.
1009 return;
1012 CMemFile bio(packetData, lenPacket);
1013 CUInt128 file = bio.ReadUInt128();
1015 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1016 distance.XOR(file);
1018 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1019 return;
1022 DEBUG_ONLY( wxString strInfo; )
1023 uint16_t count = bio.ReadUInt16();
1024 uint8_t load = 0;
1025 while (count > 0) {
1026 DEBUG_ONLY( strInfo.Clear(); )
1028 CUInt128 target = bio.ReadUInt128();
1030 Kademlia::CKeyEntry* entry = new Kademlia::CKeyEntry();
1033 entry->m_uIP = ip;
1034 entry->m_uUDPport = port;
1035 entry->m_uKeyID.SetValue(file);
1036 entry->m_uSourceID.SetValue(target);
1037 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMEK;
1038 entry->m_bSource = false;
1039 uint32_t tags = bio.ReadUInt8();
1040 while (tags > 0) {
1041 CTag* tag = bio.ReadTag();
1042 if (tag) {
1043 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1044 if (entry->GetCommonFileName().IsEmpty()) {
1045 entry->SetFileName(tag->GetStr());
1046 DEBUG_ONLY( strInfo += CFormat(wxT(" Name=\"%s\"")) % entry->GetCommonFileName(); )
1048 delete tag; // tag is no longer stored, but membervar is used
1049 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1050 if (entry->m_uSize == 0) {
1051 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1052 entry->m_uSize = PeekUInt64(tag->GetBsob());
1053 } else {
1054 entry->m_uSize = tag->GetInt();
1056 DEBUG_ONLY( strInfo += CFormat(wxT(" Size=%u")) % entry->m_uSize; )
1058 delete tag; // tag is no longer stored, but membervar is used
1059 } else {
1060 //TODO: Filter tags
1061 entry->AddTag(tag);
1064 tags--;
1066 #ifdef __DEBUG__
1067 if (!strInfo.IsEmpty()) {
1068 AddDebugLogLineN(logClientKadUDP, strInfo);
1070 #endif
1071 } catch(...) {
1072 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishKeyRequest"),ip,port,packetData,lenPacket);
1073 delete entry;
1074 throw;
1077 if (!indexed->AddKeyword(file, target, entry, load)) {
1078 //We already indexed the maximum number of keywords.
1079 //We do not index anymore but we still send a success..
1080 //Reason: Because if a VERY busy node tells the publisher it failed,
1081 //this busy node will spread to all the surrounding nodes causing popular
1082 //keywords to be stored on MANY nodes..
1083 //So, once we are full, we will periodically clean our list until we can
1084 //begin storing again..
1085 delete entry;
1086 entry = NULL;
1088 count--;
1090 CMemFile packetdata(17);
1091 packetdata.WriteUInt128(file);
1092 packetdata.WriteUInt8(load);
1093 DebugSend(Kad2PublishRes, ip, port);
1094 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1097 // KADEMLIA2_PUBLISH_SOURCE_REQ
1098 // Used in Kad2.0 only
1099 void CKademliaUDPListener::Process2PublishSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1101 //Used Pointers
1102 CIndexed *indexed = CKademlia::GetIndexed();
1104 // check if we are UDP firewalled
1105 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1106 //We are firewalled. We should not index this entry and give publisher a false report.
1107 return;
1110 CMemFile bio(packetData, lenPacket);
1111 CUInt128 file = bio.ReadUInt128();
1113 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1114 distance.XOR(file);
1116 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1117 return;
1120 DEBUG_ONLY( wxString strInfo; )
1121 uint8_t load = 0;
1122 bool flag = false;
1123 CUInt128 target = bio.ReadUInt128();
1124 Kademlia::CEntry* entry = new Kademlia::CEntry();
1125 try {
1126 entry->m_uIP = ip;
1127 entry->m_uUDPport = port;
1128 entry->m_uKeyID.SetValue(file);
1129 entry->m_uSourceID.SetValue(target);
1130 entry->m_bSource = false;
1131 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMES;
1132 bool addUDPPortTag = true;
1133 uint32_t tags = bio.ReadUInt8();
1134 while (tags > 0) {
1135 CTag* tag = bio.ReadTag();
1136 if (tag) {
1137 if (!tag->GetName().Cmp(TAG_SOURCETYPE)) {
1138 if (entry->m_bSource == false) {
1139 entry->AddTag(new CTagVarInt(TAG_SOURCEIP, entry->m_uIP));
1140 entry->AddTag(tag);
1141 entry->m_bSource = true;
1142 } else {
1143 //More than one sourcetype tag found.
1144 delete tag;
1146 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1147 if (entry->m_uSize == 0) {
1148 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1149 entry->m_uSize = PeekUInt64(tag->GetBsob());
1150 } else {
1151 entry->m_uSize = tag->GetInt();
1153 DEBUG_ONLY( strInfo += CFormat(wxT(" Size=%u")) % entry->m_uSize; )
1155 delete tag;
1156 } else if (!tag->GetName().Cmp(TAG_SOURCEPORT)) {
1157 if (entry->m_uTCPport == 0) {
1158 entry->m_uTCPport = (uint16_t)tag->GetInt();
1159 entry->AddTag(tag);
1160 } else {
1161 //More than one port tag found
1162 delete tag;
1164 } else if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
1165 if (addUDPPortTag && tag->IsInt() && tag->GetInt() != 0) {
1166 entry->m_uUDPport = (uint16_t)tag->GetInt();
1167 entry->AddTag(tag);
1168 addUDPPortTag = false;
1169 } else {
1170 //More than one udp port tag found
1171 delete tag;
1173 } else {
1174 //TODO: Filter tags
1175 entry->AddTag(tag);
1178 tags--;
1180 if (addUDPPortTag) {
1181 entry->AddTag(new CTagVarInt(TAG_SOURCEUPORT, entry->m_uUDPport));
1183 #ifdef __DEBUG__
1184 if (!strInfo.IsEmpty()) {
1185 AddDebugLogLineN(logClientKadUDP, strInfo);
1187 #endif
1188 } catch(...) {
1189 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishSourceRequest"),ip,port,packetData,lenPacket);
1190 delete entry;
1191 throw;
1194 if (entry->m_bSource == true) {
1195 if (indexed->AddSources(file, target, entry, load)) {
1196 flag = true;
1197 } else {
1198 delete entry;
1199 entry = NULL;
1201 } else {
1202 delete entry;
1203 entry = NULL;
1205 if (flag) {
1206 CMemFile packetdata(17);
1207 packetdata.WriteUInt128(file);
1208 packetdata.WriteUInt8(load);
1209 DebugSend(Kad2PublishRes, ip, port);
1210 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1214 // KADEMLIA_PUBLISH_RES
1215 // Used only by Kad1.0
1216 void CKademliaUDPListener::ProcessPublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1218 // Verify packet is expected size
1219 CHECK_PACKET_MIN_SIZE(16);
1220 CHECK_TRACKED_PACKET(KADEMLIA_PUBLISH_REQ);
1222 CMemFile bio(packetData, lenPacket);
1223 CUInt128 file = bio.ReadUInt128();
1225 bool loadResponse = false;
1226 uint8_t load = 0;
1227 if (bio.GetLength() > bio.GetPosition()) {
1228 loadResponse = true;
1229 load = bio.ReadUInt8();
1232 CSearchManager::ProcessPublishResult(file, load, loadResponse);
1235 // KADEMLIA2_PUBLISH_RES
1236 // Used only by Kad2.0
1237 void CKademliaUDPListener::Process2PublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1239 if (!IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_KEY_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_SOURCE_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_NOTES_REQ)) {
1240 throw wxString(CFormat(wxT("***NOTE: Received unrequested response packet, size (%u) in %s")) % lenPacket % wxString::FromAscii(__FUNCTION__));
1242 CMemFile bio(packetData, lenPacket);
1243 CUInt128 file = bio.ReadUInt128();
1244 uint8_t load = bio.ReadUInt8();
1245 CSearchManager::ProcessPublishResult(file, load, true);
1246 if (bio.GetLength() > bio.GetPosition()) {
1247 // for future use
1248 uint8_t options = bio.ReadUInt8();
1249 bool requestACK = (options & 0x01) > 0;
1250 if (requestACK && !senderKey.IsEmpty()) {
1251 DebugSend(Kad2PublishResAck, ip, port);
1252 SendNullPacket(KADEMLIA2_PUBLISH_RES_ACK, ip, port, senderKey, NULL);
1257 // KADEMLIA2_SEARCH_NOTES_REQ
1258 // Used only by Kad2.0
1259 void CKademliaUDPListener::Process2SearchNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1261 CMemFile bio(packetData, lenPacket);
1262 CUInt128 target = bio.ReadUInt128();
1263 uint64_t fileSize = bio.ReadUInt64();
1264 CKademlia::GetIndexed()->SendValidNoteResult(target, ip, port, fileSize, senderKey);
1267 // KADEMLIA_SEARCH_NOTES_RES
1268 // Used only by Kad1.0
1269 void CKademliaUDPListener::ProcessSearchNotesResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1271 // Verify packet is expected size
1272 CHECK_PACKET_MIN_SIZE(37);
1273 CHECK_TRACKED_PACKET(KADEMLIA_SEARCH_NOTES_REQ);
1275 // What search does this relate to
1276 CMemFile bio(packetData, lenPacket);
1277 ProcessSearchResponse(bio);
1280 // KADEMLIA2_PUBLISH_NOTES_REQ
1281 // Used only by Kad2.0
1282 void CKademliaUDPListener::Process2PublishNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1284 // check if we are UDP firewalled
1285 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1286 //We are firewalled. We should not index this entry and give publisher a false report.
1287 return;
1290 CMemFile bio(packetData, lenPacket);
1291 CUInt128 target = bio.ReadUInt128();
1293 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1294 distance.XOR(target);
1296 if (distance.Get32BitChunk(0) > SEARCHTOLERANCE && !::IsLanIP(wxUINT32_SWAP_ALWAYS(ip))) {
1297 return;
1300 CUInt128 source = bio.ReadUInt128();
1302 Kademlia::CEntry* entry = new Kademlia::CEntry();
1303 try {
1304 entry->m_uIP = ip;
1305 entry->m_uUDPport = port;
1306 entry->m_uKeyID.SetValue(target);
1307 entry->m_uSourceID.SetValue(source);
1308 entry->m_bSource = false;
1309 uint32_t tags = bio.ReadUInt8();
1310 while (tags > 0) {
1311 CTag* tag = bio.ReadTag();
1312 if(tag) {
1313 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1314 if (entry->GetCommonFileName().IsEmpty()) {
1315 entry->SetFileName(tag->GetStr());
1317 delete tag;
1318 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1319 if (entry->m_uSize == 0) {
1320 entry->m_uSize = tag->GetInt();
1322 delete tag;
1323 } else {
1324 //TODO: Filter tags
1325 entry->AddTag(tag);
1328 tags--;
1330 } catch(...) {
1331 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishNotesRequest"),ip,port,packetData,lenPacket);
1332 delete entry;
1333 entry = NULL;
1334 throw;
1337 uint8_t load = 0;
1338 if (CKademlia::GetIndexed()->AddNotes(target, source, entry, load)) {
1339 CMemFile packetdata(17);
1340 packetdata.WriteUInt128(target);
1341 packetdata.WriteUInt8(load);
1342 DebugSend(Kad2PublishRes, ip, port);
1343 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1344 } else {
1345 delete entry;
1349 // KADEMLIA_FIREWALLED_REQ
1350 // Used by Kad1.0 and Kad2.0
1351 void CKademliaUDPListener::ProcessFirewalledRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1353 // Verify packet is expected size
1354 CHECK_PACKET_EXACT_SIZE(2);
1356 CMemFile bio(packetData, lenPacket);
1357 uint16_t tcpport = bio.ReadUInt16();
1359 CUInt128 zero;
1360 CContact contact(zero, ip, port, tcpport, 0, 0, false, zero);
1361 if (!theApp->clientlist->RequestTCP(&contact, 0)) {
1362 return; // cancelled for some reason, don't send a response
1365 // Send response
1366 CMemFile packetdata(4);
1367 packetdata.WriteUInt32(ip);
1368 DebugSend(KadFirewalledRes, ip, port);
1369 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1372 // KADEMLIA_FIREWALLED2_REQ
1373 // Used by Kad2.0 Prot.Version 7+
1374 void CKademliaUDPListener::ProcessFirewalled2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1376 // Verify packet is expected size
1377 CHECK_PACKET_MIN_SIZE(19);
1379 CMemFile bio(packetData, lenPacket);
1380 uint16_t tcpPort = bio.ReadUInt16();
1381 CUInt128 userID = bio.ReadUInt128();
1382 uint8_t connectOptions = bio.ReadUInt8();
1384 CUInt128 zero;
1385 CContact contact(userID, ip, port, tcpPort, 0, 0, false, zero);
1386 if (!theApp->clientlist->RequestTCP(&contact, connectOptions)) {
1387 return; // cancelled for some reason, don't send a response
1390 // Send response
1391 CMemFile packetdata(4);
1392 packetdata.WriteUInt32(ip);
1393 DebugSend(KadFirewalledRes, ip, port);
1394 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1397 // KADEMLIA_FIREWALLED_RES
1398 // Used by Kad1.0 and Kad2.0
1399 void CKademliaUDPListener::ProcessFirewalledResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, const CKadUDPKey& WXUNUSED(senderKey))
1401 // Verify packet is expected size
1402 CHECK_PACKET_EXACT_SIZE(4);
1404 if (!theApp->clientlist->IsKadFirewallCheckIP(wxUINT32_SWAP_ALWAYS(ip))) { /* KADEMLIA_FIREWALLED2_REQ + KADEMLIA_FIREWALLED_REQ */
1405 throw wxString(wxT("Received unrequested firewall response packet in ")) + wxString::FromAscii(__FUNCTION__);
1408 CMemFile bio(packetData, lenPacket);
1409 uint32_t firewalledIP = bio.ReadUInt32();
1411 // Update con state only if something changes.
1412 if (CKademlia::GetPrefs()->GetIPAddress() != firewalledIP) {
1413 CKademlia::GetPrefs()->SetIPAddress(firewalledIP);
1414 theApp->ShowConnectionState();
1416 CKademlia::GetPrefs()->IncRecheckIP();
1419 // KADEMLIA_FIREWALLED_ACK_RES
1420 // Used by Kad1.0 and Kad2.0
1421 void CKademliaUDPListener::ProcessFirewalledAckResponse(uint32_t lenPacket)
1423 // 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.
1424 // But we want the TCP testresult regardless if UDP is firewalled, the new UDP state and test takes care of the rest.
1426 // Verify packet is expected size
1427 CHECK_PACKET_EXACT_SIZE(0);
1429 CKademlia::GetPrefs()->IncFirewalled();
1432 // KADEMLIA_FINDBUDDY_REQ
1433 // Used by Kad1.0 and Kad2.0
1434 void CKademliaUDPListener::ProcessFindBuddyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1436 // Verify packet is expected size
1437 CHECK_PACKET_MIN_SIZE(34);
1439 if (CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true) || !CUDPFirewallTester::IsVerified()) {
1440 // We are firewalled but somehow we still got this packet.. Don't send a response..
1441 return;
1442 } else if (theApp->clientlist->GetBuddyStatus() == Connected) {
1443 // we already have a buddy
1444 return;
1447 CMemFile bio(packetData, lenPacket);
1448 CUInt128 BuddyID = bio.ReadUInt128();
1449 CUInt128 userID = bio.ReadUInt128();
1450 uint16_t tcpport = bio.ReadUInt16();
1452 CUInt128 zero;
1453 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1454 if (!theApp->clientlist->IncomingBuddy(&contact, &BuddyID)) {
1455 return; // cancelled for some reason, don't send a response
1458 CMemFile packetdata(34);
1459 packetdata.WriteUInt128(BuddyID);
1460 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
1461 packetdata.WriteUInt16(thePrefs::GetPort());
1462 if (!senderKey.IsEmpty()) { // remove check for later versions
1463 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false)); // new since 0.49a, old mules will ignore it (hopefully ;) )
1466 DebugSend(KadFindBuddyRes, ip, port);
1467 SendPacket(packetdata, KADEMLIA_FINDBUDDY_RES, ip, port, senderKey, NULL);
1470 // KADEMLIA_FINDBUDDY_RES
1471 // Used by Kad1.0 and Kad2.0
1472 void CKademliaUDPListener::ProcessFindBuddyResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
1474 // Verify packet is expected size
1475 CHECK_PACKET_MIN_SIZE(34);
1476 CHECK_TRACKED_PACKET(KADEMLIA_FINDBUDDY_REQ);
1478 CMemFile bio(packetData, lenPacket);
1479 CUInt128 check = bio.ReadUInt128();
1480 check.XOR(CUInt128(true));
1481 if (CKademlia::GetPrefs()->GetKadID() == check) {
1482 CUInt128 userID = bio.ReadUInt128();
1483 uint16_t tcpport = bio.ReadUInt16();
1484 uint8_t connectOptions = 0;
1485 if (lenPacket > 34) {
1486 // 0.49+ (kad version 7) sends additionally its connect options so we know whether to use an obfuscated connection
1487 connectOptions = bio.ReadUInt8();
1490 CUInt128 zero;
1491 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1492 theApp->clientlist->RequestBuddy(&contact, connectOptions);
1496 // KADEMLIA_CALLBACK_REQ
1497 // Used by Kad1.0 and Kad2.0
1498 void CKademliaUDPListener::ProcessCallbackRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t WXUNUSED(port), const CKadUDPKey& WXUNUSED(senderKey))
1500 // Verify packet is expected size
1501 CHECK_PACKET_MIN_SIZE(34);
1503 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1504 if (buddy != NULL) {
1505 CMemFile bio(packetData, lenPacket);
1506 CUInt128 check = bio.ReadUInt128();
1507 // JOHNTODO: Begin filtering bad buddy ID's..
1508 // CUInt128 bud(buddy->GetBuddyID());
1509 CUInt128 file = bio.ReadUInt128();
1510 uint16_t tcp = bio.ReadUInt16();
1512 if (buddy->GetSocket()) {
1513 CMemFile packetdata(lenPacket + 6);
1514 packetdata.WriteUInt128(check);
1515 packetdata.WriteUInt128(file);
1516 packetdata.WriteUInt32(ip);
1517 packetdata.WriteUInt16(tcp);
1518 CPacket* packet = new CPacket(packetdata, OP_EMULEPROT, OP_CALLBACK);
1519 AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_CALLBACK to ") + KadIPToString(ip));
1520 buddy->GetSocket()->SendPacket(packet);
1521 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1522 } else {
1523 throw wxString::FromAscii(__FUNCTION__) + wxT(": Buddy has no valid socket");
1528 // KADEMLIA2_PING
1529 void CKademliaUDPListener::Process2Ping(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1531 // can be used just as PING, currently it is however only used to determine one's external port
1532 CMemFile packetdata(2);
1533 packetdata.WriteUInt16(port);
1534 DebugSend(Kad2Pong, ip, port);
1535 SendPacket(packetdata, KADEMLIA2_PONG, ip, port, senderKey, NULL);
1538 // KADEMLIA2_PONG
1539 void CKademliaUDPListener::Process2Pong(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1541 CHECK_PACKET_MIN_SIZE(2);
1542 CHECK_TRACKED_PACKET(KADEMLIA2_PING);
1544 // Is this one of our legacy challenge packets?
1545 CUInt128 contactID;
1546 if (IsLegacyChallenge(CUInt128((uint32_t)0), ip, KADEMLIA2_PING, contactID)) {
1547 // yup it is, set the contact as verified
1548 if (!CKademlia::GetRoutingZone()->VerifyContact(contactID, ip)) {
1549 AddDebugLogLineN(logKadRouting, wxT("Unable to find valid sender in routing table (sender: ") + KadIPToString(ip) + wxT(")"));
1550 } else {
1551 AddDebugLogLineN(logKadRouting, wxT("Verified contact with legacy challenge (Kad2Ping) - ") + KadIPToString(ip));
1553 return; // we do not actually care for its other content
1556 if (CKademlia::GetPrefs()->FindExternKadPort(false)) {
1557 // the reported port doesn't always have to be our true external port, esp. if we used our intern port
1558 // and communicated recently with the client some routers might remember this and assign the intern port as source
1559 // but this shouldn't be a problem because we prefer intern ports anyway.
1560 // might have to be reviewed in later versions when more data is available
1561 CKademlia::GetPrefs()->SetExternKadPort(PeekUInt16(packetData), ip);
1563 if (CUDPFirewallTester::IsFWCheckUDPRunning()) {
1564 CUDPFirewallTester::QueryNextClient();
1567 theApp->ShowConnectionState();
1570 // KADEMLIA2_FIREWALLUDP
1571 void CKademliaUDPListener::Process2FirewallUDP(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1573 // Verify packet is expected size
1574 CHECK_PACKET_MIN_SIZE(3);
1576 uint8_t errorCode = PeekUInt8(packetData);
1577 uint16_t incomingPort = PeekUInt16(packetData + 1);
1578 if ((incomingPort != CKademlia::GetPrefs()->GetExternalKadPort() && incomingPort != CKademlia::GetPrefs()->GetInternKadPort()) || incomingPort == 0) {
1579 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck on unexpected incoming port %u from %s")) % incomingPort % KadIPToString(ip));
1580 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
1581 } else if (errorCode == 0) {
1582 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck packet from %s with incoming port %u")) % KadIPToString(ip) % incomingPort);
1583 CUDPFirewallTester::SetUDPFWCheckResult(true, false, ip, incomingPort);
1584 } else {
1585 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("Received UDP FirewallCheck packet from %s with incoming port %u with remote errorcode %u - ignoring result"))
1586 % KadIPToString(ip) % incomingPort % errorCode);
1587 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
1591 void CKademliaUDPListener::SendPacket(const CMemFile &data, uint8_t opcode, uint32_t destinationHost, uint16_t destinationPort, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
1593 AddTrackedOutPacket(destinationHost, opcode);
1594 CPacket* packet = new CPacket(data, OP_KADEMLIAHEADER, opcode);
1595 if (packet->GetPacketSize() > 200) {
1596 packet->PackPacket();
1598 uint8_t cryptData[16];
1599 uint8_t *cryptKey;
1600 if (cryptTargetID != NULL) {
1601 cryptKey = (uint8_t *)&cryptData;
1602 cryptTargetID->StoreCryptValue(cryptKey);
1603 } else {
1604 cryptKey = NULL;
1606 theStats::AddUpOverheadKad(packet->GetPacketSize());
1607 theApp->clientudp->SendPacket(packet, wxUINT32_SWAP_ALWAYS(destinationHost), destinationPort, true, cryptKey, true, targetKey.GetKeyValue(theApp->GetPublicIP(false)));
1610 bool CKademliaUDPListener::FindNodeIDByIP(CKadClientSearcher* requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort)
1612 // send a hello packet to the given IP in order to get a HELLO_RES with the NodeID
1613 AddDebugLogLineN(logClientKadUDP, wxT("FindNodeIDByIP: Requesting NodeID from ") + KadIPToString(ip) + wxT(" by sending Kad2HelloReq"));
1614 DebugSend(Kad2HelloReq, ip, udpPort);
1615 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
1616 FetchNodeID_Struct sRequest = { ip, tcpPort, ::GetTickCount() + SEC2MS(60), requester };
1617 m_fetchNodeIDRequests.push_back(sRequest);
1618 return true;
1621 void CKademliaUDPListener::ExpireClientSearch(CKadClientSearcher* expireImmediately)
1623 uint32_t now = ::GetTickCount();
1624 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end();) {
1625 FetchNodeIDList::iterator it2 = it++;
1626 if (it2->requester == expireImmediately) {
1627 m_fetchNodeIDRequests.erase(it2);
1629 else if (it2->expire < now) {
1630 it2->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
1631 m_fetchNodeIDRequests.erase(it2);
1636 void CKademliaUDPListener::SendLegacyChallenge(uint32_t ip, uint16_t port, const CUInt128& contactID)
1638 // We want to verify that a pre-0.49a contact is valid and not sent from a spoofed IP.
1639 // Because those versions don't support any direct validating, we send a KAD_REQ with a random ID,
1640 // which is our challenge. If we receive an answer packet for this request, we can be sure the
1641 // contact is not spoofed
1642 #ifdef __DEBUG__
1643 CContact* contact = CKademlia::GetRoutingZone()->GetContact(contactID);
1644 if (contact != NULL) {
1645 if (contact->GetType() < 2) {
1646 AddDebugLogLineN(logKadRouting, wxT("Sending challenge to a long known contact (should be verified already) - ") + KadIPToString(ip));
1648 } else {
1649 wxFAIL;
1651 #endif
1653 if (HasActiveLegacyChallenge(ip)) {
1654 // don't send more than one challenge at a time
1655 return;
1657 CMemFile packetdata(33);
1658 packetdata.WriteUInt8(KADEMLIA_FIND_VALUE);
1659 CUInt128 challenge(GetRandomUint128());
1660 if (challenge == 0) {
1661 // hey there is a 2^128 chance that this happens ;)
1662 wxFAIL;
1663 challenge = 1;
1665 // Put the target we want into the packet. This is our challenge
1666 packetdata.WriteUInt128(challenge);
1667 // Add the ID of the contact we are contacting for sanity checks on the other end.
1668 packetdata.WriteUInt128(contactID);
1669 DebugSendF(wxT("Kad2Req(SendLegacyChallenge)"), ip, port);
1670 // those versions we send those requests to don't support encryption / obfuscation
1671 SendPacket(packetdata, KADEMLIA2_REQ, ip, port, 0, NULL);
1672 AddLegacyChallenge(contactID, challenge, ip, KADEMLIA2_REQ);
1675 void CKademliaUDPListener::DebugClientOutput(const wxString& place, uint32 kad_ip, uint32 port, const byte* data, int len)
1677 #if THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX
1678 uint32 ip = wxUINT32_SWAP_ALWAYS(kad_ip);
1679 printf("Error on %s received from: %s\n",(const char*)unicode2char(place),(const char*)unicode2char(Uint32_16toStringIP_Port(ip,port)));
1680 if (data) {
1681 printf("Packet dump:\n");
1682 DumpMem(data, len);
1684 CClientList::SourceList clientslist = theApp->clientlist->GetClientsByIP(ip);
1685 if (!clientslist.empty()) {
1686 for (CClientList::SourceList::iterator it = clientslist.begin(); it != clientslist.end(); ++it) {
1687 printf("Ip Matches: %s\n",(const char*)unicode2char((*it)->GetClientFullInfo()));
1689 } else {
1690 printf("No ip match, trying to create a client connection:\n");
1691 printf("Trying port %d\n", port - 10);
1692 CUpDownClient* client = new CUpDownClient(port-10,kad_ip,0,0,NULL,false,false);
1693 client->SetConnectionReason(wxT("Error on ") + place);
1694 client->TryToConnect(true);
1696 #else
1697 // No need for warnings for the rest of us.
1698 (void)place;
1699 (void)kad_ip;
1700 (void)port;
1701 (void)data;
1702 (void)len;
1703 #endif
1705 // File_checked_for_headers