1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2003-2011 Barry Dunne (http://www.emule-project.net)
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
25 //
26 
27 // Note To Mods //
28 /*
29 Please do not change anything here and release it..
30 There is going to be a new forum created just for the Kademlia side of the client..
31 If you feel there is an error or a way to improve something, please
32 post it in the forum first and let us look at it.. If it is a real improvement,
33 it will be added to the offical client.. Changing something without knowing
34 what all it does can cause great harm to the network if released in mass form..
35 Any mod that changes anything within the Kademlia side will not be allowed to advertise
36 there client on the eMule forum..
37 */
38 
39 #include "Kademlia.h" // Interface declarations
40 
41 #include <protocol/kad/Constants.h>
42 
43 #include "Defines.h"
44 #include "Indexed.h"
45 #include "UDPFirewallTester.h"
46 #include "../routing/RoutingZone.h"
47 #include "../utils/KadUDPKey.h"
48 #include "../utils/KadClientSearcher.h"
49 #include "../../amule.h"
50 #include "../../Logger.h"
51 #include <protocol/kad2/Client2Client/UDP.h>
52 
53 #ifdef _MSC_VER  // silly warnings about deprecated functions
54 #pragma warning(disable:4996)
55 #endif
56 
57 const CUInt128	Kademlia::s_nullUInt128(false);
58 
59 ////////////////////////////////////////
60 using namespace Kademlia;
61 ////////////////////////////////////////
62 
63 CKademlia *	CKademlia::instance = NULL;
64 EventMap	CKademlia::m_events;
65 time_t		CKademlia::m_nextSearchJumpStart;
66 time_t		CKademlia::m_nextSelfLookup;
67 time_t		CKademlia::m_statusUpdate;
68 time_t		CKademlia::m_bigTimer;
69 time_t		CKademlia::m_nextFirewallCheck;
70 time_t		CKademlia::m_nextFindBuddy;
71 time_t		CKademlia::m_bootstrap;
72 time_t		CKademlia::m_consolidate;
73 time_t		CKademlia::m_externPortLookup;
74 time_t		CKademlia::m_lanModeCheck = 0;
75 bool		CKademlia::m_running = false;
76 bool		CKademlia::m_lanMode = false;
77 ContactList	CKademlia::s_bootstrapList;
78 std::list<uint32_t>	CKademlia::m_statsEstUsersProbes;
79 
Start(CPrefs * prefs)80 void CKademlia::Start(CPrefs *prefs)
81 {
82 	if (instance) {
83 		// If we already have an instance, something is wrong.
84 		delete prefs;
85 		wxASSERT(instance->m_running);
86 		wxASSERT(instance->m_prefs);
87 		return;
88 	}
89 
90 	// Make sure a prefs was passed in..
91 	if (!prefs) {
92 		return;
93 	}
94 
95 	AddDebugLogLineN(logKadMain, wxT("Starting Kademlia"));
96 
97 	// Init jump start timer.
98 	m_nextSearchJumpStart = time(NULL);
99 	// Force a FindNodeComplete within the first 3 minutes.
100 	m_nextSelfLookup = time(NULL) + MIN2S(3);
101 	// Init status timer.
102 	m_statusUpdate = time(NULL);
103 	// Init big timer for Zones
104 	m_bigTimer = time(NULL);
105 	// First Firewall check is done on connect, init next check.
106 	m_nextFirewallCheck = time(NULL) + (HR2S(1));
107 	// Find a buddy after the first 5mins of starting the client.
108 	// We wait just in case it takes a bit for the client to determine firewall status..
109 	m_nextFindBuddy = time(NULL) + (MIN2S(5));
110 	// Init contact consolidate timer;
111 	m_consolidate = time(NULL) + (MIN2S(45));
112 	// Look up our extern port
113 	m_externPortLookup = time(NULL);
114 	// Init bootstrap time.
115 	m_bootstrap = 0;
116 	// Init our random seed.
117 	srand((uint32_t)time(NULL));
118 	// Create our Kad objects.
119 	instance = new CKademlia();
120 	instance->m_prefs = prefs;
121 	instance->m_indexed = new CIndexed();
122 	instance->m_routingZone = new CRoutingZone();
123 	instance->m_udpListener = new CKademliaUDPListener();
124 	// Mark Kad as running state.
125 	m_running = true;
126 }
127 
128 
Stop()129 void CKademlia::Stop()
130 {
131 	// Make sure we are running to begin with.
132 	if (!m_running) {
133 		return;
134 	}
135 
136 	AddDebugLogLineN(logKadMain, wxT("Stopping Kademlia"));
137 
138 	// Mark Kad as being in the stop state to make sure nothing else is used.
139 	m_running = false;
140 
141 	// Reset Firewallstate
142 	CUDPFirewallTester::Reset();
143 
144 	// Remove all active searches.
145 	CSearchManager::StopAllSearches();
146 
147 	// Delete all Kad Objects.
148 	delete instance->m_udpListener;
149 	instance->m_udpListener = NULL;
150 
151 	delete instance->m_routingZone;
152 	instance->m_routingZone = NULL;
153 
154 	delete instance->m_indexed;
155 	instance->m_indexed = NULL;
156 
157 	delete instance->m_prefs;
158 	instance->m_prefs = NULL;
159 
160 	delete instance;
161 	instance = NULL;
162 
163 	for (ContactList::iterator it = s_bootstrapList.begin(); it != s_bootstrapList.end(); ++it) {
164 		delete *it;
165 	}
166 	s_bootstrapList.clear();
167 
168 	// Make sure all zones are removed.
169 	m_events.clear();
170 
171 //	theApp->ShowConnectionState();
172 }
173 
Process()174 void CKademlia::Process()
175 {
176 
177 	if (instance == NULL || !m_running) {
178 		return;
179 	}
180 
181 	time_t now = time(NULL);
182 	uint32_t maxUsers = 0;
183 	uint32_t tempUsers = 0;
184 	uint32_t lastContact = 0;
185 	bool updateUserFile = false;
186 
187 	wxASSERT(instance->m_prefs != NULL);
188 	lastContact = instance->m_prefs->GetLastContact();
189 	CSearchManager::UpdateStats();
190 
191 	if (m_statusUpdate <= now) {
192 		updateUserFile = true;
193 		m_statusUpdate = MIN2S(1) + now;
194 	}
195 
196 	if (m_nextFirewallCheck <= now) {
197 		RecheckFirewalled();
198 	}
199 
200 	if (m_nextSelfLookup <= now) {
201 		CSearchManager::FindNode(instance->m_prefs->GetKadID(), true);
202 		m_nextSelfLookup = HR2S(4) + now;
203 	}
204 
205 	if (m_nextFindBuddy <= now) {
206 		instance->m_prefs->SetFindBuddy();
207 		m_nextFindBuddy = MIN2S(20) + now;
208 	}
209 
210 	if (m_externPortLookup <= now && CUDPFirewallTester::IsFWCheckUDPRunning() && GetPrefs()->FindExternKadPort(false)) {
211 		// If our UDP firewallcheck is running and we don't know our external port, we send a request every 15 seconds
212 		CContact *contact = GetRoutingZone()->GetRandomContact(3, 6);
213 		if (contact != NULL) {
214 			AddDebugLogLineN(logKadPrefs, wxT("Requesting our external port from ") + KadIPToString(contact->GetIPAddress()));
215 			DebugSend(Kad2Ping, contact->GetIPAddress(), contact->GetUDPPort());
216 			GetUDPListener()->SendNullPacket(KADEMLIA2_PING, contact->GetIPAddress(), contact->GetUDPPort(), contact->GetUDPKey(), &contact->GetClientID());
217 		} else {
218 			AddDebugLogLineN(logKadPrefs, wxT("No valid client for requesting external port available"));
219 		}
220 		m_externPortLookup = 15 + now;
221 	}
222 
223 	for (EventMap::const_iterator it = m_events.begin(); it != m_events.end(); ++it) {
224 		CRoutingZone *zone = it->first;
225 		if (updateUserFile) {
226 			// The EstimateCount function is not made for really small networks, if we are in LAN mode, it is actually
227 			// better to assume that all users of the network are in our routing table and use the real count function
228 			if (IsRunningInLANMode()) {
229 				tempUsers = zone->GetNumContacts();
230 			} else {
231 				tempUsers = zone->EstimateCount();
232 			}
233 			if (maxUsers < tempUsers) {
234 				maxUsers = tempUsers;
235 			}
236 		}
237 
238 		if (m_bigTimer <= now) {
239 			if (zone->m_nextBigTimer <= now) {
240 				if(zone->OnBigTimer()) {
241 					zone->m_nextBigTimer = HR2S(1) + now;
242 					m_bigTimer = SEC(10) + now;
243 				}
244 			} else {
245 				if (lastContact && (now - lastContact > KADEMLIADISCONNECTDELAY - MIN2S(5))) {
246 					if(zone->OnBigTimer()) {
247 						zone->m_nextBigTimer = HR2S(1) + now;
248 						m_bigTimer = SEC(10) + now;
249 					}
250 				}
251 			}
252 		}
253 
254 		if (zone->m_nextSmallTimer <= now) {
255 			zone->OnSmallTimer();
256 			zone->m_nextSmallTimer = MIN2S(1) + now;
257 		}
258 	}
259 
260 	// This is a convenient place to add this, although not related to routing
261 	if (m_nextSearchJumpStart <= now) {
262 		CSearchManager::JumpStart();
263 		m_nextSearchJumpStart = SEARCH_JUMPSTART + now;
264 	}
265 
266 	// Try to consolidate any zones that are close to empty.
267 	if (m_consolidate <= now) {
268 		uint32_t mergedCount = instance->m_routingZone->Consolidate();
269 		if (mergedCount) {
270 			AddDebugLogLineN(logKadRouting, CFormat(wxT("Kad merged %u zones")) % mergedCount);
271 		}
272 		m_consolidate = MIN2S(45) + now;
273 	}
274 
275 	// Update user count only if changed.
276 	if (updateUserFile) {
277 		if (maxUsers != instance->m_prefs->GetKademliaUsers()) {
278 			instance->m_prefs->SetKademliaUsers(maxUsers);
279 			instance->m_prefs->SetKademliaFiles();
280 			theApp->ShowUserCount();
281 		}
282 	}
283 
284 	if (!IsConnected() && !s_bootstrapList.empty() && (now - m_bootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && now - m_bootstrap >= 2))) {
285 		CContact *contact = s_bootstrapList.front();
286 		s_bootstrapList.pop_front();
287 		m_bootstrap = now;
288 		AddDebugLogLineN(logKadMain, CFormat(wxT("Trying to bootstrap Kad from %s, Distance: %s Version: %u, %u contacts left"))
289 			% KadIPToString(contact->GetIPAddress()) % contact->GetDistance().ToHexString() % contact->GetVersion() % s_bootstrapList.size());
290 		instance->m_udpListener->Bootstrap(contact->GetIPAddress(), contact->GetUDPPort(), contact->GetVersion(), &contact->GetClientID());
291 		delete contact;
292 	}
293 
294 	if (GetUDPListener() != NULL) {
295 		GetUDPListener()->ExpireClientSearch();	// function does only one compare in most cases, so no real need for a timer
296 	}
297 }
298 
ProcessPacket(const uint8_t * data,uint32_t lenData,uint32_t ip,uint16_t port,bool validReceiverKey,const CKadUDPKey & senderKey)299 void CKademlia::ProcessPacket(const uint8_t *data, uint32_t lenData, uint32_t ip, uint16_t port, bool validReceiverKey, const CKadUDPKey& senderKey)
300 {
301 	try {
302 		if( instance && instance->m_udpListener ) {
303 			instance->m_udpListener->ProcessPacket(data, lenData, ip, port, validReceiverKey, senderKey);
304 		}
305 	} catch (const wxString& DEBUG_ONLY(error)) {
306 		AddDebugLogLineN(logKadMain, CFormat(wxT("Exception on Kad ProcessPacket while processing packet (length = %u) from %s:"))
307 			% lenData % KadIPPortToString(ip, port));
308 		AddDebugLogLineN(logKadMain, error);
309 		throw;
310 	} catch (...) {
311 		AddDebugLogLineN(logKadMain, wxT("Unhandled exception on Kad ProcessPacket"));
312 		throw;
313 	}
314 }
315 
RecheckFirewalled()316 void CKademlia::RecheckFirewalled()
317 {
318 	if (instance && instance->m_prefs && !IsRunningInLANMode()) {
319 		// Something is forcing a new firewall check
320 		// Stop any new buddy requests, and tell the client
321 		// to recheck it's IP which in turns rechecks firewall.
322 		instance->m_prefs->SetFindBuddy(false);
323 		instance->m_prefs->SetRecheckIP();
324 		// also UDP check
325 		CUDPFirewallTester::ReCheckFirewallUDP(false);
326 		time_t now = time(NULL);
327 		// Delay the next buddy search to at least 5 minutes after our firewallcheck so we are sure to be still firewalled
328 		m_nextFindBuddy = (m_nextFindBuddy < MIN2S(5) + now) ? MIN2S(5) + now : m_nextFindBuddy;
329 		m_nextFirewallCheck = HR2S(1) + now;
330 	}
331 }
332 
333 #if 0	// currently unused function
334 bool CKademlia::FindNodeIDByIP(CKadClientSearcher& requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort)
335 {
336 	wxCHECK(IsRunning() && instance && GetUDPListener() && GetRoutingZone(), false);
337 
338 	// first search our known contacts if we can deliver a result without asking, otherwise forward the request
339 	CContact* contact;
340 	if ((contact = GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(ip), tcpPort, true)) != NULL) {
341 		uint8_t nodeID[16];
342 		contact->GetClientID().ToByteArray(nodeID);
343 		requester.KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, nodeID);
344 		return true;
345 	} else {
346 		return GetUDPListener()->FindNodeIDByIP(&requester, wxUINT32_SWAP_ALWAYS(ip), tcpPort, udpPort);
347 	}
348 }
349 #endif
350 
FindIPByNodeID(CKadClientSearcher & requester,const uint8_t * nodeID)351 bool CKademlia::FindIPByNodeID(CKadClientSearcher& requester, const uint8_t* nodeID)
352 {
353 	wxCHECK(IsRunning() && instance && GetUDPListener(), false);
354 
355 	// first search our known contacts if we can deliver a result without asking, otherwise forward the request
356 	CContact* contact;
357 	if ((contact = GetRoutingZone()->GetContact(CUInt128(nodeID))) != NULL) {
358 		// make sure that this entry is not too old, otherwise just do a search to be sure
359 		if (contact->GetLastSeen() != 0 && time(NULL) - contact->GetLastSeen() < 1800) {
360 			requester.KadSearchIPByNodeIDResult(KCSR_SUCCEEDED, wxUINT32_SWAP_ALWAYS(contact->GetIPAddress()), contact->GetTCPPort());
361 			return true;
362 		}
363 	}
364 	return CSearchManager::FindNodeSpecial(CUInt128(nodeID), &requester);
365 }
366 
CancelClientSearch(CKadClientSearcher & fromRequester)367 void CKademlia::CancelClientSearch(CKadClientSearcher& fromRequester)
368 {
369 	wxCHECK_RET(instance && GetUDPListener(), wxT("Something is really bad"));
370 
371 	GetUDPListener()->ExpireClientSearch(&fromRequester);
372 	CSearchManager::CancelNodeSpecial(&fromRequester);
373 }
374 
StatsAddClosestDistance(const CUInt128 & distance)375 void CKademlia::StatsAddClosestDistance(const CUInt128& distance)
376 {
377 	if (distance.Get32BitChunk(0) > 0) {
378 		uint32_t toAdd = (0xFFFFFFFF / distance.Get32BitChunk(0)) / 2;
379 		std::list<uint32_t>::iterator it = m_statsEstUsersProbes.begin();
380 		for (; it != m_statsEstUsersProbes.end(); ++it) {
381 			if (*it == toAdd) {
382 				break;
383 			}
384 		}
385 		if (it == m_statsEstUsersProbes.end()) {
386 			m_statsEstUsersProbes.push_front(toAdd);
387 		}
388 	}
389 	if (m_statsEstUsersProbes.size() > 100) {
390 		m_statsEstUsersProbes.pop_back();
391 	}
392 }
393 
CalculateKadUsersNew()394 uint32_t CKademlia::CalculateKadUsersNew()
395 {
396 	// the idea of calculating the user count with this method is simple:
397 	// whenever we do a search for any NodeID (except in certain cases where the result is not usable),
398 	// we remember the distance of the closest node we found. Because we assume all NodeIDs are distributed
399 	// equally, we can calculate based on this distance how "filled" the possible NodesID room is and by this
400 	// calculate how many users there are. Of course this only works if we have enough samples, because
401 	// each single sample will be wrong, but the average of them should produce a usable number. To avoid
402 	// drifts caused by a a single (or more) really close or really far away hits, we do use median-average instead through
403 
404 	// doesn't work well if we have no files to index and nothing to download and the numbers seems to be a bit too low
405 	// compared to our other method. So let's stay with the old one for now, but keep this here as an alternative
406 
407 	if (m_statsEstUsersProbes.size() < 10) {
408 		return 0;
409 	}
410 	uint32_t median = 0;
411 
412 	std::list<uint32_t> medianList;
413 	for (std::list<uint32_t>::iterator it1 = m_statsEstUsersProbes.begin(); it1 != m_statsEstUsersProbes.end(); ++it1) {
414 		uint32_t probe = *it1;
415 		bool inserted = false;
416 		for (std::list<uint32_t>::iterator it2 = medianList.begin(); it2 != medianList.end(); ++it2) {
417 			if (*it2 > probe) {
418 				medianList.insert(it2, probe);
419 				inserted = true;
420 				break;
421 			}
422 		}
423 		if (!inserted) {
424 			medianList.push_back(probe);
425 		}
426 	}
427 	// cut away 1/3 of the values - 1/6 of the top and 1/6 of the bottom  to avoid spikes having too much influence, build the average of the rest
428 	std::list<uint32_t>::size_type cut = medianList.size() / 6;
429 	for (std::list<uint32_t>::size_type i = 0; i != cut; ++i) {
430 		medianList.pop_front();
431 		medianList.pop_back();
432 	}
433 	uint64_t average = 0;
434 	for (std::list<uint32_t>::iterator it = medianList.begin(); it != medianList.end(); ++it) {
435 		average += *it;
436 	}
437 	median = (uint32_t)(average / medianList.size());
438 
439 	// LowIDModififier
440 	// Modify count by assuming 20% of the users are firewalled and can't be a contact for < 0.49b nodes
441 	// Modify count by actual statistics of Firewalled ratio for >= 0.49b if we are not firewalled ourself
442 	// Modify count by 40% for >= 0.49b if we are firewalled ourself (the actual Firewalled count at this date on kad is 35-55%)
443 	const float firewalledModifyOld = 1.20f;
444 	float firewalledModifyNew = 0.0;
445 	if (CUDPFirewallTester::IsFirewalledUDP(true)) {
446 		firewalledModifyNew = 1.40f; // we are firewalled and can't get the real statistics, assume 40% firewalled >=0.49b nodes
447 	} else if (GetPrefs()->StatsGetFirewalledRatio(true) > 0) {
448 		firewalledModifyNew = 1.0 + (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true)); // apply the firewalled ratio to the modify
449 		wxASSERT(firewalledModifyNew > 1.0 && firewalledModifyNew < 1.90);
450 	}
451 	float newRatio = CKademlia::GetPrefs()->StatsGetKadV8Ratio();
452 	float firewalledModifyTotal = 0.0;
453 	if (newRatio > 0 && firewalledModifyNew > 0) { // weigth the old and the new modifier based on how many new contacts we have
454 		firewalledModifyTotal = (newRatio * firewalledModifyNew) + ((1 - newRatio) * firewalledModifyOld);
455 	} else {
456 		firewalledModifyTotal = firewalledModifyOld;
457 	}
458 	wxASSERT(firewalledModifyTotal > 1.0 && firewalledModifyTotal < 1.90);
459 
460 	return (uint32_t)((float)median * firewalledModifyTotal);
461 }
462 
IsRunningInLANMode()463 bool CKademlia::IsRunningInLANMode()
464 {
465 	if (thePrefs::FilterLanIPs() || !IsRunning()) {
466 		return false;
467 	}
468 
469 	time_t now = time(NULL);
470 	if (m_lanModeCheck + 10 <= now) {
471 		m_lanModeCheck = now;
472 		uint32_t count = GetRoutingZone()->GetNumContacts();
473 		// Limit to 256 nodes, if we have more we don't want to use the LAN mode which is assuming we use a small home LAN
474 		// (otherwise we might need to do firewallcheck, external port requests etc after all)
475 		if (count == 0 || count > 256) {
476 			m_lanMode = false;
477 		} else {
478 			if (GetRoutingZone()->HasOnlyLANNodes()) {
479 				if (!m_lanMode) {
480 					m_lanMode = true;
481 					theApp->ShowConnectionState();
482 					AddDebugLogLineN(logKadMain, wxT("Activating LAN mode"));
483 				}
484 			} else {
485 				if (m_lanMode) {
486 					m_lanMode = false;
487 					theApp->ShowConnectionState();
488 					AddDebugLogLineN(logKadMain, wxT("Deactivating LAN mode"));
489 				}
490 			}
491 		}
492 	}
493 	return m_lanMode;
494 }
495 
496 
497 // Global function.
498 
499 #include "../../CryptoPP_Inc.h"
KadGetKeywordHash(const wxString & rstrKeyword,Kademlia::CUInt128 * pKadID)500 void KadGetKeywordHash(const wxString& rstrKeyword, Kademlia::CUInt128* pKadID)
501 {
502 	uint8_t Output[16];
503 
504 	CryptoPP::Weak::MD4 md4_hasher;
505 
506 	// This should be safe - we assume rstrKeyword is ANSI anyway.
507 	char* ansi_buffer = strdup(unicode2UTF8(rstrKeyword));
508 
509 	//printf("Kad keyword hash: UTF8 %s\n",ansi_buffer);
510 	md4_hasher.CalculateDigest(Output,(const unsigned char*)ansi_buffer,strlen(ansi_buffer));
511 	//DumpMem(Output,16);
512 	free(ansi_buffer);
513 
514 	pKadID->SetValueBE(Output);
515 }
516