1 /********************************************************************************
2 * Nepenthes
3 * - finest collection -
4 *
5 *
6 *
7 * Copyright (C) 2005 Paul Baecher & Markus Koetter & Georg Wicherski
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 *
24 * contact nepenthesdev@users.sourceforge.net
25 *
26 *******************************************************************************/
27
28 /* $Id: SocketManager.cpp 1264 2007-05-12 10:29:49Z common $ */
29
30 #ifdef WIN32
31 #include <winsock2.h>
32 #include <ws2tcpip.h>
33 #include <iostream.h>
34 #else
35
36 #include <poll.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <cstdlib>
40 #include <cerrno>
41 #include <netinet/in.h>
42 #include <net/if.h>
43 #include <arpa/inet.h>
44 #include <sys/ioctl.h>
45 #endif
46
47
48 #include <string>
49
50 #include "SocketManager.hpp"
51 #include "Socket.hpp"
52 #include "TCPSocket.hpp"
53 #include "FILESocket.hpp"
54 #include "UDPSocket.hpp"
55 #include "POLLSocket.hpp"
56
57 #include "Nepenthes.hpp"
58
59 #include "LogManager.hpp"
60
61 #include "Config.hpp"
62
63 #ifdef __linux__ // bind to interface on linux
64 #include <net/if.h>
65 #include <sys/types.h>
66 #include <sys/ioctl.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #endif // end bind to if
71
72 using namespace nepenthes;
73 using namespace std;
74
75 #ifdef STDTAGS
76 #undef STDTAGS
77 #endif
78 #define STDTAGS l_net | l_mgr
79
80 /**
81 * SocketManager constructor
82 *
83 * @param nepenthes the nepenthes
84 */
SocketManager(Nepenthes * nepenthes)85 SocketManager::SocketManager(Nepenthes *nepenthes)
86 {
87 m_Nepenthes = nepenthes;
88 m_UseRawSockets = false;
89 m_BindAddress = INADDR_ANY;
90 }
91
92 /**
93 * SocketManager destructor
94 */
~SocketManager()95 SocketManager::~SocketManager()
96 {
97 Exit();
98 }
99
100 #define PROC_NET_DEV "/proc/net/dev"
101
102 /**
103 * check config values
104 *
105 * @return true on success,
106 * else false
107 */
Init()108 bool SocketManager::Init()
109 {
110 try {
111 string bindAddressString = m_Nepenthes->getConfig()->getValString("nepenthes.socketmanager.bind_address");
112
113 #ifdef __linux__
114 if(bindAddressString.substr(0, 3) == string("if:"))
115 {
116 const char * interfaceName = bindAddressString.substr(3).c_str();
117 int ifaceSocket = socket(AF_INET, SOCK_STREAM, 0);
118 struct ifreq interfaceRequest;
119 struct sockaddr_in addrInterface;
120
121 strncpy(interfaceRequest.ifr_name, interfaceName, IFNAMSIZ - 1);
122
123 if(ifaceSocket < 0 || ioctl(ifaceSocket, SIOCGIFADDR, &interfaceRequest) < 0)
124 {
125 logCrit("Failed to obtain address for interface %s: %s!\n", interfaceName, strerror(errno));
126 } else
127 {
128 memcpy(&addrInterface, &(interfaceRequest.ifr_addr), sizeof(addrInterface));
129 logInfo("Obtained address of interface %s: %s\n", interfaceName, inet_ntoa(addrInterface.sin_addr));
130 m_BindAddress = addrInterface.sin_addr.s_addr;
131
132 close(ifaceSocket);
133 }
134
135 } else
136 #endif
137 {
138 m_BindAddress = inet_addr(bindAddressString.c_str());
139 }
140
141 if (m_BindAddress != INADDR_ANY)
142 {
143 logInfo("Using %s as bind_address for all connections\n", inet_ntoa(*(struct in_addr *)&m_BindAddress));
144 }
145 } catch ( ... ) {
146 logCrit("Could not find nepenthes.socketmanager.bind_address in config file, assuming no\n");
147 }
148
149 return true;
150 }
151
Exit()152 bool SocketManager::Exit()
153 {
154 while(m_Sockets.size() > 0)
155 {
156 if ( !(m_Sockets.front()->getType() & ST_NODEL) )
157 delete m_Sockets.front();
158 m_Sockets.pop_front();
159 }
160
161 return true;
162 }
163
164 /**
165 * list all used Socket 's
166 */
doList()167 void SocketManager::doList()
168 {
169 list <Socket *>::iterator socket;
170 logSpam("=--- %-69s ---=\n","SocketManager");
171 int32_t i=0;
172 for(socket = m_Sockets.begin();socket != m_Sockets.end();socket++,i++)
173 {
174 logSpam(" %i) %-8s \n",i,(*socket)->getDescription().c_str());
175 }
176 logSpam("=--- %2i %-66s ---=\n\n",i, "Sockets open");
177 }
178
179 /**
180 * poll the sockets
181 *
182 * @param polltimeout
183 * the polltimeout
184 *
185 * @return returns true
186 */
doLoop(uint32_t polltimeout)187 bool SocketManager::doLoop(uint32_t polltimeout)
188 {
189 list <Socket *>::iterator itSocket;
190
191 // check socket timeouts and remove dead sockets
192 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(); itSocket++)
193 {
194 (*itSocket)->checkTimeout();
195 if ((*itSocket)->getStatus() == SS_TIMEOUT )
196 {
197 logDebug("Deleting Socket %s due to timeout \n",(*itSocket)->getDescription().c_str());
198 Socket *delsocket = *itSocket;
199 m_Sockets.erase(itSocket);
200 delete delsocket;
201
202 itSocket = m_Sockets.begin(); // FIXME ?
203 if(m_Sockets.size() == 0)
204 return false;
205
206
207 }
208
209 if ( (*itSocket)->getStatus() == SS_CLOSED )
210 {
211 logDebug("Deleting %s due to closed connection \n",(*itSocket)->getDescription().c_str());
212 Socket *delsocket = *itSocket;
213 m_Sockets.erase(itSocket);
214 delete delsocket;
215 itSocket = m_Sockets.begin(); // FIXME ?
216 }
217 }
218
219 pollfd *polls = (pollfd *) malloc( (m_Sockets.size())* sizeof(pollfd));
220 memset(polls,0,(m_Sockets.size())* sizeof(pollfd));
221 int32_t i=0;
222 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(); itSocket++)
223 {
224 int32_t iError = 0;
225 int32_t iSize = sizeof(iError);
226 if((*itSocket)->getType() & ST_FILE)
227 {
228 (*itSocket)->setPolled();
229 }else
230 if ((*itSocket)->getsockOpt(SOL_SOCKET, SO_ERROR, &iError,(socklen_t *) &iSize) != 0 )
231 {
232 // socket is dead
233 logSpam("Socket %i %s is Dead\n",(*itSocket)->getSocket(), (*itSocket)->getDescription().c_str());
234 (*itSocket)->unsetPolled();
235
236 } else
237 {
238 switch (iError)
239 {
240 case 0: // der socket is soweit okay
241 case EISCONN:
242 if ((*itSocket)->getStatus() == SS_CONNECTING)
243 {
244 (*itSocket)->setStatus(SS_CONNECTED);
245 }
246 (*itSocket)->setPolled(); // der socket ist am start
247 break;
248
249 case EINPROGRESS: // der socket versuchts
250 (*itSocket)->unsetPolled();
251 break;
252
253
254 default:
255 (*itSocket)->unsetPolled(); // der is defekt
256 }
257 }
258 }
259
260 i=0;
261 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(); itSocket++)
262 {
263 polls[i].events = 0;
264 if ((*itSocket)->isPolled() == true )
265 {
266 polls[i].fd = (*itSocket)->getSocket();
267 polls[i].events = POLLIN;
268
269 if ((*itSocket)->wantSend() == true)
270 {
271 polls[i].events |= POLLOUT;
272 }
273 i++;
274 }
275 }
276
277 int32_t socketcounter, socketmax;
278 socketcounter=0;
279 socketmax = m_Sockets.size();
280
281 int32_t iPollRet = poll(polls,i,50);
282
283 if (iPollRet != 0)
284 {
285 // read sockets
286 i=0;
287 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(), socketcounter < socketmax ; itSocket++, socketcounter++)
288 {
289 if ( (*itSocket)->isPolled() == true )
290 {
291 if (
292 ( (*itSocket)->isAccept() || (*itSocket)->isConnect() ) ||
293 ( (*itSocket)->isBind() && (*itSocket)->getType() & ST_UDP) // bound udp sockets dont accept, they recvfrom
294 )
295 {
296 if ( iPollRet == 0 )
297 continue;
298
299 if ( polls[i].revents & POLLIN && polls[i].events & POLLIN )
300 {
301 (*itSocket)->doRecv();
302 iPollRet--;
303 }
304 }
305 i++;
306 }
307 }
308
309 // write sockets
310 i=0;
311 socketcounter=0;
312 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(), socketcounter < socketmax; itSocket++, socketcounter++)
313 {
314 if ( (*itSocket)->isPolled() == true )
315 {
316 if (
317 ( (*itSocket)->getStatus() == SS_CONNECTED || (*itSocket)->getStatus() == SS_CLEANQUIT ) &&
318 (
319 (*itSocket)->isAccept() ||
320 (*itSocket)->isConnect() ||
321 (
322 (*itSocket)->isBind() && (*itSocket)->getType() & ST_UDP
323 )
324 )
325 )
326 {
327 if ( polls[i].revents & POLLOUT && polls[i].events & POLLOUT )
328 {
329 (*itSocket)->doSend();
330 iPollRet--;
331 }
332 }
333 i++;
334 }
335 }
336
337
338 // accept new, non udp clients as udp does not accept()
339 i=0;
340 socketcounter=0;
341 for (itSocket = m_Sockets.begin();itSocket != m_Sockets.end(), socketcounter < socketmax; itSocket++, socketcounter++)
342 {
343
344
345 if ( (*itSocket)->isPolled() == true )
346 {
347 if ( (*itSocket)->isBind() )
348 {
349 if ( iPollRet == 0 )
350 continue;
351
352 if ( !((*itSocket)->getType() & ST_UDP) ) // bound udp sockets dont accept, they recvfrom
353 {
354 if ( polls[i].revents & POLLIN && polls[i].events & POLLIN )
355 {
356 logDebug("%s could Accept a Connection\n",(*itSocket)->getDescription().c_str());
357 Socket * socket = (*itSocket)->acceptConnection();
358 if ( socket == NULL )
359 {
360 logCrit("Accept returned NULL ptr \n");
361 } else
362 {
363 m_Sockets.push_back(socket);
364 logDebug("Accepted Connection %s \n%i Sockets in list\n",socket->getDescription().c_str(), m_Sockets.size());
365 }
366 iPollRet--;
367 }
368 }
369 }
370 i++;
371 }
372 }
373 }
374 free(polls);
375 return true;
376 }
377
378
379 /**
380 * bind a given port to a given local ip address
381 *
382 * @param localhost the local ip address to bind to
383 * @param port the port to bind
384 * @param bindtimeout
385 * the timeout for the bind socket in seconds
386 * @param accepttimeout
387 * the timeout for the accepted connections sockets in seconds
388 *
389 * @return returns the bound Socket if binding was successfull, else NULL
390 */
bindTCPSocket(uint32_t localhost,uint16_t port,time_t bindtimeout,time_t accepttimeout)391 Socket *SocketManager::bindTCPSocket(uint32_t localhost, uint16_t port,time_t bindtimeout,time_t accepttimeout)
392 {
393 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
394 {
395 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
396 localhost = m_BindAddress;
397 }
398
399 logSpam("bindTCPSocket %li %i %li %li\n",localhost,port,bindtimeout,accepttimeout);
400 TCPSocket *sock = NULL;
401
402 list <Socket *>::iterator socket;
403 for(socket = m_Sockets.begin();socket != m_Sockets.end(); socket++)
404 {
405 if((*socket)->getType() & ST_TCP && (*socket)->isBind() && (*socket)->getLocalPort() == (int32_t)port )
406 {
407 return (*socket);
408 }
409 }
410
411 if(sock == NULL)
412 {
413 // This can bee seen as ambiguous - at least on FreeBSD. We want this:
414 // TCPSocket(Nepenthes *nepenthes, uint32_t localaddress, int32_t port, time_t bindtimeout, time_t accepttimeout)
415 if ((sock = new TCPSocket(getNepenthes(), (uint32_t)localhost, (uint16_t)port, (time_t) bindtimeout, (time_t) accepttimeout)) == NULL )
416 {
417 logCrit("ERROR Binding %s:%i failed\n","",port);
418 return NULL;
419 }else
420 {
421 if(sock->Init() == false)
422 {
423 logCrit("ERROR Binding %s:%i failed\n","",port);
424 delete sock;
425 return NULL;
426 }else
427 {
428 m_Sockets.push_back(sock);
429 return sock;
430 }
431 }
432 }
433 return sock;
434 }
435
436
bindTCPSocket(uint32_t localhost,uint16_t port,time_t bindtimeout,time_t accepttimeout,DialogueFactory * dialoguefactory)437 Socket *SocketManager::bindTCPSocket(uint32_t localhost, uint16_t port,time_t bindtimeout,time_t accepttimeout, DialogueFactory *dialoguefactory)
438 {
439 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
440 {
441 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
442 localhost = m_BindAddress;
443 }
444
445
446 logSpam("bindTCPSocket %li %i %li %li %lx\n",localhost,port,bindtimeout,accepttimeout, dialoguefactory);
447 TCPSocket *sock = NULL;
448
449 list <Socket *>::iterator socket;
450 for(socket = m_Sockets.begin();socket != m_Sockets.end(); socket++)
451 {
452 if((*socket)->getType() & ST_TCP && (*socket)->isBind() && (*socket)->getLocalPort() == (int32_t)port )
453 {
454 (*socket)->addDialogueFactory(dialoguefactory);
455 return (*socket);
456 }
457 }
458
459 if(sock == NULL)
460 {
461 if ((sock = new TCPSocket(getNepenthes(), localhost, (int32_t) port, bindtimeout, accepttimeout)) == NULL )
462 {
463 logCrit("ERROR Binding %s:%i failed\n","",port);
464
465 return NULL;
466 }else
467 {
468 if(sock->Init() == false)
469 {
470 logCrit("ERROR Binding %s:%i failed\n","",port);
471 delete sock;
472 return NULL;
473 }else
474 {
475 m_Sockets.push_back(sock);
476 sock->addDialogueFactory(dialoguefactory);
477 return sock;
478 }
479 }
480 }
481 return NULL;
482 }
483
484
bindUDPSocket(uint32_t localhost,uint16_t port,time_t bindtimeout,time_t accepttimeout,DialogueFactory * dialoguefactory)485 Socket *SocketManager::bindUDPSocket(uint32_t localhost, uint16_t port,time_t bindtimeout,time_t accepttimeout, DialogueFactory *dialoguefactory)
486 {
487 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
488 {
489 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
490 localhost = m_BindAddress;
491 }
492
493
494 logSpam("bindUDPSocket %li %i %li %li\n",localhost,port,bindtimeout,accepttimeout);
495 UDPSocket *sock = NULL;
496
497 list <Socket *>::iterator socket;
498 for(socket = m_Sockets.begin();socket != m_Sockets.end(); socket++)
499 {
500 if((*socket)->getType() & ST_UDP && (*socket)->isBind() && (*socket)->getLocalPort() == (int32_t)port )
501 {
502 (*socket)->addDialogueFactory(dialoguefactory);
503 return (*socket);
504 }
505 }
506
507 if(sock == NULL)
508 {
509 if ((sock = new UDPSocket(getNepenthes(), localhost, (int32_t) port, bindtimeout, accepttimeout)) == NULL )
510 {
511 logCrit("ERROR Binding %s:%i failed\n","",port);
512 return NULL;
513 }else
514 {
515 if(sock->Init() == false)
516 {
517 logCrit("ERROR Binding %s:%i failed\n","",port);
518 delete sock;
519 return NULL;
520 }else
521 {
522 m_Sockets.push_back(sock);
523 sock->addDialogueFactory(dialoguefactory);
524 return sock;
525 }
526 }
527 }
528 return NULL;
529 }
530
531
532
bindTCPSocket(uint32_t localHost,uint16_t Port,time_t bindtimeout,time_t accepttimeout,char * dialoguefactoryname)533 Socket *SocketManager::bindTCPSocket(uint32_t localHost, uint16_t Port,time_t bindtimeout,time_t accepttimeout, char *dialoguefactoryname)
534 {
535 return NULL;
536 }
537
538
openFILESocket(char * filepath,int32_t flags)539 Socket *SocketManager::openFILESocket(char *filepath, int32_t flags)
540 {
541 #ifdef WIN32
542 return NULL;
543 #else
544 FILESocket *sock = new FILESocket(getNepenthes(),filepath, flags);
545 sock->Init();
546 m_Sockets.push_back(sock);
547 return sock;
548 #endif
549 }
550
connectUDPHost(uint32_t localhost,uint32_t remotehost,uint16_t port,time_t connecttimeout)551 Socket *SocketManager::connectUDPHost(uint32_t localhost, uint32_t remotehost, uint16_t port,time_t connecttimeout)
552 {
553 logPF();
554 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
555 {
556 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
557 localhost = m_BindAddress;
558 }
559
560 UDPSocket *sock = new UDPSocket(getNepenthes(),localhost,remotehost,port,connecttimeout);
561 sock->Init();
562 m_Sockets.push_back(sock);
563 return sock;
564 }
565
connectTCPHost(uint32_t localhost,uint32_t remotehost,uint16_t remoteport,time_t connecttimeout)566 Socket *SocketManager::connectTCPHost(uint32_t localhost, uint32_t remotehost, uint16_t remoteport,time_t connecttimeout)
567 {
568 logPF();
569 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
570 {
571 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
572 localhost = m_BindAddress;
573 }
574
575 TCPSocket *sock = new TCPSocket(getNepenthes(),localhost,remotehost,remoteport,connecttimeout);
576 sock->Init();
577 m_Sockets.push_back(sock);
578 return sock;
579 }
580
connectTCPHost(uint32_t localhost,uint32_t remotehost,uint16_t localport,uint16_t remoteport,time_t connecttimeout)581 Socket *SocketManager::connectTCPHost(uint32_t localhost, uint32_t remotehost, uint16_t localport, uint16_t remoteport,time_t connecttimeout)
582 {
583 logPF();
584 if ( localhost == INADDR_ANY && m_BindAddress != INADDR_ANY )
585 {
586 logDebug("Changed local Bind address from 0.0.0.0 to %s \n",inet_ntoa(*(in_addr *)&m_BindAddress));
587 localhost = m_BindAddress;
588 }
589
590 TCPSocket *sock = new TCPSocket(getNepenthes(),localhost,remotehost,localport,remoteport,connecttimeout);
591 if ( sock->Init() != true )
592 {
593 delete sock;
594 return NULL;
595 }
596 m_Sockets.push_back(sock);
597 return sock;
598 }
599
600
addPOLLSocket(POLLSocket * sock)601 Socket *SocketManager::addPOLLSocket(POLLSocket *sock)
602 {
603 m_Sockets.push_back(sock);
604 return sock;
605 }
606
removePOLLSocket(POLLSocket * sock)607 bool SocketManager::removePOLLSocket(POLLSocket *sock)
608 {
609 logPF();
610 list <Socket *>::iterator it;
611 for ( it = m_Sockets.begin();it != m_Sockets.end(); it++ )
612 {
613 if (sock == (*it))
614 {
615 /* this is really *bad*
616 * as it may change the order of pollfd's
617 * we should replace the socket to remove with a dead dummy socket who shares the same poll flags instead, and
618 * let the poll loop remove the socket instead
619 * but this works for now, and does not make any problem, so ...
620 */
621 m_Sockets.erase(it);
622 return true;
623 }
624 }
625 return false;
626 }
627
628