]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/connection.cpp
Security audit based on RATS output
[user/henk/code/inspircd.git] / src / connection.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include <connection.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/errno.h>
21 #include <sys/ioctl.h>
22 #include <sys/utsname.h>
23 #include <vector>
24 #include <string>
25 #include <deque>
26 #include "inspircd.h"
27 #include "modules.h"
28
29 using namespace std;
30
31
32 extern std::vector<Module*> modules;
33 extern std::vector<ircd_module*> factory;
34
35 extern int MODCOUNT;
36
37
38
39 connection::connection()
40 {
41         fd = 0;
42 }
43
44
45 bool connection::CreateListener(char* host, int p)
46 {
47         sockaddr_in host_address;
48         int flags;
49         in_addr addy;
50         int on = 0;
51         struct linger linger = { 0 };
52         
53         this->port = p;
54         
55         fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
56         if (fd <= 0)
57         {
58                 return false;
59         }
60
61         setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
62         linger.l_onoff = 1;
63         linger.l_linger = 0;
64         setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
65         
66         // attempt to increase socket sendq and recvq as high as its possible
67         // to get them on linux.
68         int sendbuf = 32768;
69         int recvbuf = 32768;
70         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
71         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
72
73         memset((void*)&host_address, 0, sizeof(host_address));
74
75         host_address.sin_family = AF_INET;
76
77         if (!strcmp(host,""))
78         {
79                 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
80         }
81         else
82         {
83                 inet_aton(host,&addy);
84                 host_address.sin_addr = addy;
85         }
86
87         host_address.sin_port = htons(p);
88
89         if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
90         {
91                 return false;
92         }
93
94         // make the socket non-blocking
95         flags = fcntl(fd, F_GETFL, 0);
96         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
97
98         this->port = p;
99
100         listen(this->fd,5);
101
102         return true;
103 }
104
105 char* ircd_connector::GetServerIP()
106 {
107         return this->host;
108 }
109
110 int ircd_connector::GetServerPort()
111 {
112         return this->port;
113 }
114
115 bool ircd_connector::SetHostAndPort(char* host, int port)
116 {
117         strncpy(this->host,host,160);
118         this->port = port;
119         return true;
120 }
121
122 bool ircd_connector::SetHostAddress(char* host, int port)
123 {
124         strncpy(this->host,host,160);
125         this->port = port;
126         memset((void*)&addr, 0, sizeof(addr));
127         addr.sin_family = AF_INET;
128         inet_aton(host,&addr.sin_addr);
129         addr.sin_port = htons(port);
130         return true;
131 }
132
133 void ircd_connector::SetServerPort(int p)
134 {
135         this->port = p;
136 }
137
138 bool ircd_connector::MakeOutboundConnection(char* host, int port)
139 {
140         log(DEBUG,"MakeOutboundConnection: Original param: %s",host);
141         hostent* hoste = gethostbyname(host);
142         if (!hoste)
143         {
144                 log(DEBUG,"MakeOutboundConnection: gethostbyname was NULL, setting %s",host);
145                 this->SetHostAddress(host,port);
146                 SetHostAndPort(host,port);
147         }
148         else
149         {
150                 struct in_addr* ia = (in_addr*)hoste->h_addr;
151                 log(DEBUG,"MakeOutboundConnection: gethostbyname was valid, setting %s",inet_ntoa(*ia));
152                 this->SetHostAddress(inet_ntoa(*ia),port);
153                 SetHostAndPort(inet_ntoa(*ia),port);
154         }
155
156         this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
157         if (this->fd >= 0)
158         {
159                 if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)))
160                 {
161                         WriteOpers("connect() failed for %s",host);
162                         RemoveServer(this->servername.c_str());
163                         return false;
164                 }
165                 int flags = fcntl(this->fd, F_GETFL, 0);
166                 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
167                 int sendbuf = 32768;
168                 int recvbuf = 32768;
169                 setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
170                 setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
171                 return true;
172         }
173         else
174         {
175                 WriteOpers("socket() failed!");
176                 RemoveServer(this->servername.c_str());
177         }
178
179         return false;
180 }
181
182
183 bool connection::BeginLink(char* targethost, int port, char* password, char* servername, int myport)
184 {
185         char connect[MAXBUF];
186         
187         ircd_connector connector;
188         ircd_connector *cn = this->FindHost(servername);
189
190
191         if (cn)
192         {
193                 WriteOpers("CONNECT aborted: Server %s already exists",servername);
194                 return false;
195         }
196
197         
198         if (this->fd)
199         {
200                 if (connector.MakeOutboundConnection(targethost,port))
201                 {
202                         // targethost has been turned into an ip...
203                         // we dont want this as the server name.
204                         connector.SetServerName(servername);
205                         snprintf(connect,MAXBUF,"S %s %s %d %d :%s",getservername().c_str(),password,myport,GetRevision(),getserverdesc().c_str());
206                         connector.SetState(STATE_NOAUTH_OUTBOUND);
207                         connector.SetHostAndPort(targethost, port);
208                         this->connectors.push_back(connector);
209                         return this->SendPacket(connect, servername);
210                 }
211                 else
212                 {
213                         connector.SetState(STATE_DISCONNECTED);
214                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
215                 }
216         }
217         return false;
218 }
219
220 bool connection::MeshCookie(char* targethost, int port, long cookie, char* servername)
221 {
222         char connect[MAXBUF];
223         
224         ircd_connector connector;
225         
226         WriteOpers("Establishing meshed link to %s:%d",servername,port);
227
228         if (this->fd)
229         {
230                 if (connector.MakeOutboundConnection(targethost,port))
231                 {
232                         // targethost has been turned into an ip...
233                         // we dont want this as the server name.
234                         connector.SetServerName(servername);
235                         snprintf(connect,MAXBUF,"- %d %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
236                         connector.SetState(STATE_NOAUTH_OUTBOUND);
237                         connector.SetHostAndPort(targethost, port);
238                         connector.SetState(STATE_CONNECTED);
239                         this->connectors.push_back(connector);
240                         return this->SendPacket(connect, servername);
241                 }
242                 else
243                 {
244                         connector.SetState(STATE_DISCONNECTED);
245                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
246                 }
247         }
248         return false;
249 }
250
251 bool connection::AddIncoming(int fd, char* targethost, int sourceport)
252 {
253         char connect[MAXBUF];
254         
255         ircd_connector connector;
256         
257         // targethost has been turned into an ip...
258         // we dont want this as the server name.
259         connector.SetServerName(targethost);
260         connector.SetDescriptor(fd);
261         connector.SetState(STATE_NOAUTH_INBOUND);
262         int flags = fcntl(fd, F_GETFL, 0);
263         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
264         int sendbuf = 32768;
265         int recvbuf = 32768;
266         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
267         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
268         connector.SetHostAndPort(targethost, sourceport);
269         connector.SetState(STATE_NOAUTH_INBOUND);
270         log(DEBUG,"connection::AddIncoming() Added connection: %s:%d",targethost,sourceport);
271         this->connectors.push_back(connector);
272         return true;
273 }
274
275 void connection::TerminateLink(char* targethost)
276 {
277         // this locates the targethost in the connection::connectors vector of the class,
278         // and terminates it by sending it an SQUIT token and closing its descriptor.
279         // TerminateLink with a null string causes a terminate of ALL links
280 }
281
282
283 // Returns a pointer to the connector for 'host'
284 ircd_connector* connection::FindHost(std::string host)
285 {
286         for (int i = 0; i < this->connectors.size(); i++)
287         {
288                 if (this->connectors[i].GetServerName() == host)
289                 {
290                         return &this->connectors[i];
291                 }
292         }
293         return NULL;
294 }
295
296 std::string ircd_connector::GetServerName()
297 {
298         return this->servername;
299 }
300
301 std::string ircd_connector::GetDescription()
302 {
303         return this->description;
304 }
305
306 void ircd_connector::SetServerName(std::string serv)
307 {
308         this->servername = serv;
309 }
310
311 void ircd_connector::SetDescription(std::string desc)
312 {
313         this->description = desc;
314 }
315
316
317 int ircd_connector::GetDescriptor()
318 {
319         return this->fd;
320 }
321
322 int ircd_connector::GetState()
323 {
324         return this->state;
325 }
326
327
328 void ircd_connector::SetState(int state)
329 {
330         this->state = state;
331         if (state == STATE_DISCONNECTED)
332         {
333                 NetSendMyRoutingTable();
334         }
335 }
336
337 void ircd_connector::CloseConnection()
338 {
339         int flags = fcntl(this->fd, F_GETFL, 0);
340         fcntl(this->fd, F_SETFL, flags ^ O_NONBLOCK);
341         close(this->fd);
342         flags = fcntl(this->fd, F_GETFL, 0);
343         fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
344 }
345
346 void ircd_connector::SetDescriptor(int fd)
347 {
348         this->fd = fd;
349 }
350
351 bool connection::SendPacket(char *message, const char* host)
352 {
353         if ((!message) || (!host))
354                 return true;
355
356         ircd_connector* cn = this->FindHost(host);
357         
358         if (!strchr(message,'\n'))
359         {
360                 strlcat(message,"\n",MAXBUF);
361         }
362
363         if (cn)
364         {
365                 log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
366                 
367                 if (cn->GetState() == STATE_DISCONNECTED)
368                 {
369                         log(DEBUG,"Main route to %s is down, seeking alternative",host);
370                         // fix: can only route one hop to avoid a loop
371                         if (strlcat(message,"R ",2))
372                         {
373                                 // this route is down, we must re-route the packet through an available point in the mesh.
374                                 for (int k = 0; k < this->connectors.size(); k++)
375                                 {
376                                         // search for another point in the mesh which can 'reach' where we want to go
377                                         for (int m = 0; m < this->connectors[k].routes.size(); m++)
378                                         {
379                                                 if (!strcasecmp(this->connectors[k].routes[m].c_str(),host))
380                                                 {
381                                                         log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
382                                                         char buffer[MAXBUF];
383                                                         snprintf(buffer,MAXBUF,"R %s %s",host,message);
384                                                         this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
385                                                         return true;
386                                                 }
387                                         }
388                                 }
389                         }
390                         char buffer[MAXBUF];
391                         snprintf(buffer,MAXBUF,"& %s",host);
392                         NetSendToAllExcept(host,buffer);
393                         log(DEBUG,"There are no routes to %s, we're gonna boot the server off!",host);
394                         DoSplit(host);
395                         return false;
396                 }
397
398                 // returns false if the packet could not be sent (e.g. target host down)
399                 if (send(cn->GetDescriptor(),message,strlen(message),0)<0)
400                 {
401                         log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno));
402                         log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
403                         cn->CloseConnection();
404                         cn->SetState(STATE_DISCONNECTED);
405                         // retry the packet along a new route so either arrival OR failure are gauranteed (bugfix)
406                         return this->SendPacket(message,host);
407                 }
408                 return true;
409         }
410 }
411
412 // receives a packet from any where there is data waiting, first come, first served
413 // fills the message and host values with the host where the data came from.
414
415 bool connection::RecvPacket(std::deque<std::string> &messages, char* host)
416 {
417         char data[32767];
418         memset(data, 0, 32767);
419         for (int i = 0; i < this->connectors.size(); i++)
420         {
421                 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
422                 {
423                         // returns false if the packet could not be sent (e.g. target host down)
424                         int rcvsize = 0;
425                         rcvsize = recv(this->connectors[i].GetDescriptor(),data,32767,0);
426                         if (rcvsize == -1)
427                         {
428                                 if (errno != EAGAIN)
429                                 {
430                                         log(DEBUG,"recv() failed for Connection::RecvPacket(): %s",strerror(errno));
431                                         log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
432                                         this->connectors[i].CloseConnection();
433                                         this->connectors[i].SetState(STATE_DISCONNECTED);
434                                 }
435                         }
436                         if (rcvsize > 0)
437                         {
438                                 char* l = strtok(data,"\n");
439                                 while (l)
440                                 {
441                                         char sanitized[32767];
442                                         memset(sanitized, 0, 32767);
443                                         int ptt = 0;
444                                         for (int pt = 0; pt < strlen(l); pt++)
445                                         {
446                                                 if (l[pt] != '\r')
447                                                 {
448                                                         sanitized[ptt++] = l[pt];
449                                                 }
450                                         }
451                                         sanitized[ptt] = '\0';
452                                         if (strlen(sanitized))
453                                         {
454                                                 messages.push_back(sanitized);
455                                                 strlcpy(host,this->connectors[i].GetServerName().c_str(),160);
456                                                 log(DEBUG,"main: Connection::RecvPacket() got '%s' from %s",sanitized,host);
457                                                 
458                                         }
459                                         l = strtok(NULL,"\n");
460                                 }
461                                 return true;
462                         }
463                 }
464         }
465         // nothing new yet -- message and host will be undefined
466         return false;
467 }
468
469 long connection::GenKey()
470 {
471         srand(time(NULL));
472         return (random()*time(NULL));
473 }
474