1 /*
2 * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "stdinc.h"
20
21 #include "AdcHub.h"
22
23 #include <boost/scoped_array.hpp>
24
25 #include "ChatMessage.h"
26 #include "ClientManager.h"
27 #include "ShareManager.h"
28 #include "StringTokenizer.h"
29 #include "AdcCommand.h"
30 #include "ConnectionManager.h"
31 #include "version.h"
32 #include "Util.h"
33 #include "UserCommand.h"
34 #include "CryptoManager.h"
35 #include "LogManager.h"
36 #include "ThrottleManager.h"
37 #include "UploadManager.h"
38 #include "format.h"
39
40 #include <cmath>
41
42 namespace dcpp {
43
44 using std::make_pair;
45
46 const string AdcHub::CLIENT_PROTOCOL("ADC/1.0");
47 const string AdcHub::SECURE_CLIENT_PROTOCOL_TEST("ADCS/0.10");
48 const string AdcHub::ADCS_FEATURE("ADC0");
49 const string AdcHub::TCP4_FEATURE("TCP4");
50 const string AdcHub::UDP4_FEATURE("UDP4");
51 const string AdcHub::NAT0_FEATURE("NAT0");
52 const string AdcHub::SEGA_FEATURE("SEGA");
53 const string AdcHub::BASE_SUPPORT("ADBASE");
54 const string AdcHub::BAS0_SUPPORT("ADBAS0");
55 const string AdcHub::TIGR_SUPPORT("ADTIGR");
56 const string AdcHub::UCM0_SUPPORT("ADUCM0");
57 const string AdcHub::BLO0_SUPPORT("ADBLO0");
58 const string AdcHub::ZLIF_SUPPORT("ADZLIF");
59 #ifdef WITH_DHT
60 const string AdcHub::DHT0_SUPPORT("ADDHT0");
61 #endif
62
63 const vector<StringList> AdcHub::searchExts;
64
AdcHub(const string & aHubURL,bool secure)65 AdcHub::AdcHub(const string& aHubURL, bool secure) : Client(aHubURL, '\n', secure), oldPassword(false), sid(0) {
66 TimerManager::getInstance()->addListener(this);
67 }
68
~AdcHub()69 AdcHub::~AdcHub() {
70 TimerManager::getInstance()->removeListener(this);
71 clearUsers();
72 }
73
getUser(const uint32_t aSID,const CID & aCID)74 OnlineUser& AdcHub::getUser(const uint32_t aSID, const CID& aCID) {
75 OnlineUser* ou = findUser(aSID);
76 if(ou) {
77 return *ou;
78 }
79
80 UserPtr p = ClientManager::getInstance()->getUser(aCID);
81
82 {
83 Lock l(cs);
84 ou = users.insert(make_pair(aSID, new OnlineUser(p, *this, aSID))).first->second;
85 }
86
87 if(aSID != AdcCommand::HUB_SID)
88 ClientManager::getInstance()->putOnline(ou);
89 return *ou;
90 }
91
findUser(const uint32_t aSID) const92 OnlineUser* AdcHub::findUser(const uint32_t aSID) const {
93 Lock l(cs);
94 auto i = users.find(aSID);
95 return i == users.end() ? NULL : i->second;
96 }
97
findUser(const CID & aCID) const98 OnlineUser* AdcHub::findUser(const CID& aCID) const {
99 Lock l(cs);
100 for(auto i = users.begin(); i != users.end(); ++i) {
101 if(i->second->getUser()->getCID() == aCID) {
102 return i->second;
103 }
104 }
105 return 0;
106 }
107
putUser(const uint32_t aSID,bool disconnect)108 void AdcHub::putUser(const uint32_t aSID, bool disconnect) {
109 OnlineUser* ou = 0;
110 {
111 Lock l(cs);
112 auto i = users.find(aSID);
113 if(i == users.end())
114 return;
115 ou = i->second;
116 users.erase(i);
117 }
118
119 if(aSID != AdcCommand::HUB_SID)
120 ClientManager::getInstance()->putOffline(ou, disconnect);
121
122 fire(ClientListener::UserRemoved(), this, *ou);
123 delete ou;
124 }
125
clearUsers()126 void AdcHub::clearUsers() {
127 SIDMap tmp;
128 {
129 Lock l(cs);
130 users.swap(tmp);
131 }
132
133 for(auto i = tmp.begin(); i != tmp.end(); ++i) {
134 if(i->first != AdcCommand::HUB_SID)
135 ClientManager::getInstance()->putOffline(i->second);
136 delete i->second;
137 }
138 }
139
handle(AdcCommand::INF,AdcCommand & c)140 void AdcHub::handle(AdcCommand::INF, AdcCommand& c) noexcept {
141 if(c.getParameters().empty())
142 return;
143
144 string cid;
145
146 OnlineUser* u = 0;
147 if(c.getParam("ID", 0, cid)) {
148 u = findUser(CID(cid));
149 if(u) {
150 if(u->getIdentity().getSID() != c.getFrom()) {
151 // Same CID but different SID not allowed - buggy hub?
152 string nick;
153 if(!c.getParam("NI", 0, nick)) {
154 nick = "[nick unknown]";
155 }
156 fire(ClientListener::StatusMessage(), this, str(F_("%1% (%2%) has same CID {%3%} as %4% (%5%), ignoring")
157 % u->getIdentity().getNick() % u->getIdentity().getSIDString() % cid % nick % AdcCommand::fromSID(c.getFrom())),
158 ClientListener::FLAG_IS_SPAM);
159 return;
160 }
161 } else {
162 u = &getUser(c.getFrom(), CID(cid));
163 }
164 } else if(c.getFrom() == AdcCommand::HUB_SID) {
165 u = &getUser(c.getFrom(), CID());
166 } else {
167 u = findUser(c.getFrom());
168 }
169
170 if(!u) {
171 dcdebug("AdcHub::INF Unknown user / no ID\n");
172 return;
173 }
174
175 for(auto i = c.getParameters().begin(); i != c.getParameters().end(); ++i) {
176 if(i->length() < 2)
177 continue;
178
179 u->getIdentity().set(i->c_str(), i->substr(2));
180 }
181
182 if(u->getIdentity().isBot()) {
183 u->getUser()->setFlag(User::BOT);
184 } else {
185 u->getUser()->unsetFlag(User::BOT);
186 }
187
188 if(u->getIdentity().supports(ADCS_FEATURE)) {
189 u->getUser()->setFlag(User::TLS);
190 }
191
192 if(!u->getIdentity().get("US").empty()) {
193 u->getIdentity().setConnection(str(F_("%1%/s") % Util::formatBytes(u->getIdentity().get("US"))));
194 }
195
196 if(u->getUser() == getMyIdentity().getUser()) {
197 state = STATE_NORMAL;
198 setAutoReconnect(true);
199 setMyIdentity(u->getIdentity());
200 updateCounts(false);
201 }
202
203 if(u->getIdentity().isHub()) {
204 setHubIdentity(u->getIdentity());
205 fire(ClientListener::HubUpdated(), this);
206 } else {
207 fire(ClientListener::UserUpdated(), this, *u);
208 }
209 }
210
handle(AdcCommand::SUP,AdcCommand & c)211 void AdcHub::handle(AdcCommand::SUP, AdcCommand& c) noexcept {
212 if(state != STATE_PROTOCOL) /** @todo SUP changes */
213 return;
214 bool baseOk = false;
215 bool tigrOk = false;
216 for(auto i = c.getParameters().begin(); i != c.getParameters().end(); ++i) {
217 if(*i == BAS0_SUPPORT) {
218 baseOk = true;
219 tigrOk = true;
220 } else if(*i == BASE_SUPPORT) {
221 baseOk = true;
222 } else if(*i == TIGR_SUPPORT) {
223 tigrOk = true;
224 }
225 }
226
227 if(!baseOk) {
228 fire(ClientListener::StatusMessage(), this, _("Failed to negotiate base protocol"));
229 disconnect(false);
230 return;
231 } else if(!tigrOk) {
232 oldPassword = true;
233 // Some hubs fake BASE support without TIGR support =/
234 fire(ClientListener::StatusMessage(), this, _("Hub probably uses an old version of ADC, please encourage the owner to upgrade"));
235 }
236 }
237
handle(AdcCommand::SID,AdcCommand & c)238 void AdcHub::handle(AdcCommand::SID, AdcCommand& c) noexcept {
239 if(state != STATE_PROTOCOL) {
240 dcdebug("Invalid state for SID\n");
241 return;
242 }
243
244 if(c.getParameters().empty())
245 return;
246
247 sid = AdcCommand::toSID(c.getParam(0));
248
249 state = STATE_IDENTIFY;
250 info(true);
251 }
252
handle(AdcCommand::MSG,AdcCommand & c)253 void AdcHub::handle(AdcCommand::MSG, AdcCommand& c) noexcept {
254 if(c.getParameters().empty())
255 return;
256
257 ChatMessage message = { c.getParam(0), findUser(c.getFrom()) };
258
259 if(!message.from)
260 return;
261
262 string temp;
263 if(c.getParam("PM", 1, temp)) { // add PM<group-cid> as well
264 message.to = findUser(c.getTo());
265 if(!message.to)
266 return;
267
268 message.replyTo = findUser(AdcCommand::toSID(temp));
269 if(!message.replyTo)
270 return;
271 }
272
273 message.thirdPerson = c.hasFlag("ME", 1);
274
275 if(c.getParam("TS", 1, temp))
276 message.timestamp = Util::toInt64(temp);
277
278 fire(ClientListener::Message(), this, message);
279 }
280
handle(AdcCommand::GPA,AdcCommand & c)281 void AdcHub::handle(AdcCommand::GPA, AdcCommand& c) noexcept {
282 if(c.getParameters().empty())
283 return;
284 salt = c.getParam(0);
285 state = STATE_VERIFY;
286
287 fire(ClientListener::GetPassword(), this);
288 }
289
handle(AdcCommand::QUI,AdcCommand & c)290 void AdcHub::handle(AdcCommand::QUI, AdcCommand& c) noexcept {
291 uint32_t s = AdcCommand::toSID(c.getParam(0));
292
293 OnlineUser* victim = findUser(s);
294 if(victim) {
295
296 string tmp;
297 if(c.getParam("MS", 1, tmp)) {
298 OnlineUser* source = 0;
299 string tmp2;
300 if(c.getParam("ID", 1, tmp2)) {
301 source = findUser(AdcCommand::toSID(tmp2));
302 }
303
304 if(source) {
305 tmp = str(F_("%1% was kicked by %2%: %3%") % victim->getIdentity().getNick() %
306 source->getIdentity().getNick() % tmp);
307 } else {
308 tmp = str(F_("%1% was kicked: %2%") % victim->getIdentity().getNick() % tmp);
309 }
310 fire(ClientListener::StatusMessage(), this, tmp, ClientListener::FLAG_IS_SPAM);
311 }
312
313 putUser(s, c.getParam("DI", 1, tmp));
314 }
315
316 if(s == sid) {
317 // this QUI is directed to us
318
319 string tmp;
320 if(c.getParam("TL", 1, tmp)) {
321 if(tmp == "-1") {
322 setAutoReconnect(false);
323 } else {
324 setAutoReconnect(true);
325 setReconnDelay(Util::toUInt32(tmp));
326 }
327 }
328 if(!victim && c.getParam("MS", 1, tmp)) {
329 fire(ClientListener::StatusMessage(), this, tmp, ClientListener::FLAG_NORMAL);
330 }
331 if(c.getParam("RD", 1, tmp)) {
332 fire(ClientListener::Redirect(), this, tmp);
333 }
334 }
335 }
336
handle(AdcCommand::CTM,AdcCommand & c)337 void AdcHub::handle(AdcCommand::CTM, AdcCommand& c) noexcept {
338 OnlineUser* u = findUser(c.getFrom());
339 if(!u || u->getUser() == ClientManager::getInstance()->getMe())
340 return;
341 if(c.getParameters().size() < 3)
342 return;
343
344 const string& protocol = c.getParam(0);
345 const string& port = c.getParam(1);
346 const string& token = c.getParam(2);
347
348 bool secure = false;
349 if(protocol == CLIENT_PROTOCOL) {
350 // Nothing special
351 } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) {
352 secure = true;
353 } else {
354 unknownProtocol(c.getFrom(), protocol, token);
355 return;
356 }
357
358 if(!u->getIdentity().isTcpActive()) {
359 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "IP unknown", AdcCommand::TYPE_DIRECT).setTo(c.getFrom()));
360 return;
361 }
362
363 ConnectionManager::getInstance()->adcConnect(*u, static_cast<uint16_t>(Util::toInt(port)), token, secure);
364 }
365
handle(AdcCommand::RCM,AdcCommand & c)366 void AdcHub::handle(AdcCommand::RCM, AdcCommand& c) noexcept {
367 if(c.getParameters().size() < 2) {
368 return;
369 }
370
371 OnlineUser* u = findUser(c.getFrom());
372 if(!u || u->getUser() == ClientManager::getInstance()->getMe())
373 return;
374
375 const string& protocol = c.getParam(0);
376 const string& token = c.getParam(1);
377
378 bool secure;
379 if(protocol == CLIENT_PROTOCOL) {
380 secure = false;
381 } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) {
382 secure = true;
383 } else {
384 unknownProtocol(c.getFrom(), protocol, token);
385 return;
386 }
387
388 if(isActive()) {
389 connect(*u, token, secure);
390 return;
391 }
392
393 if (!u->getIdentity().supports(NAT0_FEATURE) && !BOOLSETTING(ALLOW_NATT))
394 return;
395
396 // Attempt to traverse NATs and/or firewalls with TCP.
397 // If they respond with their own, symmetric, RNT command, both
398 // clients call ConnectionManager::adcConnect.
399 send(AdcCommand(AdcCommand::CMD_NAT, u->getIdentity().getSID(), AdcCommand::TYPE_DIRECT).
400 addParam(protocol).addParam(Util::toString(sock->getLocalPort())).addParam(token));
401 return;
402 }
403
handle(AdcCommand::CMD,AdcCommand & c)404 void AdcHub::handle(AdcCommand::CMD, AdcCommand& c) noexcept {
405 if(c.getParameters().empty())
406 return;
407 const string& name = c.getParam(0);
408 bool rem = c.hasFlag("RM", 1);
409 if(rem) {
410 fire(ClientListener::HubUserCommand(), this, (int)UserCommand::TYPE_REMOVE, 0, name, Util::emptyString);
411 return;
412 }
413 bool sep = c.hasFlag("SP", 1);
414 string sctx;
415 if(!c.getParam("CT", 1, sctx))
416 return;
417 int ctx = Util::toInt(sctx);
418 if(ctx <= 0)
419 return;
420 if(sep) {
421 fire(ClientListener::HubUserCommand(), this, (int)UserCommand::TYPE_SEPARATOR, ctx, name, Util::emptyString);
422 return;
423 }
424 bool once = c.hasFlag("CO", 1);
425 string txt;
426 if(!c.getParam("TT", 1, txt))
427 return;
428 fire(ClientListener::HubUserCommand(), this, (int)(once ? UserCommand::TYPE_RAW_ONCE : UserCommand::TYPE_RAW), ctx, name, txt);
429 }
430
sendUDP(const AdcCommand & cmd)431 void AdcHub::sendUDP(const AdcCommand& cmd) noexcept {
432 string command;
433 string ip;
434 uint16_t port;
435 {
436 Lock l(cs);
437 auto i = users.find(cmd.getTo());
438 if(i == users.end()) {
439 dcdebug("AdcHub::sendUDP: invalid user\n");
440 return;
441 }
442 OnlineUser& ou = *i->second;
443 if(!ou.getIdentity().isUdpActive()) {
444 return;
445 }
446 ip = ou.getIdentity().getIp();
447 port = static_cast<uint16_t>(Util::toInt(ou.getIdentity().getUdpPort()));
448 command = cmd.toString(ou.getUser()->getCID());
449 }
450 try {
451 udp.writeTo(ip, port, command);
452 } catch(const SocketException& e) {
453 dcdebug("AdcHub::sendUDP: write failed: %s\n", e.getError().c_str());
454 udp.close();
455 }
456 }
457
handle(AdcCommand::STA,AdcCommand & c)458 void AdcHub::handle(AdcCommand::STA, AdcCommand& c) noexcept {
459 if(c.getParameters().size() < 2)
460 return;
461
462 OnlineUser* u = c.getFrom() == AdcCommand::HUB_SID ? &getUser(c.getFrom(), CID()) : findUser(c.getFrom());
463 if(!u)
464 return;
465
466 //int severity = Util::toInt(c.getParam(0).substr(0, 1));
467 if(c.getParam(0).size() != 3) {
468 return;
469 }
470
471 switch(Util::toInt(c.getParam(0).substr(1))) {
472
473 case AdcCommand::ERROR_BAD_PASSWORD:
474 {
475 setPassword(Util::emptyString);
476 break;
477 }
478
479 case AdcCommand::ERROR_COMMAND_ACCESS:
480 {
481 string tmp;
482 if(c.getParam("FC", 1, tmp) && tmp.size() == 4)
483 forbiddenCommands.insert(AdcCommand::toFourCC(tmp.c_str()));
484 break;
485 }
486
487 case AdcCommand::ERROR_PROTOCOL_UNSUPPORTED:
488 {
489 string tmp;
490 if(c.getParam("PR", 1, tmp)) {
491 if(tmp == CLIENT_PROTOCOL) {
492 u->getUser()->setFlag(User::NO_ADC_1_0_PROTOCOL);
493 } else if(tmp == SECURE_CLIENT_PROTOCOL_TEST) {
494 u->getUser()->setFlag(User::NO_ADCS_0_10_PROTOCOL);
495 u->getUser()->unsetFlag(User::TLS);
496 }
497 // Try again...
498 ConnectionManager::getInstance()->force(u->getUser());
499 }
500 return;
501 }
502 }
503 ChatMessage message = { c.getParam(1), u };
504 fire(ClientListener::Message(), this, message);
505 }
506
handle(AdcCommand::SCH,AdcCommand & c)507 void AdcHub::handle(AdcCommand::SCH, AdcCommand& c) noexcept {
508 OnlineUser* ou = findUser(c.getFrom());
509 if(!ou) {
510 dcdebug("Invalid user in AdcHub::onSCH\n");
511 return;
512 }
513
514 fire(ClientListener::AdcSearch(), this, c, ou->getUser()->getCID());
515 }
516
handle(AdcCommand::RES,AdcCommand & c)517 void AdcHub::handle(AdcCommand::RES, AdcCommand& c) noexcept {
518 OnlineUser* ou = findUser(c.getFrom());
519 if(!ou) {
520 dcdebug("Invalid user in AdcHub::onRES\n");
521 return;
522 }
523 SearchManager::getInstance()->onRES(c, ou->getUser());
524 }
525
handle(AdcCommand::PSR,AdcCommand & c)526 void AdcHub::handle(AdcCommand::PSR, AdcCommand& c) noexcept {
527 OnlineUser* ou = findUser(c.getFrom());
528 if(!ou) {
529 dcdebug("Invalid user in AdcHub::onPSR\n");
530 return;
531 }
532 SearchManager::getInstance()->onPSR(c, ou->getUser());
533 }
534
handle(AdcCommand::GET,AdcCommand & c)535 void AdcHub::handle(AdcCommand::GET, AdcCommand& c) noexcept {
536 if(c.getParameters().size() < 5) {
537 if(c.getParameters().size() > 0) {
538 if(c.getParam(0) == "blom") {
539 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC,
540 "Too few parameters for blom", AdcCommand::TYPE_HUB));
541 } else {
542 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC,
543 "Unknown transfer type", AdcCommand::TYPE_HUB));
544 }
545 } else {
546 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC,
547 "Too few parameters for GET", AdcCommand::TYPE_HUB));
548 }
549 return;
550 }
551 const string& type = c.getParam(0);
552 string sk, sh;
553 if(type == "blom" && c.getParam("BK", 4, sk) && c.getParam("BH", 4, sh)) {
554 ByteVector v;
555 size_t m = Util::toUInt32(c.getParam(3)) * 8;
556 size_t k = Util::toUInt32(sk);
557 size_t h = Util::toUInt32(sh);
558
559 if(k > 8 || k < 1) {
560 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC,
561 "Unsupported k", AdcCommand::TYPE_HUB));
562 return;
563 }
564 if(h > 64 || h < 1) {
565 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC,
566 "Unsupported h", AdcCommand::TYPE_HUB));
567 return;
568 }
569 size_t n = ShareManager::getInstance()->getSharedFiles();
570
571 // Ideal size for m is n * k / ln(2), but we allow some slack
572 if(m > (5 * Util::roundUp((int64_t)(n * k / log(2.)), (int64_t)64)) || m > static_cast<size_t>(1 << h)) {
573 send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC,
574 "Unsupported m", AdcCommand::TYPE_HUB));
575 return;
576 }
577 if (m > 0) {
578 ShareManager::getInstance()->getBloom(v, k, m, h);
579 }
580 AdcCommand cmd(AdcCommand::CMD_SND, AdcCommand::TYPE_HUB);
581 cmd.addParam(c.getParam(0));
582 cmd.addParam(c.getParam(1));
583 cmd.addParam(c.getParam(2));
584 cmd.addParam(c.getParam(3));
585 cmd.addParam(c.getParam(4));
586 send(cmd);
587 if (m > 0) {
588 send((char*)&v[0], v.size());
589 }
590 }
591 }
handle(AdcCommand::NAT,AdcCommand & c)592 void AdcHub::handle(AdcCommand::NAT, AdcCommand& c) noexcept {
593 if (!BOOLSETTING(ALLOW_NATT))
594 return;
595
596 OnlineUser* u = findUser(c.getFrom());
597 if(!u || u->getUser() == ClientManager::getInstance()->getMe() || c.getParameters().size() < 3)
598 return;
599
600 const string& protocol = c.getParam(0);
601 const string& port = c.getParam(1);
602 const string& token = c.getParam(2);
603
604 // bool secure = secureAvail(c.getFrom(), protocol, token);
605 bool secure = false;
606 if(protocol == CLIENT_PROTOCOL) {
607 // Nothing special
608 } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) {
609 secure = true;
610 } else {
611 unknownProtocol(c.getFrom(), protocol, token);
612 return;
613 }
614
615 // Trigger connection attempt sequence locally ...
616 dcdebug("triggering connecting attempt in NAT: remote port = %s, local IP = %s, local port = %d\n", port.c_str(), sock->getLocalIp().c_str(), sock->getLocalPort());
617 ConnectionManager::getInstance()->adcConnect(*u, static_cast<uint16_t>(Util::toInt(port)), sock->getLocalPort(), BufferedSocket::NAT_CLIENT, token, secure);
618
619 // ... and signal other client to do likewise.
620 send(AdcCommand(AdcCommand::CMD_RNT, u->getIdentity().getSID(), AdcCommand::TYPE_DIRECT).addParam(protocol).
621 addParam(Util::toString(sock->getLocalPort())).addParam(token));
622 }
623
handle(AdcCommand::RNT,AdcCommand & c)624 void AdcHub::handle(AdcCommand::RNT, AdcCommand& c) noexcept {
625 // Sent request for NAT traversal cooperation, which
626 // was acknowledged (with requisite local port information).
627 if(!BOOLSETTING(ALLOW_NATT))
628 return;
629
630 OnlineUser* u = findUser(c.getFrom());
631 if(!u || u->getUser() == ClientManager::getInstance()->getMe() || c.getParameters().size() < 3)
632 return;
633
634 const string& protocol = c.getParam(0);
635 const string& port = c.getParam(1);
636 const string& token = c.getParam(2);
637
638 bool secure = false;
639 if(protocol == CLIENT_PROTOCOL) {
640 // Nothing special
641 } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) {
642 secure = true;
643 } else {
644 unknownProtocol(c.getFrom(), protocol, token);
645 return;
646 }
647
648 // Trigger connection attempt sequence locally
649 dcdebug("triggering connecting attempt in RNT: remote port = %s, local IP = %s, local port = %d\n", port.c_str(), sock->getLocalIp().c_str(), sock->getLocalPort());
650 ConnectionManager::getInstance()->adcConnect(*u, static_cast<uint16_t>(Util::toInt(port)), sock->getLocalPort(), BufferedSocket::NAT_SERVER, token, secure);
651 }
handle(AdcCommand::ZON,AdcCommand & c)652 void AdcHub::handle(AdcCommand::ZON, AdcCommand& c) noexcept {
653 try {
654 sock->setMode(BufferedSocket::MODE_ZPIPE);
655 } catch (const Exception& e) {
656 dcdebug("AdcHub::handleZON failed with error: %s\n", e.getError().c_str());
657 }
658 }
handle(AdcCommand::ZOF,AdcCommand & c)659 void AdcHub::handle(AdcCommand::ZOF, AdcCommand& c) noexcept {
660 try {
661 sock->setMode(BufferedSocket::MODE_LINE);
662 } catch (const Exception& e) {
663 dcdebug("AdcHub::handleZOF failed with error: %s\n", e.getError().c_str());
664 }
665 }
666
connect(const OnlineUser & user,const string & token)667 void AdcHub::connect(const OnlineUser& user, const string& token) {
668 connect(user, token, CryptoManager::getInstance()->TLSOk() && user.getUser()->isSet(User::TLS));
669 }
670
connect(const OnlineUser & user,string const & token,bool secure)671 void AdcHub::connect(const OnlineUser& user, string const& token, bool secure) {
672 if(state != STATE_NORMAL)
673 return;
674
675 const string* proto;
676 if(secure) {
677 if(user.getUser()->isSet(User::NO_ADCS_0_10_PROTOCOL)) {
678 /// @todo log
679 return;
680 }
681 proto = &SECURE_CLIENT_PROTOCOL_TEST;
682 } else {
683 if(user.getUser()->isSet(User::NO_ADC_1_0_PROTOCOL)) {
684 /// @todo log
685 return;
686 }
687 proto = &CLIENT_PROTOCOL;
688 }
689
690 if(isActive()) {
691 uint16_t port = secure ? ConnectionManager::getInstance()->getSecurePort() : ConnectionManager::getInstance()->getPort();
692 if(port == 0) {
693 // Oops?
694 LogManager::getInstance()->message(str(F_("Not listening for connections - please restart %1%") % APPNAME));
695 return;
696 }
697 send(AdcCommand(AdcCommand::CMD_CTM, user.getIdentity().getSID(), AdcCommand::TYPE_DIRECT).addParam(*proto).addParam(Util::toString(port)).addParam(token));
698 } else {
699 send(AdcCommand(AdcCommand::CMD_RCM, user.getIdentity().getSID(), AdcCommand::TYPE_DIRECT).addParam(*proto).addParam(token));
700 }
701 }
702
hubMessage(const string & aMessage,bool thirdPerson)703 void AdcHub::hubMessage(const string& aMessage, bool thirdPerson) {
704 if(state != STATE_NORMAL)
705 return;
706 AdcCommand c(AdcCommand::CMD_MSG, AdcCommand::TYPE_BROADCAST);
707 c.addParam(aMessage);
708 if(thirdPerson)
709 c.addParam("ME", "1");
710 send(c);
711 }
712
privateMessage(const OnlineUser & user,const string & aMessage,bool thirdPerson)713 void AdcHub::privateMessage(const OnlineUser& user, const string& aMessage, bool thirdPerson) {
714 if(state != STATE_NORMAL)
715 return;
716 AdcCommand c(AdcCommand::CMD_MSG, user.getIdentity().getSID(), AdcCommand::TYPE_ECHO);
717 c.addParam(aMessage);
718 if(thirdPerson)
719 c.addParam("ME", "1");
720 c.addParam("PM", getMySID());
721 send(c);
722 }
723
sendUserCmd(const UserCommand & command,const StringMap & params)724 void AdcHub::sendUserCmd(const UserCommand& command, const StringMap& params) {
725 if(state != STATE_NORMAL)
726 return;
727 string cmd = Util::formatParams(command.getCommand(), params, false);
728 if(command.isChat()) {
729 if(command.getTo().empty()) {
730 hubMessage(cmd);
731 } else {
732 const string& to = command.getTo();
733 Lock l(cs);
734 for(auto i = users.begin(); i != users.end(); ++i) {
735 if(i->second->getIdentity().getNick() == to) {
736 privateMessage(*i->second, cmd);
737 return;
738 }
739 }
740 }
741 } else {
742 send(cmd);
743 }
744 }
745
getSearchExts()746 const vector<StringList>& AdcHub::getSearchExts() {
747 if(!searchExts.empty())
748 return searchExts;
749
750 // the list is always immutable except for this function where it is initially being filled.
751 auto& xSearchExts = const_cast<vector<StringList>&>(searchExts);
752
753 xSearchExts.resize(7);
754
755 /// @todo simplify this as searchExts[0] = { "mp3", "etc" } when VC++ supports initializer lists
756 // these extensions *must* be sorted alphabetically!
757
758 {
759 StringList& l = xSearchExts[0];
760 l.push_back("ape"); l.push_back("flac"); l.push_back("m4a"); l.push_back("mid");
761 l.push_back("mp3"); l.push_back("mpc"); l.push_back("ogg"); l.push_back("ra");
762 l.push_back("wav"); l.push_back("wma");
763 }
764
765 {
766 StringList& l = xSearchExts[1];
767 l.push_back("7z"); l.push_back("ace"); l.push_back("arj"); l.push_back("bz2");
768 l.push_back("gz"); l.push_back("lha"); l.push_back("lzh"); l.push_back("rar");
769 l.push_back("tar"); l.push_back("z"); l.push_back("zip");
770 }
771
772 {
773 StringList& l = xSearchExts[2];
774 l.push_back("doc"); l.push_back("docx"); l.push_back("htm"); l.push_back("html");
775 l.push_back("nfo"); l.push_back("odf"); l.push_back("odp"); l.push_back("ods");
776 l.push_back("odt"); l.push_back("pdf"); l.push_back("ppt"); l.push_back("pptx");
777 l.push_back("rtf"); l.push_back("txt"); l.push_back("xls"); l.push_back("xlsx");
778 l.push_back("xml"); l.push_back("xps");
779 }
780
781 {
782 StringList& l = xSearchExts[3];
783 l.push_back("app"); l.push_back("bat"); l.push_back("cmd"); l.push_back("com");
784 l.push_back("dll"); l.push_back("exe"); l.push_back("jar"); l.push_back("msi");
785 l.push_back("ps1"); l.push_back("vbs"); l.push_back("wsf");
786 }
787
788 {
789 StringList& l = xSearchExts[4];
790 l.push_back("bmp"); l.push_back("cdr"); l.push_back("eps"); l.push_back("gif");
791 l.push_back("ico"); l.push_back("img"); l.push_back("jpeg"); l.push_back("jpg");
792 l.push_back("png"); l.push_back("ps"); l.push_back("psd"); l.push_back("sfw");
793 l.push_back("tga"); l.push_back("tif"); l.push_back("webp");
794 }
795
796 {
797 StringList& l = xSearchExts[5];
798 l.push_back("3gp"); l.push_back("asf"); l.push_back("asx"); l.push_back("avi");
799 l.push_back("divx"); l.push_back("flv"); l.push_back("mkv"); l.push_back("mov");
800 l.push_back("mp4"); l.push_back("mpeg"); l.push_back("mpg"); l.push_back("ogm");
801 l.push_back("pxp"); l.push_back("qt"); l.push_back("rm"); l.push_back("rmvb");
802 l.push_back("swf"); l.push_back("vob"); l.push_back("webm"); l.push_back("wmv");
803 }
804
805 {
806 StringList& l = xSearchExts[6];
807 l.push_back("iso"); l.push_back("mdf"); l.push_back("mds"); l.push_back("nrg");
808 l.push_back("vcd"); l.push_back("bwt"); l.push_back("ccd"); l.push_back("cdi");
809 l.push_back("pdi"); l.push_back("cue"); l.push_back("isz"); l.push_back("img");
810 l.push_back("vc4");
811 }
812 return searchExts;
813 }
814
parseSearchExts(int flag)815 StringList AdcHub::parseSearchExts(int flag) {
816 StringList ret;
817 const auto& searchExts = getSearchExts();
818 for(auto i = searchExts.cbegin(), ibegin = i, iend = searchExts.cend(); i != iend; ++i) {
819 if(flag & (1 << (i - ibegin))) {
820 ret.insert(ret.begin(), i->begin(), i->end());
821 }
822 }
823 return ret;
824 }
825
search(int aSizeMode,int64_t aSize,int aFileType,const string & aString,const string & aToken,const StringList & aExtList)826 void AdcHub::search(int aSizeMode, int64_t aSize, int aFileType, const string& aString, const string& aToken, const StringList& aExtList) {
827 if(state != STATE_NORMAL)
828 return;
829
830 AdcCommand c(AdcCommand::CMD_SCH, AdcCommand::TYPE_BROADCAST);
831
832 if(!aToken.empty())
833 c.addParam("TO", aToken);
834
835 if(aFileType == SearchManager::TYPE_TTH) {
836 c.addParam("TR", aString);
837 } else {
838 if(aSizeMode == SearchManager::SIZE_ATLEAST) {
839 c.addParam("GE", Util::toString(aSize));
840 } else if(aSizeMode == SearchManager::SIZE_ATMOST) {
841 c.addParam("LE", Util::toString(aSize));
842 }
843 StringTokenizer<string> st(aString, ' ');
844 for(auto i = st.getTokens().begin(); i != st.getTokens().end(); ++i) {
845 c.addParam("AN", *i);
846 }
847 if(aFileType == SearchManager::TYPE_DIRECTORY) {
848 c.addParam("TY", "2");
849 }
850
851 if(aExtList.size() > 2) {
852 StringList exts = aExtList;
853
854 sort(exts.begin(), exts.end());
855
856 uint8_t gr = 0;
857 StringList rx;
858
859 const auto& searchExts = getSearchExts();
860 for(auto i = searchExts.cbegin(), ibegin = i, iend = searchExts.cend(); i != iend; ++i) {
861 const StringList& def = *i;
862
863 // gather the exts not present in any of the lists
864 StringList temp(def.size() + exts.size());
865 temp = StringList(temp.begin(), set_symmetric_difference(def.begin(), def.end(),
866 exts.begin(), exts.end(), temp.begin()));
867
868 // figure out whether the remaining exts have to be added or removed from the set
869 StringList rx_;
870 bool ok = true;
871 for(auto diff = temp.begin(); diff != temp.end();) {
872 if(find(def.cbegin(), def.cend(), *diff) == def.cend()) {
873 ++diff; // will be added further below as an "EX"
874 } else {
875 if(rx_.size() == 2) {
876 ok = false;
877 break;
878 }
879 rx_.push_back(*diff);
880 diff = temp.erase(diff);
881 }
882 }
883 if(!ok) // too many "RX"s necessary - disregard this group
884 continue;
885
886 // let's include this group!
887 gr += 1 << (i - ibegin);
888
889 exts = temp; // the exts to still add (that were not defined in the group)
890
891 rx.insert(rx.begin(), rx_.begin(), rx_.end());
892
893 if(exts.size() <= 2)
894 break;
895 // keep looping to see if there are more exts that can be grouped
896 }
897
898 if(gr) {
899 // some extensions can be grouped; let's send a command with grouped exts.
900 AdcCommand c_gr(AdcCommand::CMD_SCH, AdcCommand::TYPE_FEATURE);
901 c_gr.setFeatures('+' + SEGA_FEATURE);
902
903 const auto& params = c.getParameters();
904 for(auto i = params.cbegin(), iend = params.cend(); i != iend; ++i)
905 c_gr.addParam(*i);
906
907 for(auto i = exts.cbegin(), iend = exts.cend(); i != iend; ++i)
908 c_gr.addParam("EX", *i);
909 c_gr.addParam("GR", Util::toString(gr));
910 for(auto i = rx.cbegin(), iend = rx.cend(); i != iend; ++i)
911 c_gr.addParam("RX", *i);
912
913 sendSearch(c_gr);
914
915 // make sure users with the feature don't receive the search twice.
916 c.setType(AdcCommand::TYPE_FEATURE);
917 c.setFeatures('-' + SEGA_FEATURE);
918 }
919 }
920
921 for(auto i = aExtList.cbegin(), iend = aExtList.cend(); i != iend; ++i)
922 c.addParam("EX", *i);
923 }
924
925 sendSearch(c);
926 }
sendSearch(AdcCommand & c)927 void AdcHub::sendSearch(AdcCommand& c) {
928 if(isActive()) {
929 send(c);
930 } else {
931 string features = c.getFeatures();
932 c.setType(AdcCommand::TYPE_FEATURE);
933 if (BOOLSETTING(ALLOW_NATT)) {
934 c.setFeatures(features + '+' + TCP4_FEATURE + '-' + NAT0_FEATURE);
935 send(c);
936 c.setFeatures(features + '+' + NAT0_FEATURE);
937 } else {
938 c.setFeatures(features + '+' + TCP4_FEATURE);
939 }
940 send(c);
941 }
942 }
943
password(const string & pwd)944 void AdcHub::password(const string& pwd) {
945 if(state != STATE_VERIFY)
946 return;
947 if(!salt.empty()) {
948 size_t saltBytes = salt.size() * 5 / 8;
949 boost::scoped_array<uint8_t> buf(new uint8_t[saltBytes]);
950 Encoder::fromBase32(salt.c_str(), &buf[0], saltBytes);
951 TigerHash th;
952 if(oldPassword) {
953 CID cid = getMyIdentity().getUser()->getCID();
954 th.update(cid.data(), CID::SIZE);
955 }
956 th.update(pwd.data(), pwd.length());
957 th.update(&buf[0], saltBytes);
958 send(AdcCommand(AdcCommand::CMD_PAS, AdcCommand::TYPE_HUB).addParam(Encoder::toBase32(th.finalize(), TigerHash::BYTES)));
959 salt.clear();
960 }
961 }
962
addParam(StringMap & lastInfoMap,AdcCommand & c,const string & var,const string & value)963 static void addParam(StringMap& lastInfoMap, AdcCommand& c, const string& var, const string& value) {
964 auto i = lastInfoMap.find(var);
965
966 if(i != lastInfoMap.end()) {
967 if(i->second != value) {
968 if(value.empty()) {
969 lastInfoMap.erase(i);
970 } else {
971 i->second = value;
972 }
973 c.addParam(var, value);
974 }
975 } else if(!value.empty()) {
976 lastInfoMap.insert(make_pair(var, value));
977 c.addParam(var, value);
978 }
979 }
980
info(bool)981 void AdcHub::info(bool /*alwaysSend*/) {
982 if(state != STATE_IDENTIFY && state != STATE_NORMAL)
983 return;
984
985 reloadSettings(false);
986
987 AdcCommand c(AdcCommand::CMD_INF, AdcCommand::TYPE_BROADCAST);
988 if (state == STATE_NORMAL) {
989 updateCounts(false);
990 }
991 addParam(lastInfoMap, c, "ID", ClientManager::getInstance()->getMyCID().toBase32());
992 addParam(lastInfoMap, c, "PD", ClientManager::getInstance()->getMyPID().toBase32());
993 addParam(lastInfoMap, c, "NI", getCurrentNick());
994 addParam(lastInfoMap, c, "DE", getCurrentDescription());
995 addParam(lastInfoMap, c, "SL", Util::toString(SETTING(SLOTS)));
996 addParam(lastInfoMap, c, "FS", Util::toString(UploadManager::getInstance()->getFreeSlots()));
997 addParam(lastInfoMap, c, "SS", ShareManager::getInstance()->getShareSizeString());
998 addParam(lastInfoMap, c, "SF", Util::toString(ShareManager::getInstance()->getSharedFiles()));
999 addParam(lastInfoMap, c, "EM", SETTING(EMAIL));
1000 addParam(lastInfoMap, c, "HN", Util::toString(counts.normal));
1001 addParam(lastInfoMap, c, "HR", Util::toString(counts.registered));
1002 addParam(lastInfoMap, c, "HO", Util::toString(counts.op));
1003 addParam(lastInfoMap, c, "VE", getClientId().c_str());
1004 addParam(lastInfoMap, c, "AW", Util::getAway() ? "1" : Util::emptyString);
1005 int limit = ThrottleManager::getInstance()->getDownLimit();
1006 if (limit > 0 && BOOLSETTING(THROTTLE_ENABLE)) {
1007 addParam(lastInfoMap, c, "DS", Util::toString(limit * 1024));
1008 } else {
1009 addParam(lastInfoMap, c, "DS", Util::emptyString);
1010 }
1011 limit = ThrottleManager::getInstance()->getUpLimit();
1012 if (limit > 0 && BOOLSETTING(THROTTLE_ENABLE)) {
1013 addParam(lastInfoMap, c, "US", Util::toString(limit * 1024));
1014 } else {
1015 addParam(lastInfoMap, c, "US", Util::toString((long)(Util::toDouble(SETTING(UPLOAD_SPEED))*1024*1024/8)));
1016 }
1017
1018 string su(SEGA_FEATURE);
1019 if(CryptoManager::getInstance()->TLSOk()) {
1020 su += "," + ADCS_FEATURE;
1021 auto &kp = CryptoManager::getInstance()->getKeyprint();
1022 addParam(lastInfoMap, c, "KP", "SHA256/" + Encoder::toBase32(&kp[0], kp.size()));
1023 }
1024
1025 if (!getFavIp().empty()) {
1026 addParam(lastInfoMap, c, "I4", getFavIp());
1027 } else if(BOOLSETTING(NO_IP_OVERRIDE) && !SETTING(EXTERNAL_IP).empty()) {
1028 addParam(lastInfoMap, c, "I4", Socket::resolve(SETTING(EXTERNAL_IP)));
1029 } else {
1030 addParam(lastInfoMap, c, "I4", "0.0.0.0");
1031 }
1032
1033 if(isActive()) {
1034 addParam(lastInfoMap, c, "U4", Util::toString(SearchManager::getInstance()->getPort()));
1035 su += "," + TCP4_FEATURE;
1036 su += "," + UDP4_FEATURE;
1037 } else {
1038 if (BOOLSETTING(ALLOW_NATT))
1039 su += "," + NAT0_FEATURE;
1040 else
1041 addParam(lastInfoMap, c, "I4", "");
1042 addParam(lastInfoMap, c, "U4", "");
1043 }
1044
1045 addParam(lastInfoMap, c, "SU", su);
1046
1047 if(!c.getParameters().empty()) {
1048 send(c);
1049 }
1050 }
1051
getAvailable() const1052 int64_t AdcHub::getAvailable() const {
1053 Lock l(cs);
1054 int64_t x = 0;
1055 for(auto i = users.begin(); i != users.end(); ++i) {
1056 x+=i->second->getIdentity().getBytesShared();
1057 }
1058 return x;
1059 }
1060
checkNick(const string & aNick)1061 string AdcHub::checkNick(const string& aNick) {
1062 string tmp = aNick;
1063 for(size_t i = 0; i < aNick.size(); ++i) {
1064 if(static_cast<uint8_t>(tmp[i]) <= 32) {
1065 tmp[i] = '_';
1066 }
1067 }
1068 return tmp;
1069 }
1070
send(const AdcCommand & cmd)1071 void AdcHub::send(const AdcCommand& cmd) {
1072 if(forbiddenCommands.find(AdcCommand::toFourCC(cmd.getFourCC().c_str())) == forbiddenCommands.end()) {
1073 if(cmd.getType() == AdcCommand::TYPE_UDP)
1074 sendUDP(cmd);
1075 send(cmd.toString(sid));
1076 }
1077 }
1078
unknownProtocol(uint32_t target,const string & protocol,const string & token)1079 void AdcHub::unknownProtocol(uint32_t target, const string& protocol, const string& token) {
1080 AdcCommand cmd(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_UNSUPPORTED, "Protocol unknown", AdcCommand::TYPE_DIRECT);
1081 cmd.setTo(target);
1082 cmd.addParam("PR", protocol);
1083 cmd.addParam("TO", token);
1084
1085 send(cmd);
1086 }
1087
on(Connected c)1088 void AdcHub::on(Connected c) noexcept {
1089 Client::on(c);
1090
1091 if(state != STATE_PROTOCOL) {
1092 return;
1093 }
1094
1095 lastInfoMap.clear();
1096 sid = 0;
1097 forbiddenCommands.clear();
1098
1099 AdcCommand cmd(AdcCommand::CMD_SUP, AdcCommand::TYPE_HUB);
1100 cmd.addParam(BAS0_SUPPORT).addParam(BASE_SUPPORT).addParam(TIGR_SUPPORT);
1101
1102 if(BOOLSETTING(HUB_USER_COMMANDS)) {
1103 cmd.addParam(UCM0_SUPPORT);
1104 }
1105 if(BOOLSETTING(SEND_BLOOM)) {
1106 cmd.addParam(BLO0_SUPPORT);
1107 }
1108 cmd.addParam(ZLIF_SUPPORT);
1109 #ifdef WITH_DHT
1110 if (BOOLSETTING(USE_DHT))
1111 cmd.addParam(DHT0_SUPPORT);
1112 #endif
1113 send(cmd);
1114 }
1115
on(Line l,const string & aLine)1116 void AdcHub::on(Line l, const string& aLine) noexcept {
1117 Client::on(l, aLine);
1118
1119 if(!Text::validateUtf8(aLine)) {
1120 // @todo report to user?
1121 return;
1122 }
1123
1124 if(BOOLSETTING(ADC_DEBUG)) {
1125 fire(ClientListener::StatusMessage(), this, "<ADC>" + aLine + "</ADC>");
1126 }
1127 #ifdef LUA_SCRIPT
1128 if (onClientMessage(this, aLine))
1129 return;
1130 #endif
1131 dispatch(aLine);
1132 }
1133
on(Failed f,const string & aLine)1134 void AdcHub::on(Failed f, const string& aLine) noexcept {
1135 clearUsers();
1136 Client::on(f, aLine);
1137 }
1138
on(Second s,uint64_t aTick)1139 void AdcHub::on(Second s, uint64_t aTick) noexcept {
1140 Client::on(s, aTick);
1141 if(state == STATE_NORMAL && (aTick > (getLastActivity() + 120*1000)) ) {
1142 send("\n", 1);
1143 }
1144 }
1145 #ifdef LUA_SCRIPT
onClientMessage(AdcHub * aClient,const string & aLine)1146 bool AdcScriptInstance::onClientMessage(AdcHub* aClient, const string& aLine) {
1147 Lock l(cs);
1148 MakeCall("adch", "DataArrival", 1, aClient, aLine);
1149 return GetLuaBool();
1150
1151 }
1152 #endif
1153 } // namespace dcpp
1154