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