00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "commands/cmd_whois.h"
00016 #include "commands/cmd_stats.h"
00017 #include "socket.h"
00018 #include "xline.h"
00019 #include "transport.h"
00020 #include "socketengine.h"
00021
00022 #include "m_spanningtree/main.h"
00023 #include "m_spanningtree/utils.h"
00024 #include "m_spanningtree/treeserver.h"
00025 #include "m_spanningtree/link.h"
00026 #include "m_spanningtree/treesocket.h"
00027 #include "m_spanningtree/resolvers.h"
00028 #include "m_spanningtree/handshaketimer.h"
00029
00030
00031
00032 void TreeSocket::WriteLine(std::string line)
00033 {
00034 Instance->Logs->Log("m_spanningtree",DEBUG, "S[%d] O %s", this->GetFd(), line.c_str());
00035 line.append("\r\n");
00036 this->Write(line);
00037 }
00038
00039
00040
00041 bool TreeSocket::Error(std::deque<std::string> ¶ms)
00042 {
00043 if (params.size() < 1)
00044 return false;
00045 this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
00046
00047 return false;
00048 }
00049
00050 void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
00051 {
00052 n.clear();
00053 irc::tokenstream tokens(line);
00054 std::string param;
00055 while (tokens.GetToken(param))
00056 {
00057 n.push_back(param);
00058 }
00059 return;
00060 }
00061
00062 bool TreeSocket::ProcessLine(std::string &line)
00063 {
00064 std::deque<std::string> params;
00065 irc::string command;
00066 std::string prefix;
00067
00068 line = line.substr(0, line.find_first_of("\r\n"));
00069
00070 if (line.empty())
00071 return true;
00072
00073 Instance->Logs->Log("m_spanningtree",DEBUG, "S[%d] I %s", this->GetFd(), line.c_str());
00074
00075 this->Split(line.c_str(),params);
00076
00077 if (params.empty())
00078 return true;
00079
00080 if ((params[0][0] == ':') && (params.size() > 1))
00081 {
00082 prefix = params[0].substr(1);
00083 params.pop_front();
00084
00085 if (prefix.empty())
00086 {
00087 this->SendError("BUG (?) Empty prefix recieved.");
00088 return false;
00089 }
00090 }
00091
00092 command = params[0].c_str();
00093 params.pop_front();
00094
00095 switch (this->LinkState)
00096 {
00097 TreeServer* Node;
00098
00099 case WAIT_AUTH_1:
00100
00101
00102
00103
00104
00105
00106
00107
00108 if (command == "PASS")
00109 {
00110
00111
00112
00113
00114
00115
00116 }
00117 else if (command == "SERVER")
00118 {
00119 return this->Inbound_Server(params);
00120 }
00121 else if (command == "ERROR")
00122 {
00123 return this->Error(params);
00124 }
00125 else if (command == "USER")
00126 {
00127 this->SendError("Client connections to this port are prohibited.");
00128 return false;
00129 }
00130 else if (command == "CAPAB")
00131 {
00132 return this->Capab(params);
00133 }
00134 else
00135 {
00136
00137 irc::string error = "Invalid command in negotiation phase: " + command;
00138 this->SendError(assign(error));
00139 return false;
00140 }
00141 break;
00142 case WAIT_AUTH_2:
00143
00144
00145
00146
00147
00148
00149 if (command == "SERVER")
00150 {
00151
00152
00153
00154
00155 this->SendError("You may not re-authenticate or commence netburst without sending BURST.");
00156 return true;
00157 }
00158 else if (command == "BURST")
00159 {
00160 if (params.size())
00161 {
00162 time_t them = atoi(params[0].c_str());
00163 time_t delta = them - Instance->Time();
00164 if ((delta < -600) || (delta > 600))
00165 {
00166 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((long)delta));
00167 SendError("Your clocks are out by "+ConvToStr(abs((long)delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
00168 return false;
00169 }
00170 else if ((delta < -30) || (delta > 30))
00171 {
00172 Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs((long)delta));
00173 }
00174 }
00175 this->LinkState = CONNECTED;
00176 Link* lnk = Utils->FindLink(InboundServerName);
00177
00178 Node = new TreeServer(this->Utils, this->Instance, InboundServerName, InboundDescription, InboundSID, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);
00179
00180 if (Node->DuplicateID())
00181 {
00182 this->SendError("Server ID "+InboundSID+" already exists on the network!");
00183 this->Instance->SNO->WriteToSnoMask('l',"Server \2"+InboundServerName+"\2 being introduced from \2" + prefix + "\2 denied, server ID already exists on the network. Closing link.");
00184 return false;
00185 }
00186
00187 Utils->TreeRoot->AddChild(Node);
00188 params.clear();
00189 params.push_back(InboundServerName);
00190 params.push_back("*");
00191 params.push_back("1");
00192 params.push_back(InboundSID);
00193 params.push_back(":"+InboundDescription);
00194 Utils->DoOneToAllButSender(Instance->Config->GetSID(),"SERVER",params,InboundServerName);
00195 Node->bursting = true;
00196 this->DoBurst(Node);
00197 }
00198 else if (command == "ERROR")
00199 {
00200 return this->Error(params);
00201 }
00202 else if (command == "CAPAB")
00203 {
00204 return this->Capab(params);
00205 }
00206
00207 break;
00208 case LISTENER:
00209
00210
00211
00212 this->SendError("Internal error -- listening socket accepted its own descriptor!!!");
00213 return false;
00214 break;
00215 case CONNECTING:
00216
00217
00218
00219
00220
00221
00222 if (command == "SERVER")
00223 {
00224
00225 return this->Outbound_Reply_Server(params);
00226 }
00227 else if (command == "ERROR")
00228 {
00229 return this->Error(params);
00230 }
00231 else if (command == "CAPAB")
00232 {
00233 return this->Capab(params);
00234 }
00235 break;
00236 case CONNECTED:
00237
00238
00239
00240
00241
00242 if (!prefix.empty())
00243 {
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 std::string direction = prefix;
00257
00258 User *t = this->Instance->FindUUID(prefix);
00259 if (t)
00260 {
00261 direction = t->server;
00262 }
00263
00264 TreeServer* route_back_again = Utils->BestRouteTo(direction);
00265 if ((!route_back_again) || (route_back_again->GetSocket() != this))
00266 {
00267 if (route_back_again)
00268 Instance->Logs->Log("m_spanningtree",DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
00269 return true;
00270 }
00271
00272
00273
00274
00275 route_back_again->SetNextPingTime(Instance->Time() + Utils->PingFreq);
00276 route_back_again->SetPingFlag();
00277 }
00278 else
00279 {
00280
00281
00282
00283
00284
00285 TreeServer* n = Utils->FindServer(GetName());
00286 if (n)
00287 prefix = n->GetID();
00288 else
00289 prefix = GetName();
00290 }
00291
00292
00293
00294
00295
00296 if (command == "SVSMODE")
00297 command = "MODE";
00298
00299
00300
00301
00302
00303
00304 TreeServer *ServerSource = Utils->FindServer(prefix);
00305
00306
00307 std::string sourceserv = this->myhost;
00308 if (!this->InboundServerName.empty())
00309 {
00310 sourceserv = this->InboundServerName;
00311 }
00312
00313
00314
00315
00316 if (command == "UID")
00317 {
00318 return this->ParseUID(prefix, params);
00319 }
00320 else if (command == "FJOIN")
00321 {
00322 return this->ForceJoin(prefix,params);
00323 }
00324 else if ((command == "NOTICE" || command == "PRIVMSG") && (Utils->IsServer(prefix)))
00325 {
00326 return this->ServerMessage(assign(command), prefix, params, sourceserv);
00327 }
00328 else if (command == "STATS")
00329 {
00330 return this->Stats(prefix, params);
00331 }
00332 else if (command == "MOTD")
00333 {
00334 return this->Motd(prefix, params);
00335 }
00336 else if (command == "KILL" && ServerSource)
00337 {
00338
00339 return this->RemoteKill(prefix,params);
00340 }
00341 else if (command == "MODULES")
00342 {
00343 return this->Modules(prefix, params);
00344 }
00345 else if (command == "ADMIN")
00346 {
00347 return this->Admin(prefix, params);
00348 }
00349 else if (command == "MAP")
00350 {
00351 User* user = Instance->FindNick(prefix);
00352 if (user)
00353 {
00354 std::vector<std::string> p(params.begin(), params.end());
00355 return Utils->Creator->HandleMap(p, user);
00356 }
00357 }
00358 else if (command == "SERVER")
00359 {
00360 return this->RemoteServer(prefix,params);
00361 }
00362 else if (command == "ERROR")
00363 {
00364 return this->Error(params);
00365 }
00366 else if (command == "OPERTYPE")
00367 {
00368 return this->OperType(prefix,params);
00369 }
00370 else if (command == "FMODE")
00371 {
00372 return this->ForceMode(prefix,params);
00373 }
00374 else if (command == "FTOPIC")
00375 {
00376 return this->ForceTopic(prefix,params);
00377 }
00378 else if (command == "METADATA")
00379 {
00380 return this->MetaData(prefix,params);
00381 }
00382 else if (command == "PING")
00383 {
00384 return this->LocalPing(prefix,params);
00385 }
00386 else if (command == "PONG")
00387 {
00388 TreeServer *s = Utils->FindServer(prefix);
00389 if (s && s->bursting)
00390 {
00391 Instance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not finished burst, forcing end of burst (send ENDBURST!)", prefix.c_str());
00392 s->FinishBurst();
00393 }
00394 return this->LocalPong(prefix,params);
00395 }
00396 else if (command == "VERSION")
00397 {
00398 return this->ServerVersion(prefix,params);
00399 }
00400 else if (command == "FHOST")
00401 {
00402 return this->ChangeHost(prefix,params);
00403 }
00404 else if (command == "FNAME")
00405 {
00406 return this->ChangeName(prefix,params);
00407 }
00408 else if (command == "ADDLINE")
00409 {
00410 return this->AddLine(prefix,params);
00411 }
00412 else if (command == "DELLINE")
00413 {
00414 return this->DelLine(prefix,params);
00415 }
00416 else if (command == "SVSNICK")
00417 {
00418 return this->ForceNick(prefix,params);
00419 }
00420 else if (command == "OPERQUIT")
00421 {
00422 return this->OperQuit(prefix,params);
00423 }
00424 else if (command == "IDLE")
00425 {
00426 return this->Whois(prefix,params);
00427 }
00428 else if (command == "PUSH")
00429 {
00430 return this->Push(prefix,params);
00431 }
00432 else if (command == "TIME")
00433 {
00434 return this->Time(prefix,params);
00435 }
00436 else if ((command == "KICK") && (Utils->IsServer(prefix)))
00437 {
00438 if (params.size() == 3)
00439 {
00440 TreeServer* pf = Utils->FindServer(prefix);
00441 User* user = this->Instance->FindNick(params[1]);
00442 Channel* chan = this->Instance->FindChan(params[0]);
00443 if (pf && user && chan)
00444 {
00445 if (!chan->ServerKickUser(user, params[2].c_str(), false, pf->GetName().c_str()))
00446
00447 delete chan;
00448 }
00449 }
00450
00451 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
00452 }
00453 else if (command == "SVSJOIN")
00454 {
00455 return this->ServiceJoin(prefix,params);
00456 }
00457 else if (command == "SVSPART")
00458 {
00459 return this->ServicePart(prefix,params);
00460 }
00461 else if (command == "SQUIT")
00462 {
00463 if (params.size() == 2)
00464 {
00465 this->Squit(Utils->FindServer(params[0]),params[1]);
00466 }
00467 return true;
00468 }
00469 else if (command == "MODENOTICE")
00470 {
00471 if (params.size() >= 2)
00472 {
00473 if (ServerSource)
00474 Instance->Users->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str()), params[1].c_str());
00475 }
00476 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
00477 }
00478 else if (command == "SNONOTICE")
00479 {
00480 if (params.size() >= 2)
00481 {
00482 Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + (ServerSource ? ServerSource->GetName().c_str() : prefix) + ": "+ params[1]);
00483 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
00484 }
00485
00486 }
00487 else if (command == "BURST")
00488 {
00489
00490 if (!ServerSource)
00491 {
00492 this->Instance->SNO->WriteToSnoMask('l', "WTF: Got BURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str()));
00493 return false;
00494 }
00495
00496 ServerSource->bursting = true;
00497 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
00498 }
00499 else if (command == "ENDBURST")
00500 {
00501 if (!ServerSource)
00502 {
00503 this->Instance->SNO->WriteToSnoMask('l', "WTF: Got ENDBURST from a nonexistant server(?): %s", (ServerSource ? ServerSource->GetName().c_str() : prefix.c_str()));
00504 return false;
00505 }
00506
00507 ServerSource->FinishBurst();
00508 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
00509 }
00510 else if (command == "ENCAP")
00511 {
00512 return this->Encap(prefix, params);
00513 }
00514 else if (command == "MODE" && !this->Instance->FindUUID(prefix))
00515 {
00516
00517 std::vector<std::string> modelist(params.begin(), params.end());
00518
00519
00520 if (params.size() >= 1)
00521 {
00522 if (Instance->FindChan(params[0]))
00523 {
00524 this->SendError("Protocol violation by '"+(ServerSource ? ServerSource->GetName().c_str() : prefix)+"'! MODE for channel mode changes is not supported by the InspIRCd 1.2 protocol. You must use FMODE to preserve channel timestamps.");
00525 return false;
00526 }
00527 }
00528
00529
00530 this->Instance->SendMode(modelist, this->Instance->FakeClient);
00531
00532
00533 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
00534 }
00535 else
00536 {
00537
00538
00539
00540
00541 User *who = this->Instance->FindUUID(prefix);
00542
00543 if (!who)
00544 {
00545
00546 this->SendError("Command (" + std::string(command.c_str()) + ") from unknown prefix (" + prefix + ")! Dropping link.");
00547 return false;
00548 }
00549
00550 if (command == "NICK")
00551 {
00552 if (params.size() != 2)
00553 {
00554 SendError("Protocol violation: NICK message without TS - :"+std::string(who->uuid)+" NICK "+params[0]);
00555 return false;
00556 }
00557
00558 who->age = atoi(params[1].c_str());
00559
00560
00561
00562
00563
00564 User* x = this->Instance->FindNickOnly(params[0]);
00565 if ((x) && (x != who))
00566 {
00567 int collideret = 0;
00568
00569 collideret = this->DoCollision(x, who->age, who->ident, who->GetIPString(), who->uuid);
00570 if (collideret != 1)
00571 {
00572
00573
00574
00575
00576
00577 return true;
00578 }
00579 }
00580 }
00581
00582
00583 std::vector<std::string> strparams(params.begin(), params.end());
00584
00585 switch (this->Instance->CallCommandHandler(command.c_str(), strparams, who))
00586 {
00587 case CMD_INVALID:
00588
00589
00590
00591 this->SendError("Unrecognised or malformed command '" + std::string(command.c_str()) + "' -- possibly loaded mismatched modules");
00592 return false;
00593 break;
00594 case CMD_FAILURE:
00595
00596
00597
00598 return true;
00599 break;
00600 default:
00601
00602 break;
00603 }
00604
00605 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
00606
00607 }
00608 return true;
00609 break;
00610 }
00611 return true;
00612 }
00613
00614 std::string TreeSocket::GetName()
00615 {
00616 std::string sourceserv = this->myhost;
00617 if (!this->InboundServerName.empty())
00618 {
00619 sourceserv = this->InboundServerName;
00620 }
00621 return sourceserv;
00622 }
00623
00624 void TreeSocket::OnTimeout()
00625 {
00626 if (this->LinkState == CONNECTING)
00627 {
00628 Utils->Creator->RemoteMessage(NULL, "CONNECT: Connection to \002%s\002 timed out.", myhost.c_str());
00629 Link* MyLink = Utils->FindLink(myhost);
00630 if (MyLink)
00631 Utils->DoFailOver(MyLink);
00632 }
00633 }
00634
00635 void TreeSocket::OnClose()
00636 {
00637
00638 if (this->LinkState != CONNECTED)
00639 return;
00640
00641
00642
00643
00644 std::string quitserver = this->myhost;
00645 if (!this->InboundServerName.empty())
00646 {
00647 quitserver = this->InboundServerName;
00648 }
00649 TreeServer* s = Utils->FindServer(quitserver);
00650 if (s)
00651 {
00652 Squit(s,"Remote host closed the connection");
00653 }
00654
00655 if (!quitserver.empty())
00656 {
00657 Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' failed.",quitserver.c_str());
00658 time_t server_uptime = Instance->Time() - this->age;
00659 if (server_uptime)
00660 Utils->Creator->RemoteMessage(NULL,"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());
00661 }
00662 }
00663
00664 int TreeSocket::OnIncomingConnection(int newsock, char* ip)
00665 {
00666 bool found = false;
00667
00668 found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
00669 if (!found)
00670 {
00671 for (std::vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
00672 {
00673 if (*i == "*" || irc::sockets::MatchCIDR(ip, *i))
00674 {
00675 found = true;
00676 break;
00677 }
00678 }
00679
00680 if (!found)
00681 {
00682 Utils->Creator->RemoteMessage(NULL,"Server connection from %s denied (no link blocks with that IP address)", ip);
00683 Instance->SE->Close(newsock);
00684 return false;
00685 }
00686 }
00687
00688
00689 new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
00690 return true;
00691 }