00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "configreader.h"
00016 #include "users.h"
00017 #include "channels.h"
00018 #include "modules.h"
00019 #include "commands/cmd_whois.h"
00020 #include "commands/cmd_stats.h"
00021 #include "socket.h"
00022 #include "wildcard.h"
00023 #include "xline.h"
00024 #include "transport.h"
00025 #include "socketengine.h"
00026
00027 #include "m_spanningtree/main.h"
00028 #include "m_spanningtree/utils.h"
00029 #include "m_spanningtree/treeserver.h"
00030 #include "m_spanningtree/link.h"
00031 #include "m_spanningtree/treesocket.h"
00032 #include "m_spanningtree/resolvers.h"
00033 #include "m_spanningtree/handshaketimer.h"
00034
00035
00036
00037 static std::map<std::string, std::string> warned;
00038
00039 void TreeSocket::WriteLine(std::string line)
00040 {
00041 Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str());
00042 line.append("\r\n");
00043 this->Write(line);
00044 }
00045
00046
00047
00048 bool TreeSocket::Error(std::deque<std::string> ¶ms)
00049 {
00050 if (params.size() < 1)
00051 return false;
00052 this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
00053
00054 return false;
00055 }
00056
00057 bool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> ¶ms)
00058 {
00059 if (params.empty())
00060 return true;
00061
00062 if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00063 {
00064
00065 Utils->DoOneToOne(prefix, "MODULES", params, params[0]);
00066 return true;
00067 }
00068
00069 char strbuf[MAXBUF];
00070 std::deque<std::string> par;
00071 par.push_back(prefix);
00072 par.push_back("");
00073
00074 userrec* source = this->Instance->FindNick(prefix);
00075 if (!source)
00076 return true;
00077
00078 for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++)
00079 {
00080 Version V = Instance->modules[i]->GetVersion();
00081 char modulename[MAXBUF];
00082 char flagstate[MAXBUF];
00083 *flagstate = 0;
00084 if (V.Flags & VF_STATIC)
00085 strlcat(flagstate,", static",MAXBUF);
00086 if (V.Flags & VF_VENDOR)
00087 strlcat(flagstate,", vendor",MAXBUF);
00088 if (V.Flags & VF_COMMON)
00089 strlcat(flagstate,", common",MAXBUF);
00090 if (V.Flags & VF_SERVICEPROVIDER)
00091 strlcat(flagstate,", service provider",MAXBUF);
00092 if (!flagstate[0])
00093 strcpy(flagstate," <no flags>");
00094 strlcpy(modulename,Instance->Config->module_names[i].c_str(),256);
00095 if (*source->oper)
00096 {
00097 snprintf(strbuf, MAXBUF, "::%s 702 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);
00098 }
00099 else
00100 {
00101 snprintf(strbuf, MAXBUF, "::%s 702 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename));
00102 }
00103 par[1] = strbuf;
00104 Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
00105 }
00106 snprintf(strbuf, MAXBUF, "::%s 703 %s :End of MODULES list", Instance->Config->ServerName, source->nick);
00107 par[1] = strbuf;
00108 Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
00109 return true;
00110 }
00111
00113 bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> ¶ms)
00114 {
00115 if (params.size() > 0)
00116 {
00117 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00118 {
00119
00120 string_list results;
00121 userrec* source = this->Instance->FindNick(prefix);
00122
00123 if (source)
00124 {
00125 std::deque<std::string> par;
00126 par.push_back(prefix);
00127 par.push_back("");
00128
00129 if (!Instance->Config->MOTD.size())
00130 {
00131 par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";
00132 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00133 return true;
00134 }
00135
00136 par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";
00137 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00138
00139 for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)
00140 {
00141 par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];
00142 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00143 }
00144
00145 par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" :End of message of the day.";
00146 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00147 }
00148 }
00149 else
00150 {
00151
00152 userrec* source = this->Instance->FindNick(prefix);
00153 if (source)
00154 Utils->DoOneToOne(prefix, "MOTD", params, params[0]);
00155 }
00156 }
00157 return true;
00158 }
00159
00161 bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> ¶ms)
00162 {
00163 if (params.size() > 0)
00164 {
00165 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
00166 {
00167
00168 string_list results;
00169 userrec* source = this->Instance->FindNick(prefix);
00170 if (source)
00171 {
00172 std::deque<std::string> par;
00173 par.push_back(prefix);
00174 par.push_back("");
00175 par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;
00176 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00177 par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name - "+Instance->Config->AdminName;
00178 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00179 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;
00180 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00181 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail - "+Instance->Config->AdminEmail;
00182 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00183 }
00184 }
00185 else
00186 {
00187
00188 userrec* source = this->Instance->FindNick(prefix);
00189 if (source)
00190 Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);
00191 }
00192 }
00193 return true;
00194 }
00195
00196 bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> ¶ms)
00197 {
00198
00199
00200
00201 if (params.size() > 1)
00202 {
00203 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))
00204 {
00205
00206 string_list results;
00207 userrec* source = this->Instance->FindNick(prefix);
00208 if (source)
00209 {
00210 std::deque<std::string> par;
00211 par.push_back(prefix);
00212 par.push_back("");
00213 DoStats(this->Instance, *(params[0].c_str()), source, results);
00214 for (size_t i = 0; i < results.size(); i++)
00215 {
00216 par[1] = "::" + results[i];
00217 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
00218 }
00219 }
00220 }
00221 else
00222 {
00223
00224 userrec* source = this->Instance->FindNick(prefix);
00225 if (source)
00226 Utils->DoOneToOne(prefix, "STATS", params, params[1]);
00227 }
00228 }
00229 return true;
00230 }
00231
00232
00236 bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> ¶ms)
00237 {
00238 if (params.size() != 1)
00239 return true;
00240 std::string opertype = params[0];
00241 userrec* u = this->Instance->FindNick(prefix);
00242 if (u)
00243 {
00244 if (!IS_OPER(u))
00245 this->Instance->all_opers.push_back(u);
00246 u->modes[UM_OPERATOR] = 1;
00247 strlcpy(u->oper,opertype.c_str(),NICKMAX-1);
00248 Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);
00249 this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));
00250 }
00251 return true;
00252 }
00253
00257 bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> ¶ms)
00258 {
00259 if (params.size() < 3)
00260 return true;
00261
00262 userrec* u = this->Instance->FindNick(params[0]);
00263
00264 if (u)
00265 {
00266 Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);
00267 if (IS_LOCAL(u))
00268 {
00269 std::deque<std::string> par;
00270 par.push_back(params[1]);
00271 if (!u->ForceNickChange(params[1].c_str()))
00272 {
00273 userrec::QuitUser(this->Instance, u, "Nickname collision");
00274 return true;
00275 }
00276 u->age = atoi(params[2].c_str());
00277 }
00278 }
00279 return true;
00280 }
00281
00282 bool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> ¶ms)
00283 {
00284 if (params.size() < 1)
00285 return true;
00286
00287 userrec* u = this->Instance->FindNick(prefix);
00288
00289 if (u)
00290 {
00291 u->SetOperQuit(params[0]);
00292 params[0] = ":" + params[0];
00293 Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);
00294 }
00295 return true;
00296 }
00297
00298 bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> ¶ms)
00299 {
00300 if (params.size() < 2)
00301 return true;
00302
00303 if (!this->Instance->IsChannel(params[1].c_str()))
00304 return true;
00305
00306 userrec* u = this->Instance->FindNick(params[0]);
00307
00308 if (u)
00309 {
00310
00311 if (IS_LOCAL(u))
00312 chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time());
00313 Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);
00314 }
00315 return true;
00316 }
00317
00318 bool TreeSocket::ServicePart(const std::string &prefix, std::deque<std::string> ¶ms)
00319 {
00320 if (params.size() < 2)
00321 return true;
00322
00323 if (!this->Instance->IsChannel(params[1].c_str()))
00324 return true;
00325
00326 userrec* u = this->Instance->FindNick(params[0]);
00327 chanrec* c = this->Instance->FindChan(params[1]);
00328
00329 if (u)
00330 {
00331
00332 if (IS_LOCAL(u))
00333 if (!c->PartUser(u, "Services forced part"))
00334 delete c;
00335 Utils->DoOneToAllButSender(prefix,"SVSPART",params,prefix);
00336 }
00337
00338 return true;
00339 }
00340
00341 bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> ¶ms)
00342 {
00343 if (params.size() < 1)
00344 return false;
00345
00346 std::string servermask = params[0];
00347 std::string parameter;
00348
00349 if (params.size() > 1)
00350 {
00351 parameter = params[1];
00352 }
00353
00354 if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))
00355 {
00356 this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");
00357 this->Instance->RehashServer();
00358 Utils->ReadConfiguration(true);
00359 FOREACH_MOD_I(this->Instance, I_OnRehash, OnRehash(NULL, parameter));
00360 InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);
00361 }
00362 Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);
00363 return true;
00364 }
00365
00366 bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> ¶ms)
00367 {
00368 if (params.size() != 2)
00369 return true;
00370
00371 userrec* who = this->Instance->FindNick(params[0]);
00372
00373 if (who)
00374 {
00375
00376 if ((*(params[1].c_str()) != 'K') && (*(params[1].c_str()) != '['))
00377 {
00378 params[1] = "Killed (" + params[1] +")";
00379 }
00380 std::string reason = params[1];
00381 params[1] = ":" + params[1];
00382 Utils->DoOneToAllButSender(prefix,"KILL",params,prefix);
00383
00384
00385 who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str());
00386 userrec::QuitUser(this->Instance,who,reason);
00387 }
00388 return true;
00389 }
00390
00391 bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> ¶ms)
00392 {
00393 if (params.size() < 1)
00394 return true;
00395
00396 if (params.size() == 1)
00397 {
00398 TreeServer* ServerSource = Utils->FindServer(prefix);
00399 if (ServerSource)
00400 {
00401 ServerSource->SetPingFlag();
00402 timeval t;
00403 gettimeofday(&t, NULL);
00404 long ts = (t.tv_sec * 1000) + (t.tv_usec / 1000);
00405 ServerSource->rtt = ts - ServerSource->LastPingMsec;
00406 }
00407 }
00408 else
00409 {
00410 std::string forwardto = params[1];
00411 if (forwardto == this->Instance->Config->ServerName)
00412 {
00413
00414
00415
00416
00417
00418
00419 userrec* u = this->Instance->FindNick(prefix);
00420 if (u)
00421 {
00422 u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
00423 }
00424 }
00425 else
00426 {
00427
00428 Utils->DoOneToOne(prefix,"PONG",params,forwardto);
00429 }
00430 }
00431
00432 return true;
00433 }
00434
00435 bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> ¶ms)
00436 {
00437 if (params.size() < 2)
00438 return true;
00439 else if (params.size() < 3)
00440 params.push_back("");
00441 TreeServer* ServerSource = Utils->FindServer(prefix);
00442 if (ServerSource)
00443 {
00444 Utils->SetRemoteBursting(ServerSource, false);
00445
00446 if (params[0] == "*")
00447 {
00448 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));
00449 }
00450 else if (*(params[0].c_str()) == '#')
00451 {
00452 chanrec* c = this->Instance->FindChan(params[0]);
00453 if (c)
00454 {
00455 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));
00456 }
00457 }
00458 else if (*(params[0].c_str()) != '#')
00459 {
00460 userrec* u = this->Instance->FindNick(params[0]);
00461 if (u)
00462 {
00463 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));
00464 }
00465 }
00466 }
00467
00468 params[2] = ":" + params[2];
00469 Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);
00470 return true;
00471 }
00472
00473 bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> ¶ms)
00474 {
00475 if (params.size() < 1)
00476 return true;
00477
00478 TreeServer* ServerSource = Utils->FindServer(prefix);
00479
00480 if (ServerSource)
00481 {
00482 ServerSource->SetVersion(params[0]);
00483 }
00484 params[0] = ":" + params[0];
00485 Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
00486 return true;
00487 }
00488
00489 bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> ¶ms)
00490 {
00491 if (params.size() < 1)
00492 return true;
00493 userrec* u = this->Instance->FindNick(prefix);
00494
00495 if (u)
00496 {
00497 u->ChangeDisplayedHost(params[0].c_str());
00498 Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);
00499 }
00500 return true;
00501 }
00502
00503 bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> ¶ms)
00504 {
00505 if (params.size() < 6)
00506 return true;
00507 bool propogate = false;
00508 if (!this->bursting)
00509 Utils->lines_to_apply = 0;
00510 switch (*(params[0].c_str()))
00511 {
00512 case 'Z':
00513 propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00514 Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00515 if (propogate)
00516 Utils->lines_to_apply |= APPLY_ZLINES;
00517 break;
00518 case 'Q':
00519 propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00520 Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00521 if (propogate)
00522 Utils->lines_to_apply |= APPLY_QLINES;
00523 break;
00524 case 'E':
00525 propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00526 Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00527 break;
00528 case 'G':
00529 propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00530 Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
00531 if (propogate)
00532 Utils->lines_to_apply |= APPLY_GLINES;
00533 break;
00534 case 'K':
00535 propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
00536 if (propogate)
00537 Utils->lines_to_apply |= APPLY_KLINES;
00538 break;
00539 default:
00540
00541 this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");
00542 propogate = false;
00543 break;
00544 }
00545
00546 if (propogate)
00547 {
00548 if (atoi(params[4].c_str()))
00549 {
00550 time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time();
00551 this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str());
00552 }
00553 else
00554 {
00555 this->Instance->SNO->WriteToSnoMask('x',"%s Added permanent %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());
00556 }
00557 params[5] = ":" + params[5];
00558 Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);
00559 }
00560 if (!this->bursting)
00561 {
00562 Instance->XLines->apply_lines(Utils->lines_to_apply);
00563 Utils->lines_to_apply = 0;
00564 }
00565 return true;
00566 }
00567
00568 bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> ¶ms)
00569 {
00570 if (params.size() < 1)
00571 return true;
00572 userrec* u = this->Instance->FindNick(prefix);
00573 if (u)
00574 {
00575 u->ChangeName(params[0].c_str());
00576 params[0] = ":" + params[0];
00577 Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);
00578 }
00579 return true;
00580 }
00581
00582 bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> ¶ms)
00583 {
00584 if (params.size() < 1)
00585 return true;
00586 userrec* u = this->Instance->FindNick(prefix);
00587 if (u)
00588 {
00589
00590 if (params.size() == 1)
00591 {
00592 userrec* x = this->Instance->FindNick(params[0]);
00593 if ((x) && (IS_LOCAL(x)))
00594 {
00595 userrec* x = this->Instance->FindNick(params[0]);
00596 char signon[MAXBUF];
00597 char idle[MAXBUF];
00598 snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon);
00599 snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true)));
00600 std::deque<std::string> par;
00601 par.push_back(prefix);
00602 par.push_back(signon);
00603 par.push_back(idle);
00604
00605 Utils->DoOneToOne(params[0], "IDLE", par, u->server);
00606 }
00607 else
00608 {
00609
00610 if (x)
00611 Utils->DoOneToOne(prefix, "IDLE", params, x->server);
00612 }
00613 }
00614 else if (params.size() == 3)
00615 {
00616 std::string who_did_the_whois = params[0];
00617 userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);
00618 if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
00619 {
00620
00621 std::string nick_whoised = prefix;
00622 unsigned long signon = atoi(params[1].c_str());
00623 unsigned long idle = atoi(params[2].c_str());
00624 if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
00625 {
00626 do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str());
00627 }
00628 }
00629 else
00630 {
00631
00632 if (who_to_send_to)
00633 Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
00634 }
00635 }
00636 }
00637 return true;
00638 }
00639
00640 bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> ¶ms)
00641 {
00642 if (params.size() < 2)
00643 return true;
00644 userrec* u = this->Instance->FindNick(params[0]);
00645 if (!u)
00646 return true;
00647 if (IS_LOCAL(u))
00648 {
00649 u->Write(params[1]);
00650 }
00651 else
00652 {
00653
00654 params[1] = ":" + params[1];
00655 Utils->DoOneToOne(prefix,"PUSH",params,u->server);
00656 }
00657 return true;
00658 }
00659
00660 bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> ¶ms)
00661 {
00662 if (!params.size() || !Utils->EnableTimeSync)
00663 return true;
00664
00665 bool force = false;
00666
00667 if ((params.size() == 2) && (params[1] == "FORCE"))
00668 force = true;
00669
00670 time_t them = atoi(params[0].c_str());
00671 time_t us = Instance->Time(false);
00672
00673 time_t diff = them - us;
00674
00675 Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
00676
00677 if (force || (them != us))
00678 {
00679 time_t old = Instance->SetTimeDelta(diff);
00680 Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old);
00681 }
00682
00683 return true;
00684 }
00685
00686 bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> ¶ms)
00687 {
00688
00689
00690 if (params.size() == 2)
00691 {
00692
00693 if (this->Instance->Config->ServerName == params[0])
00694 {
00695 userrec* u = this->Instance->FindNick(params[1]);
00696 if (u)
00697 {
00698 params.push_back(ConvToStr(Instance->Time(false)));
00699 params[0] = prefix;
00700 Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);
00701 }
00702 }
00703 else
00704 {
00705
00706 userrec* u = this->Instance->FindNick(params[1]);
00707 if (u)
00708 Utils->DoOneToOne(prefix,"TIME",params,params[0]);
00709 }
00710 }
00711 else if (params.size() == 3)
00712 {
00713
00714 userrec* u = this->Instance->FindNick(params[1]);
00715 if ((u) && (IS_LOCAL(u)))
00716 {
00717 time_t rawtime = atol(params[2].c_str());
00718 struct tm * timeinfo;
00719 timeinfo = localtime(&rawtime);
00720 char tms[26];
00721 snprintf(tms,26,"%s",asctime(timeinfo));
00722 tms[24] = 0;
00723 u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);
00724 }
00725 else
00726 {
00727 if (u)
00728 Utils->DoOneToOne(prefix,"TIME",params,u->server);
00729 }
00730 }
00731 return true;
00732 }
00733
00734 bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> ¶ms)
00735 {
00736 if (params.size() < 1)
00737 return true;
00738 if (params.size() == 1)
00739 {
00740 std::string stufftobounce = params[0];
00741 this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);
00742 return true;
00743 }
00744 else
00745 {
00746 std::string forwardto = params[1];
00747 if (forwardto == this->Instance->Config->ServerName)
00748 {
00749
00750 params[1] = params[0];
00751 params[0] = forwardto;
00752 Utils->DoOneToOne(forwardto,"PONG",params,params[1]);
00753 }
00754 else
00755 {
00756
00757 Utils->DoOneToOne(prefix,"PING",params,forwardto);
00758 }
00759 return true;
00760 }
00761 }
00762
00765 bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> ¶ms)
00766 {
00767 if (params.size() < 1)
00768 return true;
00769 chanrec* c = Instance->FindChan(params[0]);
00770 if (c)
00771 {
00772 for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)
00773 {
00774 ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
00775 if (mh)
00776 mh->RemoveMode(c);
00777 }
00778 }
00779 return true;
00780 }
00781
00782 bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> ¶ms)
00783 {
00784 if (params.size() < 4)
00785 return false;
00786 std::string servername = params[0];
00787 std::string password = params[1];
00788
00789 std::string description = params[3];
00790 TreeServer* ParentOfThis = Utils->FindServer(prefix);
00791 if (!ParentOfThis)
00792 {
00793 this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);
00794 return false;
00795 }
00796 TreeServer* CheckDupe = Utils->FindServer(servername);
00797 if (CheckDupe)
00798 {
00799 this->SendError("Server "+servername+" already exists!");
00800 this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
00801 return false;
00802 }
00803 Link* lnk = Utils->FindLink(servername);
00804 TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false);
00805 ParentOfThis->AddChild(Node);
00806 params[3] = ":" + params[3];
00807 Utils->SetRemoteBursting(Node, true);
00808 Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
00809 this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
00810 return true;
00811 }
00812
00813 bool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs)
00814 {
00815 if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12)))
00816 {
00817
00818
00819
00820 if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse)
00821 return false;
00822 else
00823
00824 return ours == theirs;
00825 }
00826 else
00827
00828 return ours == theirs;
00829 }
00830
00831 bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> ¶ms)
00832 {
00833 if (params.size() < 4)
00834 return false;
00835
00836 irc::string servername = params[0].c_str();
00837 std::string sname = params[0];
00838 std::string password = params[1];
00839 std::string description = params[3];
00840 int hops = atoi(params[2].c_str());
00841
00842 this->InboundServerName = sname;
00843 this->InboundDescription = description;
00844
00845 if (!sentcapab)
00846 this->SendCapabilities();
00847
00848 if (hops)
00849 {
00850 this->SendError("Server too far away for authentication");
00851 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
00852 return false;
00853 }
00854
00855 for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
00856 {
00857 if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty()))))
00858 {
00859 TreeServer* CheckDupe = Utils->FindServer(sname);
00860 if (CheckDupe)
00861 {
00862 this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
00863 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
00864 return false;
00865 }
00866
00867
00868
00869
00870 this->LinkState = CONNECTED;
00871
00872
00873
00874 TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden);
00875 Utils->TreeRoot->AddChild(Node);
00876 params[3] = ":" + params[3];
00877 Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);
00878 this->bursting = true;
00879 this->DoBurst(Node);
00880 return true;
00881 }
00882 }
00883 this->SendError("Invalid credentials");
00884 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
00885 return false;
00886 }
00887
00888 bool TreeSocket::Inbound_Server(std::deque<std::string> ¶ms)
00889 {
00890 if (params.size() < 4)
00891 return false;
00892 irc::string servername = params[0].c_str();
00893 std::string sname = params[0];
00894 std::string password = params[1];
00895 std::string description = params[3];
00896 int hops = atoi(params[2].c_str());
00897
00898 this->InboundServerName = sname;
00899 this->InboundDescription = description;
00900
00901 if (!sentcapab)
00902 this->SendCapabilities();
00903
00904 if (hops)
00905 {
00906 this->SendError("Server too far away for authentication");
00907 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
00908 return false;
00909 }
00910
00911 for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
00912 {
00913 if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty()))))
00914 {
00915
00916 TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname);
00917 if (CheckDupeSocket)
00918 {
00919
00920 this->SendError("Negotiation collision");
00921 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state.");
00922 CheckDupeSocket->SendError("Negotiation collision");
00923 Instance->SE->DelFd(CheckDupeSocket);
00924 CheckDupeSocket->Close();
00925 return false;
00926 }
00927
00928 TreeServer* CheckDupe = Utils->FindServer(sname);
00929 if (CheckDupe)
00930 {
00931 this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
00932 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
00933 return false;
00934 }
00935 this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");
00936 if (this->Hook)
00937 {
00938 std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();
00939 this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");
00940 }
00941
00942 Utils->AddBurstingServer(sname,this);
00943
00944
00945
00946 this->SendCapabilities();
00947 this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
00948
00949 this->LinkState = WAIT_AUTH_2;
00950 return true;
00951 }
00952 }
00953 this->SendError("Invalid credentials");
00954 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
00955 return false;
00956 }
00957
00958 void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
00959 {
00960 n.clear();
00961 irc::tokenstream tokens(line);
00962 std::string param;
00963 while (tokens.GetToken(param))
00964 {
00965 n.push_back(param);
00966 }
00967 return;
00968 }
00969
00970 bool TreeSocket::ProcessLine(std::string &line)
00971 {
00972 std::deque<std::string> params;
00973 irc::string command;
00974 std::string prefix;
00975
00976 line = line.substr(0, line.find_first_of("\r\n"));
00977
00978 if (line.empty())
00979 return true;
00980
00981 Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str());
00982
00983 this->Split(line.c_str(),params);
00984
00985 if (params.empty())
00986 return true;
00987
00988 if ((params[0][0] == ':') && (params.size() > 1))
00989 {
00990 prefix = params[0].substr(1);
00991 params.pop_front();
00992 }
00993 command = params[0].c_str();
00994 params.pop_front();
00995 switch (this->LinkState)
00996 {
00997 TreeServer* Node;
00998
00999 case WAIT_AUTH_1:
01000
01001
01002
01003
01004
01005 if (command == "PASS")
01006 {
01007
01008 }
01009 else if (command == "SERVER")
01010 {
01011 return this->Inbound_Server(params);
01012 }
01013 else if (command == "ERROR")
01014 {
01015 return this->Error(params);
01016 }
01017 else if (command == "USER")
01018 {
01019 this->SendError("Client connections to this port are prohibited.");
01020 return false;
01021 }
01022 else if (command == "CAPAB")
01023 {
01024 return this->Capab(params);
01025 }
01026 else if ((command == "U") || (command == "S"))
01027 {
01028 this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
01029 return false;
01030 }
01031 else
01032 {
01033 irc::string error = "Invalid command in negotiation phase: " + command;
01034 this->SendError(assign(error));
01035 return false;
01036 }
01037 break;
01038 case WAIT_AUTH_2:
01039
01040
01041 if (command == "SERVER")
01042 {
01043
01044
01045 return true;
01046 }
01047 else if ((command == "U") || (command == "S"))
01048 {
01049 this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
01050 return false;
01051 }
01052 else if (command == "BURST")
01053 {
01054 if (params.size() && Utils->EnableTimeSync)
01055 {
01056 bool we_have_delta = (Instance->Time(false) != Instance->Time(true));
01057 time_t them = atoi(params[0].c_str());
01058 time_t delta = them - Instance->Time(false);
01059 if ((delta < -300) || (delta > 300))
01060 {
01061 Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
01062 SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
01063 return false;
01064 }
01065 else if ((delta < -30) || (delta > 30))
01066 {
01067 Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta));
01068 }
01069
01070 if (!Utils->MasterTime && !we_have_delta)
01071 {
01072 this->Instance->SetTimeDelta(delta);
01073
01074 Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
01075 }
01076 }
01077 this->LinkState = CONNECTED;
01078 TreeServer* CheckDupe = Utils->FindServer(InboundServerName);
01079 if (CheckDupe)
01080 {
01081 this->SendError("Server "+InboundServerName+" already exists!");
01082 this->Instance->SNO->WriteToSnoMask('l',"Server \2"+InboundServerName+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
01083 return false;
01084 }
01085 Link* lnk = Utils->FindLink(InboundServerName);
01086 Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);
01087 Utils->DelBurstingServer(this);
01088 Utils->TreeRoot->AddChild(Node);
01089 params.clear();
01090 params.push_back(InboundServerName);
01091 params.push_back("*");
01092 params.push_back("1");
01093 params.push_back(":"+InboundDescription);
01094 Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);
01095 this->bursting = true;
01096 this->DoBurst(Node);
01097 }
01098 else if (command == "ERROR")
01099 {
01100 return this->Error(params);
01101 }
01102 else if (command == "CAPAB")
01103 {
01104 return this->Capab(params);
01105 }
01106
01107 break;
01108 case LISTENER:
01109 this->SendError("Internal error -- listening socket accepted its own descriptor!!!");
01110 return false;
01111 break;
01112 case CONNECTING:
01113 if (command == "SERVER")
01114 {
01115
01116
01117
01118
01119
01120 return this->Outbound_Reply_Server(params);
01121 }
01122 else if (command == "ERROR")
01123 {
01124 return this->Error(params);
01125 }
01126 else if (command == "CAPAB")
01127 {
01128 return this->Capab(params);
01129 }
01130 break;
01131 case CONNECTED:
01132
01133
01134
01135
01136 if (!prefix.empty())
01137 {
01138 std::string direction = prefix;
01139 userrec* t = this->Instance->FindNick(prefix);
01140 if (t)
01141 {
01142 direction = t->server;
01143 }
01144 TreeServer* route_back_again = Utils->BestRouteTo(direction);
01145 if ((!route_back_again) || (route_back_again->GetSocket() != this))
01146 {
01147 if (route_back_again)
01148 Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
01149 return true;
01150 }
01151
01152
01153
01154
01155 route_back_again->SetNextPingTime(time(NULL) + Utils->PingFreq);
01156 route_back_again->SetPingFlag();
01157 }
01158 else
01159 {
01160 prefix = this->GetName();
01161 }
01162
01163 if ((command == "MODE") && (params.size() >= 2))
01164 {
01165 chanrec* channel = Instance->FindChan(params[0]);
01166 if (channel)
01167 {
01168 userrec* x = Instance->FindNick(prefix);
01169 if (x)
01170 {
01171 if (warned.find(x->server) == warned.end())
01172 {
01173 Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server);
01174 Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str());
01175 warned[x->server] = x->nick;
01176 }
01177 }
01178 }
01179 }
01180
01181 if (command == "SVSMODE")
01182 {
01183
01184
01185
01186
01187 command = "MODE";
01188 }
01189 std::string target;
01190
01191
01192
01193 if ((command == "NICK") && (params.size() >= 8))
01194 {
01195 return this->IntroduceClient(prefix,params);
01196 }
01197 else if (command == "FJOIN")
01198 {
01199 TreeServer* ServerSource = Utils->FindServer(prefix);
01200 if (ServerSource)
01201 Utils->SetRemoteBursting(ServerSource, false);
01202 return this->ForceJoin(prefix,params);
01203 }
01204 else if (command == "STATS")
01205 {
01206 return this->Stats(prefix, params);
01207 }
01208 else if (command == "MOTD")
01209 {
01210 return this->Motd(prefix, params);
01211 }
01212 else if (command == "KILL" && Utils->IsServer(prefix))
01213 {
01214 return this->RemoteKill(prefix,params);
01215 }
01216 else if (command == "MODULES")
01217 {
01218 return this->Modules(prefix, params);
01219 }
01220 else if (command == "ADMIN")
01221 {
01222 return this->Admin(prefix, params);
01223 }
01224 else if (command == "SERVER")
01225 {
01226 return this->RemoteServer(prefix,params);
01227 }
01228 else if (command == "ERROR")
01229 {
01230 return this->Error(params);
01231 }
01232 else if (command == "OPERTYPE")
01233 {
01234 return this->OperType(prefix,params);
01235 }
01236 else if (command == "FMODE")
01237 {
01238 TreeServer* ServerSource = Utils->FindServer(prefix);
01239 if (ServerSource)
01240 Utils->SetRemoteBursting(ServerSource, false);
01241 return this->ForceMode(prefix,params);
01242 }
01243 else if (command == "FTOPIC")
01244 {
01245 return this->ForceTopic(prefix,params);
01246 }
01247 else if (command == "REHASH")
01248 {
01249 return this->RemoteRehash(prefix,params);
01250 }
01251 else if (command == "METADATA")
01252 {
01253 return this->MetaData(prefix,params);
01254 }
01255 else if (command == "REMSTATUS")
01256 {
01257 return this->RemoveStatus(prefix,params);
01258 }
01259 else if (command == "PING")
01260 {
01261 if (prefix.empty())
01262 prefix = this->GetName();
01263
01264
01265
01266
01267
01268 TreeServer* ServerSource = Utils->FindServer(prefix);
01269 if (ServerSource)
01270 Utils->SetRemoteBursting(ServerSource, false);
01271
01272 if (this->bursting)
01273 {
01274 this->bursting = false;
01275 Instance->XLines->apply_lines(Utils->lines_to_apply);
01276 Utils->lines_to_apply = 0;
01277 }
01278
01279 return this->LocalPing(prefix,params);
01280 }
01281 else if (command == "PONG")
01282 {
01283 if (prefix.empty())
01284 prefix = this->GetName();
01285
01286
01287
01288
01289
01290 TreeServer* ServerSource = Utils->FindServer(prefix);
01291 if (ServerSource)
01292 Utils->SetRemoteBursting(ServerSource, false);
01293
01294 if (this->bursting)
01295 {
01296 this->bursting = false;
01297 Instance->XLines->apply_lines(Utils->lines_to_apply);
01298 Utils->lines_to_apply = 0;
01299 }
01300
01301 return this->LocalPong(prefix,params);
01302 }
01303 else if (command == "VERSION")
01304 {
01305 return this->ServerVersion(prefix,params);
01306 }
01307 else if (command == "FHOST")
01308 {
01309 return this->ChangeHost(prefix,params);
01310 }
01311 else if (command == "FNAME")
01312 {
01313 return this->ChangeName(prefix,params);
01314 }
01315 else if (command == "ADDLINE")
01316 {
01317 TreeServer* ServerSource = Utils->FindServer(prefix);
01318 if (ServerSource)
01319 Utils->SetRemoteBursting(ServerSource, false);
01320 return this->AddLine(prefix,params);
01321 }
01322 else if (command == "SVSNICK")
01323 {
01324 if (prefix.empty())
01325 {
01326 prefix = this->GetName();
01327 }
01328 return this->ForceNick(prefix,params);
01329 }
01330 else if (command == "OPERQUIT")
01331 {
01332 return this->OperQuit(prefix,params);
01333 }
01334 else if (command == "IDLE")
01335 {
01336 return this->Whois(prefix,params);
01337 }
01338 else if (command == "PUSH")
01339 {
01340 return this->Push(prefix,params);
01341 }
01342 else if (command == "TIMESET")
01343 {
01344 return this->HandleSetTime(prefix, params);
01345 }
01346 else if (command == "TIME")
01347 {
01348 return this->Time(prefix,params);
01349 }
01350 else if ((command == "KICK") && (Utils->IsServer(prefix)))
01351 {
01352 std::string sourceserv = this->myhost;
01353 if (params.size() == 3)
01354 {
01355 userrec* user = this->Instance->FindNick(params[1]);
01356 chanrec* chan = this->Instance->FindChan(params[0]);
01357 if (user && chan)
01358 {
01359 if (!chan->ServerKickUser(user, params[2].c_str(), false))
01360
01361 delete chan;
01362 }
01363 }
01364 if (!this->InboundServerName.empty())
01365 {
01366 sourceserv = this->InboundServerName;
01367 }
01368 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01369 }
01370 else if (command == "SVSJOIN")
01371 {
01372 if (prefix.empty())
01373 {
01374 prefix = this->GetName();
01375 }
01376 return this->ServiceJoin(prefix,params);
01377 }
01378 else if (command == "SVSPART")
01379 {
01380 if (prefix.empty())
01381 prefix = this->GetName();
01382 return this->ServicePart(prefix,params);
01383 }
01384 else if (command == "SQUIT")
01385 {
01386 if (params.size() == 2)
01387 {
01388 this->Squit(Utils->FindServer(params[0]),params[1]);
01389 }
01390 return true;
01391 }
01392 else if (command == "OPERNOTICE")
01393 {
01394 std::string sourceserv = this->myhost;
01395 if (!this->InboundServerName.empty())
01396 sourceserv = this->InboundServerName;
01397 if (params.size() >= 1)
01398 Instance->WriteOpers("*** From " + prefix + ": " + params[0]);
01399 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01400 }
01401 else if (command == "MODENOTICE")
01402 {
01403 std::string sourceserv = this->myhost;
01404 if (!this->InboundServerName.empty())
01405 sourceserv = this->InboundServerName;
01406 if (params.size() >= 2)
01407 {
01408 Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", prefix.c_str(), params[1].c_str());
01409 }
01410 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01411 }
01412 else if (command == "SNONOTICE")
01413 {
01414 std::string sourceserv = this->myhost;
01415 if (!this->InboundServerName.empty())
01416 sourceserv = this->InboundServerName;
01417 if (params.size() >= 2)
01418 {
01419 Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + prefix + ": "+ params[1]);
01420 }
01421 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
01422 }
01423 else if (command == "ENDBURST")
01424 {
01425 this->bursting = false;
01426 Instance->XLines->apply_lines(Utils->lines_to_apply);
01427 Utils->lines_to_apply = 0;
01428 std::string sourceserv = this->myhost;
01429 if (!this->InboundServerName.empty())
01430 sourceserv = this->InboundServerName;
01431 this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());
01432
01433 Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");
01434 rmode.Send(Instance);
01435
01436 return true;
01437 }
01438 else
01439 {
01440
01441
01442
01443 userrec* who = this->Instance->FindNick(prefix);
01444 std::string sourceserv = this->myhost;
01445 if (!this->InboundServerName.empty())
01446 {
01447 sourceserv = this->InboundServerName;
01448 }
01449 if ((!who) && (command == "MODE"))
01450 {
01451 if (Utils->IsServer(prefix))
01452 {
01453 const char* modelist[127];
01454 for (size_t i = 0; i < params.size(); i++)
01455 modelist[i] = params[i].c_str();
01456 userrec* fake = new userrec(Instance);
01457 fake->SetFd(FD_MAGIC_NUMBER);
01458 this->Instance->SendMode(modelist, params.size(), fake);
01459
01460 delete fake;
01461
01462 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01463 }
01464 }
01465 if (who)
01466 {
01467 if ((command == "NICK") && (params.size() > 0))
01468 {
01469
01470
01471
01472
01473 userrec* x = this->Instance->FindNick(params[0]);
01474 if ((x) && (x != who))
01475 {
01476 std::deque<std::string> p;
01477 p.push_back(params[0]);
01478 p.push_back(":Nickname collision ("+prefix+" -> "+params[0]+")");
01479 Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
01480 p.clear();
01481 p.push_back(prefix);
01482 p.push_back(":Nickname collision");
01483 Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
01484 userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");
01485 userrec* y = this->Instance->FindNick(prefix);
01486 if (y)
01487 {
01488 userrec::QuitUser(this->Instance,y,"Nickname collision");
01489 }
01490 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01491 }
01492 }
01493
01494 target = who->server;
01495 const char* strparams[127];
01496 for (unsigned int q = 0; q < params.size(); q++)
01497 {
01498 strparams[q] = params[q].c_str();
01499 }
01500 switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))
01501 {
01502 case CMD_INVALID:
01503 this->SendError("Unrecognised or malformed command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");
01504 return false;
01505 break;
01506 case CMD_FAILURE:
01507 return true;
01508 break;
01509 default:
01510
01511 break;
01512 }
01513 }
01514 else
01515 {
01516
01517 if (Utils->IsServer(prefix))
01518 target = this->Instance->Config->ServerName;
01519 else
01520 return true;
01521 }
01522 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
01523
01524 }
01525 return true;
01526 break;
01527 }
01528 return true;
01529 }
01530
01531 std::string TreeSocket::GetName()
01532 {
01533 std::string sourceserv = this->myhost;
01534 if (!this->InboundServerName.empty())
01535 {
01536 sourceserv = this->InboundServerName;
01537 }
01538 return sourceserv;
01539 }
01540
01541 void TreeSocket::OnTimeout()
01542 {
01543 if (this->LinkState == CONNECTING)
01544 {
01545 Utils->Creator->RemoteMessage(NULL, "CONNECT: Connection to \002%s\002 timed out.", myhost.c_str());
01546 Link* MyLink = Utils->FindLink(myhost);
01547 if (MyLink)
01548 Utils->DoFailOver(MyLink);
01549 }
01550 }
01551
01552 void TreeSocket::OnClose()
01553 {
01554
01555 if (this->LinkState != CONNECTED)
01556 return;
01557
01558
01559
01560
01561 std::string quitserver = this->myhost;
01562 if (!this->InboundServerName.empty())
01563 {
01564 quitserver = this->InboundServerName;
01565 }
01566 TreeServer* s = Utils->FindServer(quitserver);
01567 if (s)
01568 {
01569 Squit(s,"Remote host closed the connection");
01570 }
01571
01572 if (!quitserver.empty())
01573 {
01574 Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' failed.",quitserver.c_str());
01575 time_t server_uptime = Instance->Time() - this->age;
01576 if (server_uptime)
01577 Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());
01578 }
01579 }
01580
01581 int TreeSocket::OnIncomingConnection(int newsock, char* ip)
01582 {
01583
01584
01585
01586
01587 bool found = false;
01588
01589 found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
01590 if (!found)
01591 {
01592 for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
01593 if (irc::sockets::MatchCIDR(ip, (*i).c_str()))
01594 found = true;
01595
01596 if (!found)
01597 {
01598 this->Instance->SNO->WriteToSnoMask('d',"Server connection from %s denied (no link blocks with that IP address", ip);
01599 close(newsock);
01600 return false;
01601 }
01602 }
01603
01604 TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
01605 s = s;
01606 return true;
01607 }