Upstream tarball 20080630
[amule.git] / src / kademlia / net / KademliaUDPListener.cpp
blob8fba759e719bf978d80484ea20eb8b5c627bdda0
1 //
2 // This file is part of aMule Project
3 //
4 // Copyright (c) 2004-2008 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2004-2008 aMule Project ( http://www.amule-project.net )
6 // Copyright (C)2003 Barry Dunne (http://www.emule-project.net)
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 // Note To Mods //
24 Please do not change anything here and release it..
25 There is going to be a new forum created just for the Kademlia side of the client..
26 If you feel there is an error or a way to improve something, please
27 post it in the forum first and let us look at it.. If it is a real improvement,
28 it will be added to the offical client.. Changing something without knowing
29 what all it does can cause great harm to the network if released in mass form..
30 Any mod that changes anything within the Kademlia side will not be allowed to advertise
31 there client on the eMule forum..
34 #include <wx/wx.h>
36 #include "KademliaUDPListener.h"
38 #include <protocol/Protocols.h>
39 #include <protocol/kad/Constants.h>
40 #include <protocol/kad/Client2Client/UDP.h>
41 #include <protocol/kad2/Constants.h>
42 #include <protocol/kad2/Client2Client/UDP.h>
43 #include <protocol/ed2k/Client2Client/TCP.h> // OP_CALLBACK is sent in some cases.
44 #include <common/Macros.h>
45 #include <common/Format.h>
46 #include <tags/FileTags.h>
48 #include "../routing/Contact.h"
49 #include "../routing/RoutingZone.h"
50 #include "../kademlia/Indexed.h"
51 #include "../kademlia/Defines.h"
52 #include "../kademlia/UDPFirewallTester.h"
53 #include "../utils/KadUDPKey.h"
54 #include "../utils/KadClientSearcher.h"
55 #include "../../amule.h"
56 #include "../../ClientUDPSocket.h"
57 #include "../../Packet.h"
58 #include "../../ClientList.h"
59 #include "../../Statistics.h"
60 #include "../../MemFile.h"
61 #include "../../updownclient.h"
62 #include "../../ClientTCPSocket.h"
63 #include "../../Logger.h"
64 #include "../../Preferences.h"
65 #include "../../ScopedPtr.h"
66 #include "../../IPFilter.h"
68 #include <wx/tokenzr.h>
70 #define THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX 0
73 #define CHECK_PACKET_SIZE(OP, SIZE) \
74 if (lenPacket OP (uint32_t)(SIZE)) \
75 throw wxString::Format(wxT("***NOTE: Received wrong size (%u) packet in "), lenPacket) + wxString::FromAscii(__FUNCTION__)
77 #define CHECK_PACKET_MIN_SIZE(SIZE) CHECK_PACKET_SIZE(<, SIZE)
78 #define CHECK_PACKET_EXACT_SIZE(SIZE) CHECK_PACKET_SIZE(!=, SIZE)
80 #define CHECK_TRACKED_PACKET(OPCODE) \
81 if (!IsOnOutTrackList(ip, OPCODE)) \
82 throw wxString::Format(wxT("***NOTE: Received unrequested response packet, size (%u) in "), lenPacket) + wxString::FromAscii(__FUNCTION__)
85 ////////////////////////////////////////
86 using namespace Kademlia;
87 ////////////////////////////////////////
89 CKademliaUDPListener::~CKademliaUDPListener()
91 // report timeout to all pending FetchNodeIDRequests
92 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
93 it->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
97 // Used by Kad1.0 and Kad2.0
98 void CKademliaUDPListener::Bootstrap(uint32_t ip, uint16_t port, bool kad2)
100 wxASSERT(ip);
102 if (kad2) {
103 DebugSend(Kad2BootstrapReq, ip, port);
104 CMemFile bio(0);
105 // TODO: add possibility to encrypt bootstrap packets
106 SendPacket(bio, KADEMLIA2_BOOTSTRAP_REQ, ip, port, 0, NULL);
107 } else {
108 DebugSend(KadBootstrapReq, ip, port);
109 SendMyDetails(KADEMLIA_BOOTSTRAP_REQ, ip, port, kad2, 0, NULL);
113 // Used by Kad1.0 and Kad2.0
114 void CKademliaUDPListener::SendMyDetails(uint8_t opcode, uint32_t ip, uint16_t port, bool kad2, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
116 CMemFile packetdata;
117 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
119 if (kad2) {
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 packetdata.WriteUInt8(tagCount);
128 if (!CKademlia::GetPrefs()->GetUseExternKadPort()) {
129 packetdata.WriteTag(CTagVarInt(TAG_SOURCEUPORT, CKademlia::GetPrefs()->GetInternKadPort()));
131 // packetdata.WriteTag(CKadTagUInt(TAG_USER_COUNT, CKademlia::GetPrefs()->GetKademliaUsers()));
132 // packetdata.WriteTag(CKadTagUInt(TAG_FILE_COUNT, CKademlia::GetPrefs()->GetKademliaFiles()));
133 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
134 } else {
135 packetdata.WriteUInt32(CKademlia::GetPrefs()->GetIPAddress());
136 packetdata.WriteUInt16(thePrefs::GetEffectiveUDPPort());
137 packetdata.WriteUInt16(thePrefs::GetPort());
138 packetdata.WriteUInt8(0);
139 SendPacket(packetdata, opcode, ip, port, 0, NULL);
143 // Kad1.0 and Kad2.0 currently.
144 void CKademliaUDPListener::FirewalledCheck(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, uint8_t kadVersion)
146 if (kadVersion > 6) {
147 // new opcode since 0.49a with extended informations to support obfuscated connections properly
148 CMemFile packetdata(19);
149 packetdata.WriteUInt16(thePrefs::GetPort());
150 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
151 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false));
152 DebugSend(KadFirewalled2Req, ip, port);
153 SendPacket(packetdata, KADEMLIA_FIREWALLED2_REQ, ip, port, senderKey, NULL);
154 } else {
155 CMemFile packetdata(2);
156 packetdata.WriteUInt16(thePrefs::GetPort());
157 DebugSend(KadFirewalledReq, ip, port);
158 SendPacket(packetdata, KADEMLIA_FIREWALLED_REQ, ip, port, senderKey, NULL);
160 theApp->clientlist->AddKadFirewallRequest(wxUINT32_SWAP_ALWAYS(ip));
163 void CKademliaUDPListener::SendNullPacket(uint8_t opcode, uint32_t ip, uint16_t port, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
165 CMemFile packetdata(0);
166 SendPacket(packetdata, opcode, ip, port, targetKey, cryptTargetID);
169 void CKademliaUDPListener::SendPublishSourcePacket(const CContact& contact, const CUInt128 &targetID, const CUInt128 &contactID, const TagPtrList& tags)
171 uint8_t opcode;
172 CMemFile packetdata;
173 packetdata.WriteUInt128(targetID);
174 if (contact.GetVersion() >= 4/*47c*/) {
175 opcode = KADEMLIA2_PUBLISH_SOURCE_REQ;
176 packetdata.WriteUInt128(contactID);
177 packetdata.WriteTagPtrList(tags);
178 DebugSend(Kad2PublishSrcReq, contact.GetIPAddress(), contact.GetUDPPort());
179 } else {
180 opcode = KADEMLIA_PUBLISH_REQ;
181 //We only use this for publishing sources now.. So we always send one here..
182 packetdata.WriteUInt16(1);
183 packetdata.WriteUInt128(contactID);
184 packetdata.WriteTagPtrList(tags);
185 DebugSend(KadPublishReq, contact.GetIPAddress(), contact.GetUDPPort());
187 if (contact.GetVersion() >= 6) { // obfuscated ?
188 CUInt128 clientID = contact.GetClientID();
189 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), contact.GetUDPKey(), &clientID);
190 } else {
191 SendPacket(packetdata, opcode, contact.GetIPAddress(), contact.GetUDPPort(), 0, NULL);
195 void CKademliaUDPListener::ProcessPacket(const uint8_t* data, uint32_t lenData, uint32_t ip, uint16_t port, bool validReceiverKey, const CKadUDPKey& senderKey)
197 // we do not accept (<= 0.48a) unencrypted incoming packets from port 53 (DNS) to avoid attacks based on DNS protocol confusion
198 if (port == 53 && senderKey.IsEmpty()) {
199 #ifdef __DEBUG__
200 AddDebugLogLineM(false, logKadPacketTracking, wxT("Dropping incoming unencrypted packet on port 53 (DNS), IP: ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)));
201 #endif
202 return;
205 //Update connection state only when it changes.
206 bool curCon = CKademlia::GetPrefs()->HasHadContact();
207 CKademlia::GetPrefs()->SetLastContact();
208 CUDPFirewallTester::Connected();
209 if( curCon != CKademlia::GetPrefs()->HasHadContact()) {
210 theApp->ShowConnectionState();
213 uint8_t opcode = data[1];
214 const uint8_t *packetData = data + 2;
215 uint32_t lenPacket = lenData - 2;
217 if (!InTrackListIsAllowedPacket(ip, opcode, validReceiverKey)) {
218 return;
221 switch (opcode) {
222 case KADEMLIA_BOOTSTRAP_REQ:
223 DebugRecv(KadBootstrapReq, ip, port);
224 ProcessBootstrapRequest(packetData, lenPacket, ip, port);
225 break;
226 case KADEMLIA2_BOOTSTRAP_REQ:
227 DebugRecv(Kad2BootstrapReq, ip, port);
228 Process2BootstrapRequest(ip, port, senderKey);
229 break;
230 case KADEMLIA_BOOTSTRAP_RES:
231 DebugRecv(KadBootstrapRes, ip, port);
232 ProcessBootstrapResponse(packetData, lenPacket, ip);
233 break;
234 case KADEMLIA2_BOOTSTRAP_RES:
235 DebugRecv(Kad2BootstrapRes, ip, port);
236 Process2BootstrapResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
237 break;
238 case KADEMLIA_HELLO_REQ:
239 DebugRecv(KadHelloReq, ip, port);
240 ProcessHelloRequest(packetData, lenPacket, ip, port);
241 break;
242 case KADEMLIA2_HELLO_REQ:
243 DebugRecv(Kad2HelloReq, ip, port);
244 Process2HelloRequest(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
245 break;
246 case KADEMLIA_HELLO_RES:
247 DebugRecv(KadHelloRes, ip, port);
248 ProcessHelloResponse(packetData, lenPacket, ip, port);
249 break;
250 case KADEMLIA2_HELLO_RES:
251 DebugRecv(Kad2HelloRes, ip, port);
252 Process2HelloResponse(packetData, lenPacket, ip, port, senderKey, validReceiverKey);
253 break;
254 case KADEMLIA_REQ:
255 DebugRecv(KadReq, ip, port);
256 ProcessKademliaRequest(packetData, lenPacket, ip, port);
257 break;
258 case KADEMLIA2_REQ:
259 DebugRecv(Kad2Req, ip, port);
260 ProcessKademlia2Request(packetData, lenPacket, ip, port, senderKey);
261 break;
262 case KADEMLIA_RES:
263 DebugRecv(KadRes, ip, port);
264 ProcessKademliaResponse(packetData, lenPacket, ip, port);
265 break;
266 case KADEMLIA2_RES:
267 DebugRecv(Kad2Res, ip, port);
268 ProcessKademlia2Response(packetData, lenPacket, ip, port, senderKey);
269 break;
270 case KADEMLIA_SEARCH_REQ:
271 DebugRecv(KadSearchReq, ip, port);
272 ProcessSearchRequest(packetData, lenPacket, ip, port);
273 break;
274 case KADEMLIA_SEARCH_NOTES_REQ:
275 DebugRecv(KadSearchNotesReq, ip, port);
276 ProcessSearchNotesRequest(packetData, lenPacket, ip, port);
277 break;
278 case KADEMLIA2_SEARCH_NOTES_REQ:
279 DebugRecv(Kad2SearchNotesReq, ip, port);
280 Process2SearchNotesRequest(packetData, lenPacket, ip, port, senderKey);
281 break;
282 case KADEMLIA2_SEARCH_KEY_REQ:
283 DebugRecv(Kad2SearchKeyReq, ip, port);
284 Process2SearchKeyRequest(packetData, lenPacket, ip, port, senderKey);
285 break;
286 case KADEMLIA2_SEARCH_SOURCE_REQ:
287 DebugRecv(Kad2SearchSourceReq, ip, port);
288 Process2SearchSourceRequest(packetData, lenPacket, ip, port, senderKey);
289 break;
290 case KADEMLIA_SEARCH_RES:
291 DebugRecv(KadSearchRes, ip, port);
292 ProcessSearchResponse(packetData, lenPacket);
293 break;
294 case KADEMLIA_SEARCH_NOTES_RES:
295 DebugRecv(KadSearchNotesRes, ip, port);
296 ProcessSearchNotesResponse(packetData, lenPacket, ip);
297 break;
298 case KADEMLIA2_SEARCH_RES:
299 DebugRecv(Kad2SearchRes, ip, port);
300 Process2SearchResponse(packetData, lenPacket, senderKey);
301 break;
302 case KADEMLIA_PUBLISH_REQ:
303 DebugRecv(KadPublishReq, ip, port);
304 ProcessPublishRequest(packetData, lenPacket, ip, port);
305 break;
306 case KADEMLIA_PUBLISH_NOTES_REQ:
307 DebugRecv(KadPublishNotesReq, ip, port);
308 ProcessPublishNotesRequest(packetData, lenPacket, ip, port);
309 break;
310 case KADEMLIA2_PUBLISH_NOTES_REQ:
311 DebugRecv(Kad2PublishNotesReq, ip, port);
312 Process2PublishNotesRequest(packetData, lenPacket, ip, port, senderKey);
313 break;
314 case KADEMLIA2_PUBLISH_KEY_REQ:
315 DebugRecv(Kad2PublishKeyReq, ip, port);
316 Process2PublishKeyRequest(packetData, lenPacket, ip, port, senderKey);
317 break;
318 case KADEMLIA2_PUBLISH_SOURCE_REQ:
319 DebugRecv(Kad2PublishSourceReq, ip, port);
320 Process2PublishSourceRequest(packetData, lenPacket, ip, port, senderKey);
321 break;
322 case KADEMLIA_PUBLISH_RES:
323 DebugRecv(KadPublishRes, ip, port);
324 ProcessPublishResponse(packetData, lenPacket, ip);
325 break;
326 case KADEMLIA_PUBLISH_NOTES_RES:
327 DebugRecv(KadPublishNotesRes, ip, port);
328 ProcessPublishNotesResponse(packetData, lenPacket, ip);
329 break;
330 case KADEMLIA2_PUBLISH_RES:
331 DebugRecv(Kad2PublishRes, ip, port);
332 Process2PublishResponse(packetData, lenPacket, ip, senderKey);
333 break;
334 case KADEMLIA_FIREWALLED_REQ:
335 DebugRecv(KadFirewalledReq, ip, port);
336 ProcessFirewalledRequest(packetData, lenPacket, ip, port, senderKey);
337 break;
338 case KADEMLIA_FIREWALLED2_REQ:
339 DebugRecv(KadFirewalled2Req, ip, port);
340 ProcessFirewalled2Request(packetData, lenPacket, ip, port, senderKey);
341 break;
342 case KADEMLIA_FIREWALLED_RES:
343 DebugRecv(KadFirewalledRes, ip, port);
344 ProcessFirewalledResponse(packetData, lenPacket, ip, senderKey);
345 break;
346 case KADEMLIA_FIREWALLED_ACK_RES:
347 DebugRecv(KadFirewalledAck, ip, port);
348 ProcessFirewalledAckResponse(lenPacket);
349 break;
350 case KADEMLIA_FINDBUDDY_REQ:
351 DebugRecv(KadFindBuddyReq, ip, port);
352 ProcessFindBuddyRequest(packetData, lenPacket, ip, port, senderKey);
353 break;
354 case KADEMLIA_FINDBUDDY_RES:
355 DebugRecv(KadFindBuddyRes, ip, port);
356 ProcessFindBuddyResponse(packetData, lenPacket, ip, port, senderKey);
357 break;
358 case KADEMLIA_CALLBACK_REQ:
359 DebugRecv(KadCallbackReq, ip, port);
360 ProcessCallbackRequest(packetData, lenPacket, ip, port, senderKey);
361 break;
362 case KADEMLIA2_PING:
363 DebugRecv(Kad2Ping, ip, port);
364 Process2Ping(ip, port, senderKey);
365 break;
366 case KADEMLIA2_PONG:
367 DebugRecv(Kad2Pong, ip, port);
368 Process2Pong(packetData, lenPacket, ip);
369 break;
370 case KADEMLIA2_FIREWALLUDP:
371 DebugRecv(Kad2FirewallUDP, ip, port);
372 Process2FirewallUDP(packetData, lenPacket, ip);
373 break;
374 default: {
375 throw wxString::Format(wxT("Unknown opcode %02x on CKademliaUDPListener::ProcessPacket()"), opcode);
380 // Used only for Kad1.0
381 void CKademliaUDPListener::AddContact(const uint8_t *data, uint32_t lenData, uint32_t ip, uint16_t port, uint16_t tport, const CKadUDPKey& udpKey, bool ipVerified, bool update)
383 CMemFile bio(data, lenData);
384 CUInt128 id = bio.ReadUInt128();
385 bio.ReadUInt32();
386 bio.ReadUInt16();
387 if (tport) {
388 bio.ReadUInt16();
389 } else {
390 tport = bio.ReadUInt16();
392 bio.ReadUInt8();
393 //AddDebugLogLineM(false, logKadMain, wxT("Adding a contact with ip ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(ip),port));
394 if(IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip), port)) {
395 // Ignore stated ip and port, use the address the packet came from
396 CKademlia::GetRoutingZone()->Add(id, ip, port, tport, 0, udpKey, ipVerified, update);
400 // Used only for Kad2.0
401 void 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)
403 CMemFile bio(data, lenData);
404 CUInt128 id = bio.ReadUInt128();
405 uint16_t tport = bio.ReadUInt16();
406 uint8_t version = bio.ReadUInt8();
407 if (outVersion != NULL) {
408 *outVersion = version;
410 uint8_t tags = bio.ReadUInt8();
411 while (tags) {
412 CTag *tag = bio.ReadTag();
413 if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
414 if (tag->IsInt() && (uint16_t)tag->GetInt() > 0) {
415 port = tag->GetInt();
416 } else {
417 wxFAIL;
420 delete tag;
421 --tags;
424 // check if we are waiting for informations (nodeid) about this client and if so inform the requester
425 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end(); ++it) {
426 if (it->ip == ip && it->tcpPort == tport) {
427 //AddDebugLogLineM(false, logKadMain, wxT("Result Addcontact: ") + id.ToHexString());
428 uint8_t uchID[16];
429 id.ToByteArray(uchID);
430 it->requester->KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, uchID);
431 m_fetchNodeIDRequests.erase(it);
432 break;
436 CKademlia::GetRoutingZone()->Add(id, ip, port, tport, version, udpKey, ipVerified, update);
439 // Used only for Kad1.0
440 void CKademliaUDPListener::AddContacts(const uint8_t *data, uint32_t lenData, uint16_t numContacts, bool update)
442 CMemFile bio(data, lenData);
443 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
444 for (uint16_t i = 0; i < numContacts; i++) {
445 CUInt128 id = bio.ReadUInt128();
446 uint32_t ip = bio.ReadUInt32();
447 ip = wxUINT32_SWAP_ALWAYS(ip);
448 uint16_t port = bio.ReadUInt16();
449 uint16_t tport = bio.ReadUInt16();
450 bio.ReadUInt8();
451 //AddDebugLogLineM(false, logKadMain, wxT("Adding contact(s) with ip ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(ip),port));
452 if (IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip), port)) {
453 routingZone->Add(id, ip, port, tport, 0, 0, false, update);
458 // KADEMLIA_BOOTSTRAP_REQ
459 // Used only for Kad1.0
460 void CKademliaUDPListener::ProcessBootstrapRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
462 // Verify packet is expected size
463 CHECK_PACKET_EXACT_SIZE(25);
465 // Add the sender to the list of contacts
466 AddContact(packetData, lenPacket, ip, port, 0, 0, false, true);
468 // Get some contacts to return
469 ContactList contacts;
470 uint16_t numContacts = 1 + (uint16_t)CKademlia::GetRoutingZone()->GetBootstrapContacts(&contacts, 20);
472 // Create response packet
473 //We only collect a max of 20 contacts here.. Max size is 527.
474 //2 + 25(20) + 25
475 CMemFile packetdata(527);
477 // Write packet info
478 packetdata.WriteUInt16(numContacts);
479 CContact *contact;
480 for (ContactList::const_iterator it = contacts.begin(); it != contacts.end(); ++it) {
481 contact = *it;
482 packetdata.WriteUInt128(contact->GetClientID());
483 packetdata.WriteUInt32(contact->GetIPAddress());
484 packetdata.WriteUInt16(contact->GetUDPPort());
485 packetdata.WriteUInt16(contact->GetTCPPort());
486 packetdata.WriteUInt8(contact->GetType());
489 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
490 packetdata.WriteUInt32(CKademlia::GetPrefs()->GetIPAddress());
491 packetdata.WriteUInt16(thePrefs::GetEffectiveUDPPort());
492 packetdata.WriteUInt16(thePrefs::GetPort());
493 packetdata.WriteUInt8(0);
495 // Send response
496 DebugSend(KadBootstrapRes, ip, port);
497 SendPacket(packetdata, KADEMLIA_BOOTSTRAP_RES, ip, port, 0, NULL);
500 // KADEMLIA2_BOOTSTRAP_REQ
501 // Used only for Kad2.0
502 void CKademliaUDPListener::Process2BootstrapRequest(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
504 // Get some contacts to return
505 ContactList contacts;
506 uint16_t numContacts = (uint16_t)CKademlia::GetRoutingZone()->GetBootstrapContacts(&contacts, 20);
508 // Create response packet
509 //We only collect a max of 20 contacts here.. Max size is 521.
510 //2 + 25(20) + 19
511 CMemFile packetdata(521);
513 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetKadID());
514 packetdata.WriteUInt16(thePrefs::GetPort());
515 packetdata.WriteUInt8(KADEMLIA_VERSION);
517 // Write packet info
518 packetdata.WriteUInt16(numContacts);
519 CContact *contact;
520 for (ContactList::const_iterator it = contacts.begin(); it != contacts.end(); ++it) {
521 contact = *it;
522 packetdata.WriteUInt128(contact->GetClientID());
523 packetdata.WriteUInt32(contact->GetIPAddress());
524 packetdata.WriteUInt16(contact->GetUDPPort());
525 packetdata.WriteUInt16(contact->GetTCPPort());
526 packetdata.WriteUInt8(contact->GetVersion());
529 // Send response
530 DebugSend(Kad2BootstrapRes, ip, port);
531 SendPacket(packetdata, KADEMLIA2_BOOTSTRAP_RES, ip, port, senderKey, NULL);
534 // KADEMLIA_BOOTSTRAP_RES
535 // Used only for Kad1.0
536 void CKademliaUDPListener::ProcessBootstrapResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
538 // Verify packet is expected size
539 CHECK_PACKET_MIN_SIZE(27);
540 CHECK_TRACKED_PACKET(KADEMLIA_BOOTSTRAP_REQ);
542 // How many contacts were given
543 CMemFile bio(packetData, lenPacket);
544 uint16_t numContacts = bio.ReadUInt16();
546 // Verify packet is expected size
547 if (lenPacket != (uint32_t)(2 + 25 * numContacts)) {
548 return;
551 // Add these contacts to the list.
552 AddContacts(packetData + 2, lenPacket - 2, numContacts, false);
555 // KADEMLIA2_BOOTSTRAP_RES
556 // Used only for Kad2.0
557 void CKademliaUDPListener::Process2BootstrapResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
559 CHECK_TRACKED_PACKET(KADEMLIA2_BOOTSTRAP_REQ);
561 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
563 // How many contacts were given
564 CMemFile bio(packetData, lenPacket);
565 CUInt128 contactID = bio.ReadUInt128();
566 uint16_t tport = bio.ReadUInt16();
567 uint8_t version = bio.ReadUInt8();
568 routingZone->Add(contactID, ip, port, tport, version, senderKey, validReceiverKey, true);
570 uint16_t numContacts = bio.ReadUInt16();
571 while (numContacts) {
572 contactID = bio.ReadUInt128();
573 ip = bio.ReadUInt32();
574 port = bio.ReadUInt16();
575 tport = bio.ReadUInt16();
576 version = bio.ReadUInt8();
577 routingZone->Add(contactID, ip, port, tport, version, 0, false, false);
578 numContacts--;
582 // KADEMLIA_HELLO_REQ
583 // Used in Kad1.0 only
584 void CKademliaUDPListener::ProcessHelloRequest (const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
586 // Verify packet is expected size
587 CHECK_PACKET_EXACT_SIZE(25);
589 // Add the sender to the list of contacts
590 AddContact(packetData, lenPacket, ip, port, 0, 0, false, true);
592 // Send response
593 DebugSend(KadHelloRes, ip, port);
594 SendMyDetails(KADEMLIA_HELLO_RES, ip, port, false, 0, NULL);
596 // Check if firewalled
597 if (CKademlia::GetPrefs()->GetRecheckIP()) {
598 FirewalledCheck(ip, port, 0, 0);
602 // KADEMLIA2_HELLO_REQ
603 // Used in Kad2.0 only
604 void CKademliaUDPListener::Process2HelloRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
606 uint16_t dbgOldUDPPort = port;
607 uint8_t contactVersion;
608 AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true); // might change (udp)port
609 #ifdef __DEBUG__
610 if (dbgOldUDPPort != port) {
611 AddDebugLogLineM(false, logClientKadUDP, wxT("KadContact ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) + wxString::Format(wxT(" uses his internal (%u) instead external (%u) UDP Port"), port, dbgOldUDPPort));
613 #endif
615 DebugSend(Kad2HelloRes, ip, port);
616 SendMyDetails(KADEMLIA2_HELLO_RES, ip, port, true, senderKey, NULL);
618 // Check if firewalled
619 if (CKademlia::GetPrefs()->GetRecheckIP()) {
620 FirewalledCheck(ip, port, senderKey, contactVersion);
623 // do we need to find out our extern port?
624 if (CKademlia::GetPrefs()->GetExternalKadPort() == 0 && contactVersion > 5) {
625 DebugSend(Kad2Ping, ip, port);
626 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
630 // KADEMLIA_HELLO_RES
631 // Used in Kad1.0 only
632 void CKademliaUDPListener::ProcessHelloResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
634 CHECK_TRACKED_PACKET(KADEMLIA_HELLO_REQ);
636 // Verify packet is expected size
637 CHECK_PACKET_EXACT_SIZE(25);
639 // Add or Update contact.
640 AddContact(packetData, lenPacket, ip, port, 0, 0, false, true);
643 // KADEMLIA2_HELLO_RES
644 // Used in Kad2.0 only
645 void CKademliaUDPListener::Process2HelloResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey, bool validReceiverKey)
647 CHECK_TRACKED_PACKET(KADEMLIA2_HELLO_REQ);
649 // Add or Update contact.
650 uint8_t contactVersion;
651 AddContact2(packetData, lenPacket, ip, port, &contactVersion, senderKey, validReceiverKey, true);
653 // do we need to find out our extern port?
654 if (CKademlia::GetPrefs()->GetExternalKadPort() == 0 && contactVersion > 5) {
655 DebugSend(Kad2Ping, ip, port);
656 SendNullPacket(KADEMLIA2_PING, ip, port, senderKey, NULL);
659 // Check if firewalled
660 if (CKademlia::GetPrefs()->GetRecheckIP()) {
661 FirewalledCheck(ip, port, senderKey, contactVersion);
665 // KADEMLIA_REQ
666 // Used in Kad1.0 only
667 void CKademliaUDPListener::ProcessKademliaRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
669 // Verify packet is expected size
670 CHECK_PACKET_EXACT_SIZE(33);
672 // RecheckIP and firewall status
673 if (CKademlia::GetPrefs()->GetRecheckIP()) {
674 FirewalledCheck(ip, port, 0, 0);
675 DebugSend(KadHelloReq, ip, port);
676 SendMyDetails(KADEMLIA_HELLO_REQ, ip, port, false, 0, NULL);
679 // Get target and type
680 CMemFile bio(packetData, lenPacket);
681 uint8_t type = bio.ReadUInt8();
682 // bool flag1 = (type >> 6); //Reserved
683 // bool flag2 = (type >> 7); //Reserved
684 // bool flag3 = (type >> 8); //Reserved
686 type &= 0x1F;
687 if( type == 0 ) {
688 throw wxString::Format(wxT("***NOTE: Received wrong type (0x%02x) in "), type) + wxString::FromAscii(__FUNCTION__);
691 // This is the target node trying to be found.
692 CUInt128 target = bio.ReadUInt128();
693 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
694 distance.XOR(target);
696 // This makes sure we are not mistaken identify. Some client may have fresh installed and have a new hash.
697 CUInt128 check = bio.ReadUInt128();
698 if (CKademlia::GetPrefs()->GetKadID().CompareTo(check)) {
699 return;
702 // Get required number closest to target
703 ContactMap results;
704 CKademlia::GetRoutingZone()->GetClosestTo(2, target, distance, type, &results);
705 uint16_t count = (uint16_t)results.size();
707 // Write response
708 // Max count is 32. size 817..
709 // 16 + 1 + 25(32)
710 CMemFile packetdata(817);
711 packetdata.WriteUInt128(target);
712 packetdata.WriteUInt8((uint8_t)count);
713 CContact *c;
714 for (ContactMap::const_iterator it = results.begin(); it != results.end(); ++it) {
715 c = it->second;
716 packetdata.WriteUInt128(c->GetClientID());
717 packetdata.WriteUInt32(c->GetIPAddress());
718 packetdata.WriteUInt16(c->GetUDPPort());
719 packetdata.WriteUInt16(c->GetTCPPort());
720 packetdata.WriteUInt8(c->GetType());
723 DebugSendF(wxString::Format(wxT("KadRes (count=%u)"), count), ip, port);
724 SendPacket(packetdata, KADEMLIA_RES, ip, port, 0, NULL);
727 // KADEMLIA2_REQ
728 // Used in Kad2.0 only
729 void CKademliaUDPListener::ProcessKademlia2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
731 // Get target and type
732 CMemFile bio(packetData, lenPacket);
733 uint8_t type = bio.ReadUInt8();
734 type &= 0x1F;
735 if (type == 0) {
736 throw wxString::Format(wxT("***NOTE: Received wrong type (0x%02x) in "), type) + wxString::FromAscii(__FUNCTION__);
739 // This is the target node trying to be found.
740 CUInt128 target = bio.ReadUInt128();
741 // Convert Target to Distance as this is how we store contacts.
742 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
743 distance.XOR(target);
745 // This makes sure we are not mistaken identify. Some client may have fresh installed and have a new KadID.
746 CUInt128 check = bio.ReadUInt128();
747 if (CKademlia::GetPrefs()->GetKadID() == check) {
748 // Get required number closest to target
749 ContactMap results;
750 CKademlia::GetRoutingZone()->GetClosestTo(2, target, distance, type, &results);
751 uint8_t count = (uint8_t)results.size();
753 // Write response
754 // Max count is 32. size 817..
755 // 16 + 1 + 25(32)
756 CMemFile packetdata(817);
757 packetdata.WriteUInt128(target);
758 packetdata.WriteUInt8(count);
759 CContact *c;
760 for (ContactMap::const_iterator it = results.begin(); it != results.end(); ++it) {
761 c = it->second;
762 packetdata.WriteUInt128(c->GetClientID());
763 packetdata.WriteUInt32(c->GetIPAddress());
764 packetdata.WriteUInt16(c->GetUDPPort());
765 packetdata.WriteUInt16(c->GetTCPPort());
766 packetdata.WriteUInt8(c->GetVersion()); //<- Kad Version inserted to allow backward compatibility.
769 DebugSendF(wxString::Format(wxT("Kad2Res (count=%u)"), count), ip, port);
770 SendPacket(packetdata, KADEMLIA2_RES, ip, port, senderKey, NULL);
774 // KADEMLIA_RES
775 // Used in Kad1.0 only
776 void CKademliaUDPListener::ProcessKademliaResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
778 // Verify packet is expected size
779 CHECK_PACKET_MIN_SIZE(17);
780 CHECK_TRACKED_PACKET(KADEMLIA_REQ);
782 // Used Pointers
783 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
785 if (CKademlia::GetPrefs()->GetRecheckIP()) {
786 FirewalledCheck(ip, port, 0, 0);
787 DebugSend(KadHelloReq, ip, port);
788 SendMyDetails(KADEMLIA_HELLO_REQ, ip, port, false, 0, NULL);
791 // What search does this relate to
792 CMemFile bio(packetData, lenPacket);
793 CUInt128 target = bio.ReadUInt128();
794 uint16 numContacts = bio.ReadUInt8();
796 // Verify packet is expected size
797 CHECK_PACKET_EXACT_SIZE(16+1 + (16+4+2+2+1)*numContacts);
799 CScopedPtr<ContactList> results(new ContactList);
801 for (uint16_t i = 0; i < numContacts; i++) {
802 CUInt128 id = bio.ReadUInt128();
803 uint32_t contactIP = bio.ReadUInt32();
804 uint16_t contactPort = bio.ReadUInt16();
805 uint16_t tport = bio.ReadUInt16();
806 bio.ReadUInt8();
807 uint32_t hostIP = wxUINT32_SWAP_ALWAYS(contactIP);
808 if(::IsGoodIPPort(hostIP, contactPort) && contactPort != 53 /*No DNS Port without encryption*/) {
809 if (!theApp->ipfilter->IsFiltered(hostIP)) {
810 routingZone->AddUnfiltered(id, contactIP, contactPort, tport, 0, 0, false, false);
811 results->push_back(new CContact(id, contactIP, contactPort, tport, 0, 0, false, target));
816 CSearchManager::ProcessResponse(target, ip, port, results.release());
819 // KADEMLIA2_RES
820 // Used in Kad2.0 only
821 void CKademliaUDPListener::ProcessKademlia2Response(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
823 CHECK_TRACKED_PACKET(KADEMLIA2_REQ);
825 // Used Pointers
826 CRoutingZone *routingZone = CKademlia::GetRoutingZone();
828 // don't do firewallchecks on this opcode anymore, since we need the contacts kad version - hello opcodes are good enough
829 // if (CKademlia::GetPrefs()->GetRecheckIP()) {
830 // FirewalledCheck(ip, port, senderKey);
831 // DebugSend(Kad2HelloReq, ip, port);
832 // SendMyDetails(KADEMLIA2_HELLO_REQ, ip, port, true, senderKey, NULL);
833 // }
835 // What search does this relate to
836 CMemFile bio(packetData, lenPacket);
837 CUInt128 target = bio.ReadUInt128();
838 uint8_t numContacts = bio.ReadUInt8();
840 // Verify packet is expected size
841 CHECK_PACKET_EXACT_SIZE(16+1 + (16+4+2+2+1)*numContacts);
843 // is this a search for firewallcheck ips?
844 bool isFirewallUDPCheckSearch = false;
845 if (CUDPFirewallTester::IsFWCheckUDPRunning() && CSearchManager::IsFWCheckUDPSearch(target)) {
846 isFirewallUDPCheckSearch = true;
849 CScopedPtr<ContactList> results(new ContactList);
850 for (uint8_t i = 0; i < numContacts; i++) {
851 CUInt128 id = bio.ReadUInt128();
852 uint32_t contactIP = bio.ReadUInt32();
853 uint16_t contactPort = bio.ReadUInt16();
854 uint16_t tport = bio.ReadUInt16();
855 uint8_t version = bio.ReadUInt8();
856 uint32_t hostIP = wxUINT32_SWAP_ALWAYS(contactIP);
857 if (::IsGoodIPPort(hostIP, contactPort)) {
858 if (!theApp->ipfilter->IsFiltered(hostIP) && !(contactPort == 53 && version <= 5) /*No DNS Port without encryption*/) {
859 if (isFirewallUDPCheckSearch) {
860 // UDP FirewallCheck searches are special. The point is we need an IP which we didn't sent an UDP message yet
861 // (or in the near future), so we do not try to add those contacts to our routingzone and we also don't
862 // deliver them back to the searchmanager (because he would UDP-ask them for further results), but only report
863 // them to FirewallChecker - this will of course cripple the search but thats not the point, since we only
864 // care for IPs and not the random set target
865 CUDPFirewallTester::AddPossibleTestContact(id, contactIP, contactPort, tport, target, version, 0, false);
866 } else {
867 routingZone->AddUnfiltered(id, contactIP, contactPort, tport, version, 0, false, false);
868 results->push_back(new CContact(id, contactIP, contactPort, tport, version, 0, false, target));
874 CSearchManager::ProcessResponse(target, ip, port, results.release());
877 void CKademliaUDPListener::Free(SSearchTerm* pSearchTerms)
879 if (pSearchTerms) {
880 Free(pSearchTerms->left);
881 Free(pSearchTerms->right);
882 delete pSearchTerms;
886 SSearchTerm* CKademliaUDPListener::CreateSearchExpressionTree(CMemFile& bio, int iLevel)
888 // the max. depth has to match our own limit for creating the search expression
889 // (see also 'ParsedSearchExpression' and 'GetSearchPacket')
890 if (iLevel >= 24){
891 AddDebugLogLineM(false, logKadSearch, wxT("***NOTE: Search expression tree exceeds depth limit!"));
892 return NULL;
894 iLevel++;
896 uint8_t op = bio.ReadUInt8();
897 if (op == 0x00) {
898 uint8_t boolop = bio.ReadUInt8();
899 if (boolop == 0x00) { // AND
900 SSearchTerm* pSearchTerm = new SSearchTerm;
901 pSearchTerm->type = SSearchTerm::AND;
902 //TRACE(" AND");
903 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
904 wxFAIL;
905 delete pSearchTerm;
906 return NULL;
908 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
909 wxFAIL;
910 Free(pSearchTerm->left);
911 delete pSearchTerm;
912 return NULL;
914 return pSearchTerm;
915 } else if (boolop == 0x01) { // OR
916 SSearchTerm* pSearchTerm = new SSearchTerm;
917 pSearchTerm->type = SSearchTerm::OR;
918 //TRACE(" OR");
919 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
920 wxFAIL;
921 delete pSearchTerm;
922 return NULL;
924 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
925 wxFAIL;
926 Free(pSearchTerm->left);
927 delete pSearchTerm;
928 return NULL;
930 return pSearchTerm;
931 } else if (boolop == 0x02) { // NOT
932 SSearchTerm* pSearchTerm = new SSearchTerm;
933 pSearchTerm->type = SSearchTerm::NOT;
934 //TRACE(" NOT");
935 if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
936 wxFAIL;
937 delete pSearchTerm;
938 return NULL;
940 if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
941 wxFAIL;
942 Free(pSearchTerm->left);
943 delete pSearchTerm;
944 return NULL;
946 return pSearchTerm;
947 } else{
948 AddDebugLogLineM(false, logKadSearch, wxString::Format(wxT("*** Unknown boolean search operator 0x%02x (CreateSearchExpressionTree)"), boolop));
949 return NULL;
951 } else if (op == 0x01) { // String
952 wxString str(bio.ReadString(true));
954 // Make lowercase, the search code expects lower case strings!
955 str.MakeLower();
957 SSearchTerm* pSearchTerm = new SSearchTerm;
958 pSearchTerm->type = SSearchTerm::String;
959 pSearchTerm->astr = new wxArrayString;
961 // pre-tokenize the string term
962 //#warning TODO: TokenizeOptQuotedSearchTerm
963 wxStringTokenizer token(str, CSearchManager::GetInvalidKeywordChars(),wxTOKEN_DEFAULT );
964 while (token.HasMoreTokens()) {
965 wxString strTok(token.GetNextToken());
966 if (!strTok.IsEmpty()) {
967 pSearchTerm->astr->Add(strTok);
971 return pSearchTerm;
972 } else if (op == 0x02) { // Meta tag
973 // read tag value
974 wxString strValue(bio.ReadString(true));
975 // Make lowercase, the search code expects lower case strings!
976 strValue.MakeLower();
978 // read tag name
979 wxString strTagName = bio.ReadString(false);
981 SSearchTerm* pSearchTerm = new SSearchTerm;
982 pSearchTerm->type = SSearchTerm::MetaTag;
983 pSearchTerm->tag = new CTagString(strTagName, strValue);
984 return pSearchTerm;
986 else if (op == 0x03 || op == 0x08) { // Numeric relation (0x03=32-bit or 0x08=64-bit)
987 static const struct {
988 SSearchTerm::ESearchTermType eSearchTermOp;
989 wxString pszOp;
990 } _aOps[] =
992 { SSearchTerm::OpEqual, wxT("=") }, // mmop=0x00
993 { SSearchTerm::OpGreater, wxT(">") }, // mmop=0x01
994 { SSearchTerm::OpLess, wxT("<") }, // mmop=0x02
995 { SSearchTerm::OpGreaterEqual, wxT(">=") }, // mmop=0x03
996 { SSearchTerm::OpLessEqual, wxT("<=") }, // mmop=0x04
997 { SSearchTerm::OpNotEqual, wxT("<>") } // mmop=0x05
1000 // read tag value
1001 uint64_t ullValue = (op == 0x03) ? bio.ReadUInt32() : bio.ReadUInt64();
1003 // read integer operator
1004 uint8_t mmop = bio.ReadUInt8();
1005 if (mmop >= itemsof(_aOps)){
1006 AddDebugLogLineM(false, logKadSearch, wxString::Format(wxT("*** Unknown integer search op=0x%02x (CreateSearchExpressionTree)"), mmop));
1007 return NULL;
1010 // read tag name
1011 wxString strTagName = bio.ReadString(false);
1013 SSearchTerm* pSearchTerm = new SSearchTerm;
1014 pSearchTerm->type = _aOps[mmop].eSearchTermOp;
1015 pSearchTerm->tag = new CTagVarInt(strTagName, ullValue);
1017 return pSearchTerm;
1018 } else {
1019 AddDebugLogLineM(false, logKadSearch, wxString::Format(wxT("*** Unknown search op=0x%02x (CreateSearchExpressionTree)"), op));
1020 return NULL;
1024 // KADEMLIA_SEARCH_REQ
1025 // Used in Kad1.0 only
1026 void CKademliaUDPListener::ProcessSearchRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
1028 // Verify packet is expected size
1029 CHECK_PACKET_MIN_SIZE(17);
1031 CMemFile bio(packetData, lenPacket);
1032 CUInt128 target = bio.ReadUInt128();
1033 uint8_t restrictive = bio.ReadUInt8();
1035 if (lenPacket == 17) {
1036 if (restrictive) {
1037 // Source request
1038 CKademlia::GetIndexed()->SendValidSourceResult(target, ip, port, false, 0, 0, 0);
1039 } else {
1040 // Single keyword request
1041 CKademlia::GetIndexed()->SendValidKeywordResult(target, NULL, ip, port, true, false, 0, 0);
1043 } else if (lenPacket > 17) {
1044 SSearchTerm* pSearchTerms = NULL;
1045 bool oldClient = true;
1046 if (restrictive) {
1047 pSearchTerms = CreateSearchExpressionTree(bio, 0);
1048 if (pSearchTerms == NULL) {
1049 throw wxString(wxT("Invalid search expression"));
1051 if (restrictive > 1) {
1052 oldClient = false;
1054 } else {
1055 oldClient = false;
1058 // Keyword request with added options.
1059 CKademlia::GetIndexed()->SendValidKeywordResult(target, pSearchTerms, ip, port, oldClient, false, 0, 0);
1060 Free(pSearchTerms);
1064 // KADEMLIA2_SEARCH_KEY_REQ
1065 // Used in Kad2.0 only
1066 void CKademliaUDPListener::Process2SearchKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1068 CMemFile bio(packetData, lenPacket);
1069 CUInt128 target = bio.ReadUInt128();
1070 uint16_t startPosition = bio.ReadUInt16();
1071 bool restrictive = ((startPosition & 0x8000) == 0x8000);
1072 startPosition &= 0x7FFF;
1073 SSearchTerm* pSearchTerms = NULL;
1074 if (restrictive) {
1075 pSearchTerms = CreateSearchExpressionTree(bio, 0);
1076 if (pSearchTerms == NULL) {
1077 throw wxString(wxT("Invalid search expression"));
1080 CKademlia::GetIndexed()->SendValidKeywordResult(target, pSearchTerms, ip, port, false, true, startPosition, senderKey);
1081 if (pSearchTerms) {
1082 Free(pSearchTerms);
1086 // KADEMLIA2_SEARCH_SOURCE_REQ
1087 // Used in Kad2.0 only
1088 void CKademliaUDPListener::Process2SearchSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1090 CMemFile bio(packetData, lenPacket);
1091 CUInt128 target = bio.ReadUInt128();
1092 uint16_t startPosition = (bio.ReadUInt16() & 0x7FFF);
1093 uint64_t fileSize = bio.ReadUInt64();
1094 CKademlia::GetIndexed()->SendValidSourceResult(target, ip, port, true, startPosition, fileSize, senderKey);
1097 // KADEMLIA_SEARCH_RES
1098 // Used in Kad1.0 only
1099 void CKademliaUDPListener::ProcessSearchResponse(const uint8_t *packetData, uint32_t lenPacket)
1101 // Verify packet is expected size
1102 CHECK_PACKET_MIN_SIZE(37);
1104 // What search does this relate to
1105 CMemFile bio(packetData, lenPacket);
1106 CUInt128 target = bio.ReadUInt128();
1108 // How many results.. Not supported yet..
1109 uint16_t count = bio.ReadUInt16();
1110 while (count > 0) {
1111 // What is the answer
1112 CUInt128 answer = bio.ReadUInt128();
1114 // Get info about answer
1115 // NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
1116 // case we did not receive an UTF8 string. this is for backward compatibility for search results which are
1117 // supposed to be 'viewed' by user only and not feed into the Kad engine again!
1118 // If that tag list is once used for something else than for viewing, special care has to be taken for any
1119 // string conversion!
1120 TagPtrList* tags = new TagPtrList;
1121 try {
1122 bio.ReadTagPtrList(tags, true/*bOptACP*/);
1123 } catch(...) {
1124 //DebugClientOutput(wxT("CKademliaUDPListener::processSearchResponse"),ip,port,packetData,lenPacket);
1125 deleteTagPtrListEntries(tags);
1126 delete tags;
1127 tags = NULL;
1128 throw;
1130 CSearchManager::ProcessResult(target, answer, tags);
1131 count--;
1135 // KADEMLIA2_SEARCH_RES
1136 // Used in Kad2.0 only
1137 void CKademliaUDPListener::Process2SearchResponse(const uint8_t *packetData, uint32_t lenPacket, const CKadUDPKey& WXUNUSED(senderKey))
1139 CMemFile bio(packetData, lenPacket);
1141 // Who sent this packet.
1142 CUInt128 source = bio.ReadUInt128();
1144 // What search does this relate to
1145 CUInt128 target = bio.ReadUInt128();
1147 // Total results.
1148 uint16_t count = bio.ReadUInt16();
1149 while (count > 0) {
1150 // What is the answer
1151 CUInt128 answer = bio.ReadUInt128();
1153 // Get info about answer
1154 // NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
1155 // case we did not receive an UTF8 string. this is for backward compatibility for search results which are
1156 // supposed to be 'viewed' by user only and not feed into the Kad engine again!
1157 // If that tag list is once used for something else than for viewing, special care has to be taken for any
1158 // string conversion!
1159 TagPtrList* tags = new TagPtrList;
1160 try {
1161 bio.ReadTagPtrList(tags, true);
1162 } catch(...) {
1163 deleteTagPtrListEntries(tags);
1164 delete tags;
1165 tags = NULL;
1166 throw;
1168 CSearchManager::ProcessResult(target, answer, tags);
1169 count--;
1173 // KADEMLIA_PUBLISH_REQ
1174 // Used in Kad1.0 only
1175 void CKademliaUDPListener::ProcessPublishRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
1177 //There are different types of publishing..
1178 //Keyword and File are Stored..
1179 // Verify packet is expected size
1180 CHECK_PACKET_MIN_SIZE(37);
1182 //Used Pointers
1183 CIndexed *indexed = CKademlia::GetIndexed();
1185 // check if we are UDP firewalled
1186 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1187 //We are firewalled. We should not index this entry and give publisher a false report.
1188 return;
1191 CMemFile bio(packetData, lenPacket);
1192 CUInt128 file = bio.ReadUInt128();
1194 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1195 distance.XOR(file);
1197 if (thePrefs::FilterLanIPs() && distance.Get32BitChunk(0) > SEARCHTOLERANCE) {
1198 return;
1201 wxString strInfo;
1202 uint16_t count = bio.ReadUInt16();
1203 bool flag = false;
1204 uint8_t load = 0;
1205 while (count > 0) {
1206 strInfo.Clear();
1208 CUInt128 target = bio.ReadUInt128();
1210 Kademlia::CKeyEntry* entry = new Kademlia::CKeyEntry();
1211 try {
1212 entry->m_uIP = ip;
1213 entry->m_uUDPport = port;
1214 entry->m_uKeyID.SetValue(file);
1215 entry->m_uSourceID.SetValue(target);
1216 uint32_t tags = bio.ReadUInt8();
1217 while (tags > 0) {
1218 CTag* tag = bio.ReadTag();
1219 if (tag) {
1220 if (!tag->GetName().Cmp(TAG_SOURCETYPE)) {
1221 if (entry->m_bSource == false) {
1222 entry->AddTag(new CTagVarInt(TAG_SOURCEIP, entry->m_uIP));
1223 entry->AddTag(new CTagVarInt(TAG_SOURCEUPORT, entry->m_uUDPport));
1224 entry->AddTag(tag);
1225 entry->m_bSource = true;
1226 } else {
1227 //More than one sourcetype tag found.
1228 delete tag;
1230 } else if (!tag->GetName().Cmp(TAG_FILENAME)) {
1231 if (entry->GetCommonFileName().IsEmpty()) {
1232 entry->SetFileName(tag->GetStr());
1233 strInfo += CFormat(wxT(" Name=\"%s\"")) % tag->GetStr();
1235 delete tag;
1236 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1237 if (entry->m_uSize == 0) {
1238 if (tag->IsBsob() && (tag->GetBsobSize() == 8)) {
1239 // Kad1.0 uint64 type using a BSOB.
1240 entry->m_uSize = PeekUInt64(tag->GetBsob());
1241 } else {
1242 wxASSERT(tag->IsInt());
1243 entry->m_uSize = tag->GetInt();
1245 strInfo += wxString::Format(wxT(" Size=%") wxLongLongFmtSpec wxT("u"), entry->m_uSize);
1247 delete tag;
1248 } else if (!tag->GetName().Cmp(TAG_SOURCEPORT)) {
1249 if (entry->m_uTCPport == 0) {
1250 entry->m_uTCPport = tag->GetInt();
1251 entry->AddTag(tag);
1252 } else {
1253 //More than one port tag found
1254 delete tag;
1256 } else {
1257 //TODO: Filter tags
1258 entry->AddTag(tag);
1261 tags--;
1263 if (!strInfo.IsEmpty()) {
1264 AddDebugLogLineM(false, logClientKadUDP, strInfo);
1266 } catch(...) {
1267 //printf("Error on count %i tag %i\n",totalcount-count, totaltags-tags);
1268 //DebugClientOutput(wxT("CKademliaUDPListener::processPublishRequest"),ip,port,packetData,lenPacket);
1269 delete entry;
1270 throw;
1273 if (entry->m_bSource == true) {
1274 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMES;
1275 CEntry *sourceEntry = entry->Copy(); // "downcast" since we didnt knew before if this was a keyword, Kad1 support gets removed soon anyway no need for a beautiful solution here
1276 delete entry;
1277 entry = NULL;
1278 if (indexed->AddSources(file, target, sourceEntry, load)) {
1279 flag = true;
1280 } else {
1281 delete sourceEntry;
1282 sourceEntry = NULL;
1284 } else {
1285 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMEK;
1286 if (indexed->AddKeyword(file, target, entry, load)) {
1287 // This makes sure we send a publish response..
1288 // This also makes sure we index all the files for this keyword.
1289 flag = true;
1290 } else {
1291 //We already indexed the maximum number of keywords.
1292 //We do not index anymore but we still send a success..
1293 //Reason: Because if a VERY busy node tells the publisher it failed,
1294 //this busy node will spread to all the surrounding nodes causing popular
1295 //keywords to be stored on MANY nodes..
1296 //So, once we are full, we will periodically clean our list until we can
1297 //begin storing again..
1298 flag = true;
1299 delete entry;
1300 entry = NULL;
1303 count--;
1305 if (flag) {
1306 CMemFile packetdata(17);
1307 packetdata.WriteUInt128(file);
1308 packetdata.WriteUInt8(load);
1310 DebugSend(KadPublishRes, ip, port);
1311 SendPacket(packetdata, KADEMLIA_PUBLISH_RES, ip, port, 0, NULL);
1315 // KADEMLIA2_PUBLISH_KEY_REQ
1316 // Used in Kad2.0 only
1317 void CKademliaUDPListener::Process2PublishKeyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1319 //Used Pointers
1320 CIndexed *indexed = CKademlia::GetIndexed();
1322 // check if we are UDP firewalled
1323 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1324 //We are firewalled. We should not index this entry and give publisher a false report.
1325 return;
1328 CMemFile bio(packetData, lenPacket);
1329 CUInt128 file = bio.ReadUInt128();
1331 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1332 distance.XOR(file);
1334 // Shouldn't LAN IPs already be filtered?
1335 if (thePrefs::FilterLanIPs() && distance.Get32BitChunk(0) > SEARCHTOLERANCE) {
1336 return;
1339 wxString strInfo;
1340 uint16_t count = bio.ReadUInt16();
1341 uint8_t load = 0;
1342 while (count > 0) {
1343 strInfo.Clear();
1345 CUInt128 target = bio.ReadUInt128();
1347 Kademlia::CKeyEntry* entry = new Kademlia::CKeyEntry();
1350 entry->m_uIP = ip;
1351 entry->m_uUDPport = port;
1352 entry->m_uKeyID.SetValue(file);
1353 entry->m_uSourceID.SetValue(target);
1354 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMEK;
1355 entry->m_bSource = false;
1356 uint32_t tags = bio.ReadUInt8();
1357 while (tags > 0) {
1358 CTag* tag = bio.ReadTag();
1359 if (tag) {
1360 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1361 if (entry->GetCommonFileName().IsEmpty()) {
1362 entry->SetFileName(tag->GetStr());
1363 strInfo += CFormat(wxT(" Name=\"%s\"")) % entry->GetCommonFileName();
1365 delete tag; // tag is no longer stored, but membervar is used
1366 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1367 if (entry->m_uSize == 0) {
1368 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1369 entry->m_uSize = PeekUInt64(tag->GetBsob());
1370 } else {
1371 entry->m_uSize = tag->GetInt();
1373 strInfo += wxString::Format(wxT(" Size=%") wxLongLongFmtSpec wxT("u"), entry->m_uSize);
1375 delete tag; // tag is no longer stored, but membervar is used
1376 } else {
1377 //TODO: Filter tags
1378 entry->AddTag(tag);
1381 tags--;
1383 if (!strInfo.IsEmpty()) {
1384 AddDebugLogLineM(false, logClientKadUDP, strInfo);
1386 } catch(...) {
1387 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishKeyRequest"),ip,port,packetData,lenPacket);
1388 delete entry;
1389 throw;
1392 if (!indexed->AddKeyword(file, target, entry, load)) {
1393 //We already indexed the maximum number of keywords.
1394 //We do not index anymore but we still send a success..
1395 //Reason: Because if a VERY busy node tells the publisher it failed,
1396 //this busy node will spread to all the surrounding nodes causing popular
1397 //keywords to be stored on MANY nodes..
1398 //So, once we are full, we will periodically clean our list until we can
1399 //begin storing again..
1400 delete entry;
1401 entry = NULL;
1403 count--;
1405 CMemFile packetdata(17);
1406 packetdata.WriteUInt128(file);
1407 packetdata.WriteUInt8(load);
1408 DebugSend(Kad2PublishRes, ip, port);
1409 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1412 // KADEMLIA2_PUBLISH_SOURCE_REQ
1413 // Used in Kad2.0 only
1414 void CKademliaUDPListener::Process2PublishSourceRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1416 //Used Pointers
1417 CIndexed *indexed = CKademlia::GetIndexed();
1419 // check if we are UDP firewalled
1420 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1421 //We are firewalled. We should not index this entry and give publisher a false report.
1422 return;
1425 CMemFile bio(packetData, lenPacket);
1426 CUInt128 file = bio.ReadUInt128();
1428 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1429 distance.XOR(file);
1431 if (thePrefs::FilterLanIPs() && distance.Get32BitChunk(0) > SEARCHTOLERANCE) {
1432 return;
1435 wxString strInfo;
1436 uint8_t load = 0;
1437 bool flag = false;
1438 CUInt128 target = bio.ReadUInt128();
1439 Kademlia::CEntry* entry = new Kademlia::CEntry();
1440 try {
1441 entry->m_uIP = ip;
1442 entry->m_uUDPport = port;
1443 entry->m_uKeyID.SetValue(file);
1444 entry->m_uSourceID.SetValue(target);
1445 entry->m_bSource = false;
1446 entry->m_tLifeTime = (uint32_t)time(NULL) + KADEMLIAREPUBLISHTIMES;
1447 bool addUDPPortTag = true;
1448 uint32_t tags = bio.ReadUInt8();
1449 while (tags > 0) {
1450 CTag* tag = bio.ReadTag();
1451 if (tag) {
1452 if (!tag->GetName().Cmp(TAG_SOURCETYPE)) {
1453 if (entry->m_bSource == false) {
1454 entry->AddTag(new CTagVarInt(TAG_SOURCEIP, entry->m_uIP));
1455 entry->AddTag(tag);
1456 entry->m_bSource = true;
1457 } else {
1458 //More than one sourcetype tag found.
1459 delete tag;
1461 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1462 if (entry->m_uSize == 0) {
1463 if (tag->IsBsob() && tag->GetBsobSize() == 8) {
1464 entry->m_uSize = PeekUInt64(tag->GetBsob());
1465 } else {
1466 entry->m_uSize = tag->GetInt();
1468 strInfo += wxString::Format(wxT(" Size=%") wxLongLongFmtSpec wxT("u"), entry->m_uSize);
1470 delete tag;
1471 } else if (!tag->GetName().Cmp(TAG_SOURCEPORT)) {
1472 if (entry->m_uTCPport == 0) {
1473 entry->m_uTCPport = (uint16_t)tag->GetInt();
1474 entry->AddTag(tag);
1475 } else {
1476 //More than one port tag found
1477 delete tag;
1479 } else if (!tag->GetName().Cmp(TAG_SOURCEUPORT)) {
1480 if (addUDPPortTag && tag->IsInt() && tag->GetInt() != 0) {
1481 entry->m_uUDPport = (uint16_t)tag->GetInt();
1482 entry->AddTag(tag);
1483 addUDPPortTag = false;
1484 } else {
1485 //More than one udp port tag found
1486 delete tag;
1488 } else {
1489 //TODO: Filter tags
1490 entry->AddTag(tag);
1493 tags--;
1495 if (addUDPPortTag) {
1496 entry->AddTag(new CTagVarInt(TAG_SOURCEUPORT, entry->m_uUDPport));
1498 if (!strInfo.IsEmpty()) {
1499 AddDebugLogLineM(false, logClientKadUDP, strInfo);
1501 } catch(...) {
1502 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishSourceRequest"),ip,port,packetData,lenPacket);
1503 delete entry;
1504 throw;
1507 if (entry->m_bSource == true) {
1508 if (indexed->AddSources(file, target, entry, load)) {
1509 flag = true;
1510 } else {
1511 delete entry;
1512 entry = NULL;
1514 } else {
1515 delete entry;
1516 entry = NULL;
1518 if (flag) {
1519 CMemFile packetdata(17);
1520 packetdata.WriteUInt128(file);
1521 packetdata.WriteUInt8(load);
1522 DebugSend(Kad2PublishRes, ip, port);
1523 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1527 // KADEMLIA_PUBLISH_RES
1528 // Used only by Kad1.0
1529 void CKademliaUDPListener::ProcessPublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1531 // Verify packet is expected size
1532 CHECK_PACKET_MIN_SIZE(16);
1533 CHECK_TRACKED_PACKET(KADEMLIA_PUBLISH_REQ);
1535 CMemFile bio(packetData, lenPacket);
1536 CUInt128 file = bio.ReadUInt128();
1538 bool loadResponse = false;
1539 uint8_t load = 0;
1540 if (bio.GetLength() > bio.GetPosition()) {
1541 loadResponse = true;
1542 load = bio.ReadUInt8();
1545 CSearchManager::ProcessPublishResult(file, load, loadResponse);
1548 // KADEMLIA2_PUBLISH_RES
1549 // Used only by Kad2.0
1550 void CKademliaUDPListener::Process2PublishResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, const CKadUDPKey& WXUNUSED(senderKey))
1552 if (!IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_KEY_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_SOURCE_REQ) && !IsOnOutTrackList(ip, KADEMLIA2_PUBLISH_NOTES_REQ)) {
1553 throw wxString::Format(wxT("***NOTE: Received unrequested response packet, size (%u) in "), lenPacket) + wxString::FromAscii(__FUNCTION__);
1555 CMemFile bio(packetData, lenPacket);
1556 CUInt128 file = bio.ReadUInt128();
1557 uint8_t load = bio.ReadUInt8();
1558 CSearchManager::ProcessPublishResult(file, load, true);
1561 // KADEMLIA_SEARCH_NOTES_REQ
1562 // Used only by Kad1.0
1563 void CKademliaUDPListener::ProcessSearchNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
1565 // Verify packet is expected size
1566 CHECK_PACKET_MIN_SIZE(32);
1568 CMemFile bio(packetData, lenPacket);
1569 CUInt128 target = bio.ReadUInt128();
1570 // This info is currently not used.
1571 // CUInt128 source = bio.ReadUInt128();
1573 CKademlia::GetIndexed()->SendValidNoteResult(target, ip, port, false, 0, 0);
1576 // KADEMLIA2_SEARCH_NOTES_REQ
1577 // Used only by Kad2.0
1578 void CKademliaUDPListener::Process2SearchNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1580 CMemFile bio(packetData, lenPacket);
1581 CUInt128 target = bio.ReadUInt128();
1582 uint64_t fileSize = bio.ReadUInt64();
1583 CKademlia::GetIndexed()->SendValidNoteResult(target, ip, port, true, fileSize, senderKey);
1586 // KADEMLIA_SEARCH_NOTES_RES
1587 // Used only by Kad1.0
1588 void CKademliaUDPListener::ProcessSearchNotesResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1590 // Verify packet is expected size
1591 CHECK_PACKET_MIN_SIZE(37);
1592 CHECK_TRACKED_PACKET(KADEMLIA_SEARCH_NOTES_REQ);
1594 // What search does this relate to
1595 CMemFile bio(packetData, lenPacket);
1596 CUInt128 target = bio.ReadUInt128();
1598 uint16_t count = bio.ReadUInt16();
1599 while (count > 0) {
1600 // What is the answer
1601 CUInt128 answer = bio.ReadUInt128();
1603 // Get info about answer
1604 // NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
1605 // case we did not receive an UTF8 string. this is for backward compatibility for search results which are
1606 // supposed to be 'viewed' by user only and not feed into the Kad engine again!
1607 // If that tag list is once used for something else than for viewing, special care has to be taken for any
1608 // string conversion!
1609 TagPtrList* tags = new TagPtrList;
1610 try {
1611 bio.ReadTagPtrList(tags, true/*bOptACP*/);
1612 } catch(...){
1613 //DebugClientOutput(wxT("CKademliaUDPListener::processSearchNotesResponse"),ip,port,packetData,lenPacket);
1614 deleteTagPtrListEntries(tags);
1615 delete tags;
1616 tags = NULL;
1617 throw;
1619 CSearchManager::ProcessResult(target, answer, tags);
1620 count--;
1624 // KADEMLIA_PUBLISH_NOTES_REQ
1625 // Used only by Kad1.0
1626 void CKademliaUDPListener::ProcessPublishNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port)
1628 // Verify packet is expected size
1629 CHECK_PACKET_MIN_SIZE(37);
1631 // check if we are UDP firewalled
1632 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1633 //We are firewalled. We should not index this entry and give publisher a false report.
1634 return;
1637 CMemFile bio(packetData, lenPacket);
1638 CUInt128 target = bio.ReadUInt128();
1640 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1641 distance.XOR(target);
1643 if( thePrefs::FilterLanIPs() && distance.Get32BitChunk(0) > SEARCHTOLERANCE) {
1644 return;
1647 CUInt128 source = bio.ReadUInt128();
1649 Kademlia::CEntry* entry = new Kademlia::CEntry();
1650 try {
1651 entry->m_uIP = ip;
1652 entry->m_uUDPport = port;
1653 entry->m_uKeyID.SetValue(target);
1654 entry->m_uSourceID.SetValue(source);
1655 uint32_t tagCount = bio.ReadUInt8();
1656 while (tagCount > 0) {
1657 CTag *tag = bio.ReadTag();
1658 if (tag) {
1659 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1660 if (entry->GetCommonFileName().IsEmpty()) {
1661 entry->SetFileName(tag->GetStr());
1663 delete tag;
1664 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1665 if (entry->m_uSize == 0) {
1666 entry->m_uSize = tag->GetInt();
1668 delete tag;
1669 } else {
1670 //TODO: Filter tags
1671 entry->AddTag(tag);
1674 tagCount--;
1676 entry->m_bSource = false;
1677 } catch(...) {
1678 //DebugClientOutput(wxT("CKademliaUDPListener::processPublishNotesRequest"),ip,port,packetData,lenPacket);
1679 delete entry;
1680 entry = NULL;
1681 throw;
1684 if (entry == NULL) {
1685 throw wxString(wxT("CKademliaUDPListener::processPublishNotesRequest: entry == NULL"));
1686 } else if (entry->GetTagCount() == 0 || entry->GetTagCount() > 5) {
1687 delete entry;
1688 throw wxString(wxT("CKademliaUDPListener::processPublishNotesRequest: entry->GetTagCount() == 0 || entry->GetTagCount() > 5"));
1691 uint8_t load = 0;
1692 if (CKademlia::GetIndexed()->AddNotes(target, source, entry, load)) {
1693 CMemFile packetdata(17);
1694 packetdata.WriteUInt128(target);
1695 packetdata.WriteUInt8(load);
1696 DebugSend(KadPublishNotesRes, ip, port);
1697 SendPacket(packetdata, KADEMLIA_PUBLISH_NOTES_RES, ip, port, 0, NULL);
1698 } else {
1699 delete entry;
1703 // KADEMLIA2_PUBLISH_NOTES_REQ
1704 // Used only by Kad2.0
1705 void CKademliaUDPListener::Process2PublishNotesRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1707 // check if we are UDP firewalled
1708 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
1709 //We are firewalled. We should not index this entry and give publisher a false report.
1710 return;
1713 CMemFile bio(packetData, lenPacket);
1714 CUInt128 target = bio.ReadUInt128();
1716 CUInt128 distance(CKademlia::GetPrefs()->GetKadID());
1717 distance.XOR(target);
1719 // Shouldn't LAN IPs already be filtered?
1720 if (thePrefs::FilterLanIPs() && distance.Get32BitChunk(0) > SEARCHTOLERANCE) {
1721 return;
1724 CUInt128 source = bio.ReadUInt128();
1726 Kademlia::CEntry* entry = new Kademlia::CEntry();
1727 try {
1728 entry->m_uIP = ip;
1729 entry->m_uUDPport = port;
1730 entry->m_uKeyID.SetValue(target);
1731 entry->m_uSourceID.SetValue(source);
1732 entry->m_bSource = false;
1733 uint32_t tags = bio.ReadUInt8();
1734 while (tags > 0) {
1735 CTag* tag = bio.ReadTag();
1736 if(tag) {
1737 if (!tag->GetName().Cmp(TAG_FILENAME)) {
1738 if (entry->GetCommonFileName().IsEmpty()) {
1739 entry->SetFileName(tag->GetStr());
1741 delete tag;
1742 } else if (!tag->GetName().Cmp(TAG_FILESIZE)) {
1743 if (entry->m_uSize == 0) {
1744 entry->m_uSize = tag->GetInt();
1746 delete tag;
1747 } else {
1748 //TODO: Filter tags
1749 entry->AddTag(tag);
1752 tags--;
1754 } catch(...) {
1755 //DebugClientOutput(wxT("CKademliaUDPListener::Process2PublishNotesRequest"),ip,port,packetData,lenPacket);
1756 delete entry;
1757 entry = NULL;
1758 throw;
1761 uint8_t load = 0;
1762 if (CKademlia::GetIndexed()->AddNotes(target, source, entry, load)) {
1763 CMemFile packetdata(17);
1764 packetdata.WriteUInt128(target);
1765 packetdata.WriteUInt8(load);
1766 DebugSend(Kad2PublishRes, ip, port);
1767 SendPacket(packetdata, KADEMLIA2_PUBLISH_RES, ip, port, senderKey, NULL);
1768 } else {
1769 delete entry;
1773 // KADEMLIA_PUBLISH_NOTES_RES
1774 // Used only by Kad1.0
1775 void CKademliaUDPListener::ProcessPublishNotesResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1777 // Verify packet is expected size
1778 CHECK_PACKET_MIN_SIZE(16);
1779 CHECK_TRACKED_PACKET(KADEMLIA_PUBLISH_NOTES_REQ);
1781 CMemFile bio(packetData, lenPacket);
1782 CUInt128 file = bio.ReadUInt128();
1784 bool loadResponse = false;
1785 uint8_t load = 0;
1786 if( bio.GetLength() > bio.GetPosition() ) {
1787 loadResponse = true;
1788 load = bio.ReadUInt8();
1791 CSearchManager::ProcessPublishResult(file, load, loadResponse);
1794 // KADEMLIA_FIREWALLED_REQ
1795 // Used by Kad1.0 and Kad2.0
1796 void CKademliaUDPListener::ProcessFirewalledRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1798 // Verify packet is expected size
1799 CHECK_PACKET_EXACT_SIZE(2);
1801 CMemFile bio(packetData, lenPacket);
1802 uint16_t tcpport = bio.ReadUInt16();
1804 CUInt128 zero;
1805 CContact contact(zero, ip, port, tcpport, 0, 0, false, zero);
1806 if (!theApp->clientlist->RequestTCP(&contact, 0)) {
1807 return; // cancelled for some reason, don't send a response
1810 // Send response
1811 CMemFile packetdata(4);
1812 packetdata.WriteUInt32(ip);
1813 DebugSend(KadFirewalledRes, ip, port);
1814 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1817 // KADEMLIA_FIREWALLED2_REQ
1818 // Used by Kad2.0 Prot.Version 7+
1819 void CKademliaUDPListener::ProcessFirewalled2Request(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1821 // Verify packet is expected size
1822 CHECK_PACKET_MIN_SIZE(19);
1824 CMemFile bio(packetData, lenPacket);
1825 uint16_t tcpPort = bio.ReadUInt16();
1826 CUInt128 userID = bio.ReadUInt128();
1827 uint8_t connectOptions = bio.ReadUInt8();
1829 CUInt128 zero;
1830 CContact contact(userID, ip, port, tcpPort, 0, 0, false, zero);
1831 if (!theApp->clientlist->RequestTCP(&contact, connectOptions)) {
1832 return; // cancelled for some reason, don't send a response
1835 // Send response
1836 CMemFile packetdata(4);
1837 packetdata.WriteUInt32(ip);
1838 DebugSend(KadFirewalledRes, ip, port);
1839 SendPacket(packetdata, KADEMLIA_FIREWALLED_RES, ip, port, senderKey, NULL);
1842 // KADEMLIA_FIREWALLED_RES
1843 // Used by Kad1.0 and Kad2.0
1844 void CKademliaUDPListener::ProcessFirewalledResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, const CKadUDPKey& WXUNUSED(senderKey))
1846 // Verify packet is expected size
1847 CHECK_PACKET_EXACT_SIZE(4);
1849 if (!theApp->clientlist->IsKadFirewallCheckIP(wxUINT32_SWAP_ALWAYS(ip))) { /* KADEMLIA_FIREWALLED2_REQ + KADEMLIA_FIREWALLED_REQ */
1850 throw wxString(wxT("Received unrequested firewall response packet in ")) + wxString::FromAscii(__FUNCTION__);
1853 CMemFile bio(packetData, lenPacket);
1854 uint32_t firewalledIP = bio.ReadUInt32();
1856 // Update con state only if something changes.
1857 if (CKademlia::GetPrefs()->GetIPAddress() != firewalledIP) {
1858 CKademlia::GetPrefs()->SetIPAddress(firewalledIP);
1859 theApp->ShowConnectionState();
1861 CKademlia::GetPrefs()->IncRecheckIP();
1864 // KADEMLIA_FIREWALLED_ACK_RES
1865 // Used by Kad1.0 and Kad2.0
1866 void CKademliaUDPListener::ProcessFirewalledAckResponse(uint32_t lenPacket)
1868 // 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.
1869 // But we want the TCP testresult regardless if UDP is firewalled, the new UDP state and test takes care of the rest.
1871 // Verify packet is expected size
1872 CHECK_PACKET_EXACT_SIZE(0);
1874 CKademlia::GetPrefs()->IncFirewalled();
1877 // KADEMLIA_FINDBUDDY_REQ
1878 // Used by Kad1.0 and Kad2.0
1879 void CKademliaUDPListener::ProcessFindBuddyRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1881 // Verify packet is expected size
1882 CHECK_PACKET_MIN_SIZE(34);
1884 if (CKademlia::GetPrefs()->GetFirewalled() || CUDPFirewallTester::IsFirewalledUDP(true) || !CUDPFirewallTester::IsVerified()) {
1885 // We are firewalled but somehow we still got this packet.. Don't send a response..
1886 return;
1887 } else if (theApp->clientlist->GetBuddyStatus() == Connected) {
1888 // we already have a buddy
1889 return;
1892 CMemFile bio(packetData, lenPacket);
1893 CUInt128 BuddyID = bio.ReadUInt128();
1894 CUInt128 userID = bio.ReadUInt128();
1895 uint16_t tcpport = bio.ReadUInt16();
1897 CUInt128 zero;
1898 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1899 if (!theApp->clientlist->IncomingBuddy(&contact, &BuddyID)) {
1900 return; // cancelled for some reason, don't send a response
1903 CMemFile packetdata(34);
1904 packetdata.WriteUInt128(BuddyID);
1905 packetdata.WriteUInt128(CKademlia::GetPrefs()->GetClientHash());
1906 packetdata.WriteUInt16(thePrefs::GetPort());
1907 if (!senderKey.IsEmpty()) { // remove check for later versions
1908 packetdata.WriteUInt8(CPrefs::GetMyConnectOptions(true, false)); // new since 0.49a, old mules will ignore it (hopefully ;) )
1911 DebugSend(KadFindBuddyRes, ip, port);
1912 SendPacket(packetdata, KADEMLIA_FINDBUDDY_RES, ip, port, senderKey, NULL);
1915 // KADEMLIA_FINDBUDDY_RES
1916 // Used by Kad1.0 and Kad2.0
1917 void CKademliaUDPListener::ProcessFindBuddyResponse(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
1919 // Verify packet is expected size
1920 CHECK_PACKET_MIN_SIZE(34);
1921 CHECK_TRACKED_PACKET(KADEMLIA_FINDBUDDY_REQ);
1923 CMemFile bio(packetData, lenPacket);
1924 CUInt128 check = bio.ReadUInt128();
1925 check.XOR(CUInt128(true));
1926 if (CKademlia::GetPrefs()->GetKadID() == check) {
1927 CUInt128 userID = bio.ReadUInt128();
1928 uint16_t tcpport = bio.ReadUInt16();
1929 uint8_t connectOptions = 0;
1930 if (lenPacket > 34) {
1931 // 0.49+ (kad version 7) sends additionally its connect options so we know whether to use an obfuscated connection
1932 connectOptions = bio.ReadUInt8();
1935 CUInt128 zero;
1936 CContact contact(userID, ip, port, tcpport, 0, 0, false, zero);
1937 theApp->clientlist->RequestBuddy(&contact, connectOptions);
1941 // KADEMLIA_CALLBACK_REQ
1942 // Used by Kad1.0 and Kad2.0
1943 void CKademliaUDPListener::ProcessCallbackRequest(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip, uint16_t port, const CKadUDPKey& WXUNUSED(senderKey))
1945 // Verify packet is expected size
1946 CHECK_PACKET_MIN_SIZE(34);
1948 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1949 if (buddy != NULL) {
1950 CMemFile bio(packetData, lenPacket);
1951 CUInt128 check = bio.ReadUInt128();
1952 // JOHNTODO: Begin filtering bad buddy ID's..
1953 // CUInt128 bud(buddy->GetBuddyID());
1954 CUInt128 file = bio.ReadUInt128();
1955 uint16_t tcp = bio.ReadUInt16();
1957 if (buddy->GetSocket()) {
1958 CMemFile packetdata(lenPacket + 6);
1959 packetdata.WriteUInt128(check);
1960 packetdata.WriteUInt128(file);
1961 packetdata.WriteUInt32(ip);
1962 packetdata.WriteUInt16(tcp);
1963 CPacket* packet = new CPacket(packetdata, OP_EMULEPROT, OP_CALLBACK);
1964 DebugSend(KadCallbackReq, ip, port);
1965 buddy->GetSocket()->SendPacket(packet);
1966 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1967 } else {
1968 throw wxString::FromAscii(__FUNCTION__) + wxT(": Buddy has no valid socket");
1973 // KADEMLIA2_PING
1974 void CKademliaUDPListener::Process2Ping(uint32_t ip, uint16_t port, const CKadUDPKey& senderKey)
1976 // can be used just as PING, currently it is however only used to determine one's external port
1977 CMemFile packetdata(2);
1978 packetdata.WriteUInt16(port);
1979 DebugSend(Kad2Pong, ip, port);
1980 SendPacket(packetdata, KADEMLIA2_PONG, ip, port, senderKey, NULL);
1983 // KADEMLIA2_PONG
1984 void CKademliaUDPListener::Process2Pong(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
1986 CHECK_PACKET_MIN_SIZE(2);
1987 CHECK_TRACKED_PACKET(KADEMLIA2_PING);
1989 if (CKademlia::GetPrefs()->GetExternalKadPort() == 0) {
1990 // the reported port doesn't always have to be our true external port, esp. if we used our intern port
1991 // and communicated recently with the client some routers might remember this and assign the intern port as source
1992 // but this shouldn't be a problem because we prefer intern ports anyway.
1993 // might have to be reviewed in later versions when more data is available
1994 CKademlia::GetPrefs()->SetExternKadPort(PeekUInt16(packetData));
1995 AddDebugLogLineM(false, logKadMain, wxString::Format(wxT("Set external Kad Port to %u"), CKademlia::GetPrefs()->GetExternalKadPort()));
1997 if (CUDPFirewallTester::IsFWCheckUDPRunning()) {
1998 CUDPFirewallTester::QueryNextClient();
2001 theApp->ShowConnectionState();
2004 // KADEMLIA2_FIREWALLUDP
2005 void CKademliaUDPListener::Process2FirewallUDP(const uint8_t *packetData, uint32_t lenPacket, uint32_t ip)
2007 // Verify packet is expected size
2008 CHECK_PACKET_MIN_SIZE(3);
2010 uint8_t errorCode = PeekUInt8(packetData);
2011 uint16_t incomingPort = PeekUInt16(packetData + 1);
2012 if (incomingPort != CKademlia::GetPrefs()->GetExternalKadPort() && incomingPort != CKademlia::GetPrefs()->GetInternKadPort()) {
2013 AddDebugLogLineM(false, logClientKadUDP, wxString::Format(wxT("Received UDP FirewallCheck on unexpected incoming port %u (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) + wxT(")"), incomingPort));
2014 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
2015 } else if (errorCode == 0) {
2016 AddDebugLogLineM(false, logClientKadUDP, wxString::Format(wxT("Received UDP FirewallCheck packet from ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) + wxT(" with incoming port %u"), incomingPort));
2017 CUDPFirewallTester::SetUDPFWCheckResult(true, false, ip, incomingPort);
2018 } else {
2019 AddDebugLogLineM(false, logClientKadUDP, wxString::Format(wxT("Received UDP FirewallCheck packet from ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) + wxT(" with incoming port %u with remote errorcode %u - ignoring result"), incomingPort, errorCode));
2020 CUDPFirewallTester::SetUDPFWCheckResult(false, true, ip, 0);
2024 void CKademliaUDPListener::SendPacket(const CMemFile &data, uint8_t opcode, uint32_t destinationHost, uint16_t destinationPort, const CKadUDPKey& targetKey, const CUInt128* cryptTargetID)
2026 AddTrackedOutPacket(destinationHost, opcode);
2027 CPacket* packet = new CPacket(data, OP_KADEMLIAHEADER, opcode);
2028 if (packet->GetPacketSize() > 200) {
2029 packet->PackPacket();
2031 uint8_t cryptData[16];
2032 uint8_t *cryptKey;
2033 if (cryptTargetID != NULL) {
2034 cryptKey = (uint8_t *)&cryptData;
2035 cryptTargetID->StoreCryptValue(cryptKey);
2036 } else {
2037 cryptKey = NULL;
2039 theStats::AddUpOverheadKad(packet->GetPacketSize());
2040 theApp->clientudp->SendPacket(packet, wxUINT32_SWAP_ALWAYS(destinationHost), destinationPort, true, cryptKey, true, targetKey.GetKeyValue(theApp->GetPublicIP(false)));
2043 bool CKademliaUDPListener::FindNodeIDByIP(CKadClientSearcher* requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort)
2045 // send a hello packet to the given IP in order to get a HELLO_RES with the NodeID
2047 // we will drop support for Kad1 soon, so dont bother sending two packets in case we don't know if kad2 is supported
2048 // (if we know that its not, this function isn't called in the first place)
2049 AddDebugLogLineM(false, logClientKadUDP, wxT("FindNodeIDByIP: Requesting NodeID from ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip)) + wxT(" by sending Kad2HelloReq"));
2050 DebugSend(Kad2HelloReq, ip, udpPort);
2051 SendMyDetails(KADEMLIA2_HELLO_REQ, ip, udpPort, true, 0, NULL); // todo: we send this unobfuscated, which is not perfect, see this can be avoided in the future
2052 FetchNodeID_Struct sRequest = { ip, tcpPort, ::GetTickCount() + SEC2MS(60), requester };
2053 m_fetchNodeIDRequests.push_back(sRequest);
2054 return true;
2057 void CKademliaUDPListener::ExpireClientSearch(CKadClientSearcher* expireImmediately)
2059 uint32_t now = ::GetTickCount();
2060 for (FetchNodeIDList::iterator it = m_fetchNodeIDRequests.begin(); it != m_fetchNodeIDRequests.end();) {
2061 FetchNodeIDList::iterator it2 = it++;
2062 if (it2->requester == expireImmediately) {
2063 m_fetchNodeIDRequests.erase(it2);
2065 else if (it2->expire < now) {
2066 it2->requester->KadSearchNodeIDByIPResult(KCSR_TIMEOUT, NULL);
2067 m_fetchNodeIDRequests.erase(it2);
2072 void CKademliaUDPListener::DebugClientOutput(const wxString& place, uint32 kad_ip, uint32 port, const byte* data, int len)
2074 #if THIS_DEBUG_IS_JUST_FOR_KRY_DONT_TOUCH_IT_KTHX
2075 uint32 ip = wxUINT32_SWAP_ALWAYS(kad_ip);
2076 printf("Error on %s received from: %s\n",(const char*)unicode2char(place),(const char*)unicode2char(Uint32_16toStringIP_Port(ip,port)));
2077 if (data) {
2078 printf("Packet dump:\n");
2079 DumpMem(data, len);
2081 CClientList::SourceList clientslist = theApp->clientlist->GetClientsByIP(ip);
2082 if (!clientslist.empty()) {
2083 for (CClientList::SourceList::iterator it = clientslist.begin(); it != clientslist.end(); ++it) {
2084 printf("Ip Matches: %s\n",(const char*)unicode2char((*it)->GetClientFullInfo()));
2086 } else {
2087 printf("No ip match, trying to create a client connection:\n");
2088 printf("Trying port %d\n", port - 10);
2089 CUpDownClient* client = new CUpDownClient(port-10,kad_ip,0,0,NULL,false,false);
2090 client->SetConnectionReason(wxT("Error on ") + place);
2091 client->TryToConnect(true);
2093 #else
2094 // No need for warnings for the rest of us.
2095 (void)place;
2096 (void)kad_ip;
2097 (void)port;
2098 (void)data;
2099 (void)len;
2100 #endif
2102 // File_checked_for_headers