00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 using namespace std;
00018
00019 #include "inspircd_config.h"
00020 #include "servers.h"
00021 #include "inspircd.h"
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <poll.h>
00025 #include <sys/errno.h>
00026 #include <sys/ioctl.h>
00027 #include <sys/utsname.h>
00028 #include <vector>
00029 #include <string>
00030 #include <deque>
00031 #include <sstream>
00032 #include <map>
00033 #include "inspstring.h"
00034 #include "helperfuncs.h"
00035 #include "connection.h"
00036
00037 extern time_t TIME;
00038 extern int MaxConn;
00039
00040 extern serverrec* me[32];
00041
00042 extern bool has_been_netsplit;
00043
00044 std::deque<std::string> xsums;
00045
00046 serverrec::serverrec()
00047 {
00048 strlcpy(name,"",256);
00049 pingtime = 0;
00050 lastping = TIME;
00051 usercount_i = usercount = opercount = version = 0;
00052 hops_away = 1;
00053 signon = TIME;
00054 jupiter = false;
00055 fd = 0;
00056 sync_soon = false;
00057 strlcpy(nickserv,"",NICKMAX);
00058 connectors.clear();
00059 }
00060
00061
00062 serverrec::~serverrec()
00063 {
00064 }
00065
00066 serverrec::serverrec(char* n, long ver, bool jupe)
00067 {
00068 strlcpy(name,n,256);
00069 lastping = TIME;
00070 usercount_i = usercount = opercount = 0;
00071 version = ver;
00072 hops_away = 1;
00073 signon = TIME;
00074 jupiter = jupe;
00075 fd = 0;
00076 sync_soon = false;
00077 strlcpy(nickserv,"",NICKMAX);
00078 connectors.clear();
00079 }
00080
00081 bool serverrec::CreateListener(char* newhost, int p)
00082 {
00083 sockaddr_in host_address;
00084 int flags;
00085 in_addr addy;
00086 int on = 0;
00087 struct linger linger = { 0 };
00088
00089 this->port = p;
00090
00091 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00092 if (fd <= 0)
00093 {
00094 return false;
00095 }
00096
00097 setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
00098 linger.l_onoff = 1;
00099 linger.l_linger = 1;
00100 setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
00101
00102
00103
00104 int sendbuf = 32768;
00105 int recvbuf = 32768;
00106 setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00107 setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00108
00109 memset((void*)&host_address, 0, sizeof(host_address));
00110
00111 host_address.sin_family = AF_INET;
00112
00113 if (!strcmp(newhost,""))
00114 {
00115 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
00116 }
00117 else
00118 {
00119 inet_aton(newhost,&addy);
00120 host_address.sin_addr = addy;
00121 }
00122
00123 host_address.sin_port = htons(p);
00124
00125 if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
00126 {
00127 return false;
00128 }
00129
00130
00131 flags = fcntl(fd, F_GETFL, 0);
00132 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
00133
00134 this->port = p;
00135
00136 listen(this->fd, MaxConn);
00137
00138 return true;
00139 }
00140
00141
00142 bool serverrec::BeginLink(char* targethost, int newport, char* password, char* servername, int myport)
00143 {
00144 char connect[MAXBUF];
00145
00146 ircd_connector connector;
00147 ircd_connector *cn = this->FindHost(servername);
00148
00149
00150 if (cn)
00151 {
00152 WriteOpers("CONNECT aborted: Server %s already exists",servername);
00153 return false;
00154 }
00155
00156
00157 if (this->fd)
00158 {
00159 if (connector.MakeOutboundConnection(targethost,newport))
00160 {
00161
00162
00163 connector.SetServerName(servername);
00164 snprintf(connect,MAXBUF,"S %s %s %lu %s :%s",getservername().c_str(),password,(unsigned long)myport,GetRevision().c_str(),getserverdesc().c_str());
00165 connector.SetState(STATE_NOAUTH_OUTBOUND);
00166 connector.SetHostAndPort(targethost, newport);
00167 this->connectors.push_back(connector);
00168
00169
00170 return this->SendPacket(connect, servername);
00171 }
00172 else
00173 {
00174 connector.SetState(STATE_DISCONNECTED);
00175 WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00176 }
00177 }
00178 return false;
00179 }
00180
00181
00182 bool serverrec::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername)
00183 {
00184 char connect[MAXBUF];
00185
00186 ircd_connector connector;
00187
00188 WriteOpers("Establishing meshed link to %s:%d",servername,newport);
00189
00190 if (this->fd)
00191 {
00192 if (connector.MakeOutboundConnection(targethost,newport))
00193 {
00194
00195
00196 connector.SetServerName(servername);
00197 snprintf(connect,MAXBUF,"- %lu %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
00198 connector.SetState(STATE_NOAUTH_OUTBOUND);
00199 connector.SetHostAndPort(targethost, newport);
00200 this->connectors.push_back(connector);
00201 return this->SendPacket(connect, servername);
00202 }
00203 else
00204 {
00205 connector.SetState(STATE_DISCONNECTED);
00206 WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00207 }
00208 }
00209 return false;
00210 }
00211
00212 bool serverrec::AddIncoming(int newfd, char* targethost, int sourceport)
00213 {
00214 ircd_connector connector;
00215
00216
00217
00218 connector.SetServerName(targethost);
00219 connector.SetDescriptor(newfd);
00220 connector.SetState(STATE_NOAUTH_INBOUND);
00221 int flags = fcntl(newfd, F_GETFL, 0);
00222 fcntl(newfd, F_SETFL, flags | O_NONBLOCK);
00223 int sendbuf = 32768;
00224 int recvbuf = 32768;
00225 setsockopt(newfd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00226 setsockopt(newfd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00227 connector.SetHostAndPort(targethost, sourceport);
00228 connector.SetState(STATE_NOAUTH_INBOUND);
00229 log(DEBUG,"serverrec::AddIncoming() Added connection: %s:%d",targethost,sourceport);
00230 this->connectors.push_back(connector);
00231 return true;
00232 }
00233
00234 void serverrec::TerminateLink(char* targethost)
00235 {
00236
00237
00238
00239 }
00240
00241
00242 ircd_connector* serverrec::FindHost(std::string findhost)
00243 {
00244 for (int i = 0; i < this->connectors.size(); i++)
00245 {
00246 if (this->connectors[i].GetServerName() == findhost)
00247 {
00248 return &this->connectors[i];
00249 }
00250 }
00251 return NULL;
00252 }
00253
00254
00255
00256 bool IsRoutable(std::string servername)
00257 {
00258 for (int x = 0; x < 32; x++) if (me[x])
00259 {
00260 ircd_connector* cn = me[x]->FindHost(servername.c_str());
00261 if (cn)
00262 {
00263 if (cn->GetState() == STATE_DISCONNECTED)
00264 {
00265 for (int k = 0; k < me[x]->connectors.size(); k++)
00266 {
00267 for (int m = 0; m < me[x]->connectors[k].routes.size(); m++)
00268 {
00269 if (!strcasecmp(me[x]->connectors[k].routes[m].c_str(),servername.c_str()))
00270 {
00271 return true;
00272 }
00273 }
00274 }
00275 return false;
00276 }
00277 else return true;
00278 }
00279 }
00280 return false;
00281 }
00282
00283
00284 void serverrec::FlushWriteBuffers()
00285 {
00286 for (int i = 0; i < this->connectors.size(); i++)
00287 {
00288
00289 if ((this->connectors[i].GetState() == STATE_NOAUTH_OUTBOUND) && (TIME > this->connectors[i].age+30))
00290 {
00291
00292 WriteOpers("*** Connection to %s timed out",this->connectors[i].GetServerName().c_str());
00293 DoSplit(this->connectors[i].GetServerName().c_str());
00294 return;
00295 }
00296 else if ((this->connectors[i].GetState() == STATE_NOAUTH_INBOUND) && (TIME > this->connectors[i].age+30))
00297 {
00298 WriteOpers("*** Connection from %s timed out",this->connectors[i].GetServerName().c_str());
00299 DoSplit(this->connectors[i].GetServerName().c_str());
00300 return;
00301 }
00302 else if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00303 {
00304 if (!this->connectors[i].CheckPing())
00305 {
00306 WriteOpers("*** Lost single connection to %s: Ping timeout",this->connectors[i].GetServerName().c_str());
00307 this->connectors[i].CloseConnection();
00308 this->connectors[i].SetState(STATE_DISCONNECTED);
00309 if (!IsRoutable(this->connectors[i].GetServerName()))
00310 {
00311 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00312 DoSplit(this->connectors[i].GetServerName().c_str());
00313 }
00314 has_been_netsplit = true;
00315 }
00316 }
00317 if (this->connectors[i].HasBufferedOutput())
00318 {
00319 if (!this->connectors[i].FlushWriteBuf())
00320 {
00321
00322 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",this->connectors[i].GetServerName().c_str(),this->connectors[i].GetWriteError().c_str());
00323 this->connectors[i].CloseConnection();
00324 this->connectors[i].SetState(STATE_DISCONNECTED);
00325 if (!IsRoutable(this->connectors[i].GetServerName()))
00326 {
00327 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00328 DoSplit(this->connectors[i].GetServerName().c_str());
00329 }
00330 has_been_netsplit = true;
00331 }
00332 }
00333 }
00334 }
00335
00336 bool serverrec::SendPacket(char *message, const char* sendhost)
00337 {
00338 if ((!message) || (!sendhost))
00339 return true;
00340
00341 ircd_connector* cn = this->FindHost(sendhost);
00342
00343 if (!strchr(message,'\n'))
00344 {
00345 strlcat(message,"\n",MAXBUF);
00346 }
00347
00348 if (cn)
00349 {
00350 log(DEBUG,"main: serverrec::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
00351
00352 if (cn->GetState() == STATE_DISCONNECTED)
00353 {
00354
00355 if (strncmp(message,"R ",2))
00356 {
00357 log(DEBUG,"Not a double reroute");
00358
00359 for (int k = 0; k < this->connectors.size(); k++)
00360 {
00361 log(DEBUG,"Check connector %d: %s",k,this->connectors[k].GetServerName().c_str());
00362
00363 for (int m = 0; m < this->connectors[k].routes.size(); m++)
00364 {
00365 if (!strcasecmp(this->connectors[k].routes[m].c_str(),sendhost))
00366 {
00367 log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
00368 char buffer[MAXBUF];
00369 snprintf(buffer,MAXBUF,"R %s %s",sendhost,message);
00370 this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
00371 return true;
00372 }
00373 }
00374 }
00375 }
00376 char buffer[MAXBUF];
00377 snprintf(buffer,MAXBUF,"& %s",sendhost);
00378 WriteOpers("*** All connections to %s lost.",sendhost);
00379 NetSendToAllExcept(sendhost,buffer);
00380 DoSplit(sendhost);
00381 return false;
00382 }
00383
00384
00385 if (!cn->AddWriteBuf(message))
00386 {
00387
00388 log(DEBUG,"cn->AddWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00389 log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00390 cn->CloseConnection();
00391 cn->SetState(STATE_DISCONNECTED);
00392 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00393
00394 return this->SendPacket(message,sendhost);
00395 }
00396 if (!cn->FlushWriteBuf())
00397 {
00398
00399 log(DEBUG,"cn->FlushWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00400 log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00401 cn->CloseConnection();
00402 cn->SetState(STATE_DISCONNECTED);
00403 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00404
00405 return this->SendPacket(message,sendhost);
00406 }
00407 return true;
00408 }
00409 }
00410
00411 bool already_have_sum(std::string sum)
00412 {
00413 for (int i = 0; i < xsums.size(); i++)
00414 {
00415 if (xsums[i] == sum)
00416 {
00417 return true;
00418 }
00419 }
00420 if (xsums.size() >= 128)
00421 {
00422 xsums.pop_front();
00423 }
00424 xsums.push_back(sum);
00425 return false;
00426 }
00427
00428
00429
00430
00431 bool serverrec::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums)
00432 {
00433 char data[65536];
00434 memset(data, 0, 65536);
00435 for (int i = 0; i < this->connectors.size(); i++)
00436 {
00437 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00438 {
00439
00440 int rcvsize = 0;
00441
00442
00443
00444 pollfd polls;
00445 polls.fd = this->connectors[i].GetDescriptor();
00446 polls.events = POLLIN;
00447 int ret = poll(&polls,1,1);
00448 if (ret <= 0) continue;
00449
00450 rcvsize = recv(this->connectors[i].GetDescriptor(),data,65000,0);
00451 data[rcvsize] = '\0';
00452 if (rcvsize == -1)
00453 {
00454 if (errno != EAGAIN)
00455 {
00456 log(DEBUG,"recv() failed for serverrec::RecvPacket(): %s",strerror(errno));
00457 log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
00458 this->connectors[i].CloseConnection();
00459 this->connectors[i].SetState(STATE_DISCONNECTED);
00460 if (!IsRoutable(this->connectors[i].GetServerName()))
00461 {
00462 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00463 DoSplit(this->connectors[i].GetServerName().c_str());
00464 }
00465 has_been_netsplit = true;
00466 }
00467 }
00468 int pushed = 0;
00469 if (rcvsize > 0)
00470 {
00471 if (!this->connectors[i].AddBuffer(data))
00472 {
00473 WriteOpers("*** Read buffer for %s exceeds maximum, closing connection!",this->connectors[i].GetServerName().c_str());
00474 this->connectors[i].CloseConnection();
00475 this->connectors[i].SetState(STATE_DISCONNECTED);
00476 if (!IsRoutable(this->connectors[i].GetServerName()))
00477 {
00478 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00479 DoSplit(this->connectors[i].GetServerName().c_str());
00480 }
00481 has_been_netsplit = true;
00482 }
00483 if (this->connectors[i].BufferIsComplete())
00484 {
00485 this->connectors[i].ResetPing();
00486 while (this->connectors[i].BufferIsComplete())
00487 {
00488 std::string text = this->connectors[i].GetBuffer();
00489 if (text != "")
00490 {
00491 if ((text[0] == ':') && (text.find(" ") != std::string::npos))
00492 {
00493 std::string orig = text;
00494 log(DEBUG,"Original: %s",text.c_str());
00495 std::string sum = text.substr(1,text.find(" ")-1);
00496 text = text.substr(text.find(" ")+1,text.length());
00497 std::string possible_token = text.substr(1,text.find(" ")-1);
00498 if (possible_token.length() > 1)
00499 {
00500 sums.push_back("*");
00501 text = orig;
00502 log(DEBUG,"Non-mesh, non-tokenized string passed up the chain");
00503 }
00504 else
00505 {
00506 log(DEBUG,"Packet sum: '%s'",sum.c_str());
00507 if ((already_have_sum(sum)) && (sum != "*"))
00508 {
00509
00510 continue;
00511 }
00512 sums.push_back(sum.c_str());
00513 }
00514 }
00515 else sums.push_back("*");
00516 messages.push_back(text.c_str());
00517 strlcpy(recvhost,this->connectors[i].GetServerName().c_str(),160);
00518 log(DEBUG,"serverrec::RecvPacket() %d:%s->%s",pushed++,recvhost,text.c_str());
00519 }
00520 }
00521 return true;
00522 }
00523 }
00524 }
00525 }
00526
00527 return false;
00528 }
00529