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