2 * Copyright (c) 2002 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #define USE_THREADS // threads vs. subprocesses
41 #include <errno.h> // for the errno variable
42 #include <string.h> // for strtok, etc
43 #include <stdlib.h> // for malloc(), free(), ...
44 #include <pcap.h> // for PCAP_ERRBUF_SIZE
45 #include <signal.h> // for signal()
48 #include "portability.h"
50 #include "fileconf.h" // for the configuration file management
51 #include "sockutils.h" // for socket calls
52 #include "rpcap-protocol.h"
53 #include "pcap-rpcap-int.h"
54 #include "daemon.h" // the true main() method of this daemon
55 #include "utils.h" // Missing calls and such
58 #include "win32-svc.h" // for Win32 service stuff
60 #include <unistd.h> // for exit()
61 #include <sys/wait.h> // waitpid()
66 char hostlist
[MAX_HOST_LIST
+ 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
67 struct active_pars activelist
[MAX_ACTIVE_LIST
]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
68 int nullAuthAllowed
; //!< '1' if we permit NULL authentication, '0' otherwise
69 static SOCKET sockmain
; //!< keeps the main socket identifier
70 char loadfile
[MAX_LINE
+ 1]; //!< Name of the file from which we have to load the configuration
71 int passivemode
= 1; //!< '1' if we want to run in passive mode as well
72 struct addrinfo mainhints
; //!< temporary struct to keep settings needed to open the new socket
73 char address
[MAX_LINE
+ 1]; //!< keeps the network address (either numeric or literal) to bind to
74 char port
[MAX_LINE
+ 1]; //!< keeps the network port to bind to
76 extern char *optarg
; // for getopt()
78 // Function definition
79 static void main_passive(void *ptr
);
80 static void main_active(void *ptr
);
83 static void main_cleanup_childs(int sign
);
86 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
89 \brief Prints the usage screen if it is launched in console mode.
91 static void printusage(void)
95 " " PROGRAM_NAME
" [-b <address>] [-p <port>] [-6] [-l <host_list>] [-a <host,port>]\n"
96 " [-n] [-v] [-d] [-s <file>] [-f <file>]\n"
97 " -b <address>: the address to bind to (either numeric or literal).\n"
98 " Default: it binds to all local IPv4 addresses\n"
99 " -p <port>: the port to bind to. Default: it binds to port " RPCAP_DEFAULT_NETPORT
"\n"
100 " -4: use only IPv4 (default both IPv4 and IPv6 waiting sockets are used)\n"
101 " -l <host_list>: a file that keeps the list of the hosts which are allowed\n"
102 " to connect to this server (if more than one, list them one per line).\n"
103 " We suggest to use literal names (instead of numeric ones) in order to\n"
104 " avoid problems with different address families\n"
105 " -n: permit NULL authentication (usually used with '-l')\n"
106 " -a <host,port>: run in active mode when connecting to 'host' on port 'port'\n"
107 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE
") is used\n"
108 " -v: run in active mode only (default: if '-a' is specified, it accepts\n"
109 " passive connections as well\n"
110 " -d: run in daemon mode (UNIX only) or as a service (Win32 only)\n"
111 " Warning (Win32): this switch is provided automatically when the service\n"
112 " is started from the control panel\n"
113 " -s <file>: save the current configuration to file\n"
114 " -f <file>: load the current configuration from file; all the switches\n"
115 " specified from the command line are ignored\n"
116 " -h: print this help screen\n\n";
118 printf("%s", usagetext
);
124 int main(int argc
, char *argv
[], char *envp
[])
126 char savefile
[MAX_LINE
+ 1]; // name of the file on which we have to save the configuration
127 int isdaemon
= 0; // Not null if the user wants to run this program as a daemon
128 int retval
; // keeps the returning value from several functions
129 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
136 memset(errbuf
, 0, sizeof(errbuf
));
138 if (sock_init(errbuf
, PCAP_ERRBUF_SIZE
) == -1)
140 SOCK_ASSERT(errbuf
, 1);
144 strncpy(address
, RPCAP_DEFAULT_NETADDR
, MAX_LINE
);
145 strncpy(port
, RPCAP_DEFAULT_NETPORT
, MAX_LINE
);
147 // Prepare to open a new server socket
148 memset(&mainhints
, 0, sizeof(struct addrinfo
));
150 mainhints
.ai_family
= PF_UNSPEC
;
151 mainhints
.ai_flags
= AI_PASSIVE
; // Ready to a bind() socket
152 mainhints
.ai_socktype
= SOCK_STREAM
;
154 // Getting the proper command line options
155 while ((retval
= getopt(argc
, argv
, "b:dhp:4l:na:s:f:v")) != -1)
160 strncpy(address
, optarg
, MAX_LINE
);
163 strncpy(port
, optarg
, MAX_LINE
);
166 mainhints
.ai_family
= PF_INET
; // IPv4 server only
179 strncpy(hostlist
, optarg
, sizeof(hostlist
));
184 char *tmpaddress
, *tmpport
;
188 tmpaddress
= pcap_strtok_r(optarg
, RPCAP_HOSTLIST_SEP
, &lasts
);
190 while ((tmpaddress
!= NULL
) && (i
< MAX_ACTIVE_LIST
))
192 tmpport
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
194 strlcpy(activelist
[i
].address
, tmpaddress
, MAX_LINE
);
196 if ((tmpport
== NULL
) || (strcmp(tmpport
, "DEFAULT") == 0)) // the user choose a custom port
197 strlcpy(activelist
[i
].port
, RPCAP_DEFAULT_NETPORT_ACTIVE
, MAX_LINE
);
199 strlcpy(activelist
[i
].port
, tmpport
, MAX_LINE
);
201 tmpaddress
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
206 if (i
> MAX_ACTIVE_LIST
)
207 SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
209 // I don't initialize the remaining part of the structure, since
210 // it is already zeroed (it is a global var)
214 strlcpy(loadfile
, optarg
, MAX_LINE
);
217 strlcpy(savefile
, optarg
, MAX_LINE
);
229 if (fileconf_save(savefile
))
230 SOCK_ASSERT("Error when saving the configuration to file", 1);
233 // If the file does not exist, it keeps the settings provided by the command line
238 // SIGTERM (i.e. kill -15) is not generated in Win32, although it is included for ANSI compatibility
239 signal(SIGTERM
, main_cleanup
);
240 signal(SIGCHLD
, main_cleanup_childs
);
243 // forking a daemon, if it is needed
249 // Unix Network Programming, pg 336
250 if ((pid
= fork()) != 0)
251 exit(0); // Parent terminates
253 // First child continues
257 // generated under unix with 'kill -HUP', needed to reload the configuration
258 signal(SIGHUP
, fileconf_read
);
260 if ((pid
= fork()) != 0)
261 exit(0); // First child terminates
263 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
264 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
265 // created. Fom this point on, the number of threads active are always one more compared
266 // to the number you're expecting
268 // Second child continues
272 // We use the SIGABRT signal to kill the Win32 service
273 signal(SIGABRT
, main_cleanup
);
275 // If this call succeeds, it is blocking on Win32
276 if (svc_start() != 1)
277 SOCK_ASSERT("Unable to start the service", 1);
279 // When the previous call returns, the entire application has to be stopped.
285 // Enable the catching of Ctrl+C
286 signal(SIGINT
, main_cleanup
);
289 // generated under unix with 'kill -HUP', needed to reload the configuration
290 // We do not have this kind of signal in Win32
291 signal(SIGHUP
, fileconf_read
);
294 printf("Press CTRL + C to stop the server...\n");
297 // If we're a Win32 service, we have already called this function in the service_main
300 // The code should never arrive here (since the main_startup is blocking)
301 // however this avoids a compiler warning
305 void main_startup(void)
307 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
308 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
311 pthread_t threadId
; // Pthread variable that keeps the thread structures
312 pthread_attr_t detachedAttribute
; // PThread attribute needed to create the thread as detached
319 memset(errbuf
, 0, sizeof(errbuf
));
321 // Starts all the active threads
322 while ((activelist
[i
].address
[0] != 0) && (i
< MAX_ACTIVE_LIST
))
324 activelist
[i
].ai_family
= mainhints
.ai_family
;
327 /* GV we need this to create the thread as detached. */
328 /* GV otherwise, the thread handle is not destroyed */
329 pthread_attr_init(&detachedAttribute
);
330 pthread_attr_setdetachstate(&detachedAttribute
, PTHREAD_CREATE_DETACHED
);
332 if (pthread_create(&threadId
, &detachedAttribute
, (void *) &main_active
, (void *) &activelist
[i
]))
334 SOCK_ASSERT("Error creating the active child thread", 1);
335 pthread_attr_destroy(&detachedAttribute
);
338 pthread_attr_destroy(&detachedAttribute
);
340 if ((pid
= fork()) == 0) // I am the child
342 main_active((void *) &activelist
[i
]);
350 * The code that manages the active connections is not blocking;
351 * the code that manages the passive connection is blocking.
352 * So, if the user does not want to run in passive mode, we have
353 * to block the main thread here, otherwise the program ends and
354 * all threads are stopped.
356 * WARNING: this means that in case we have only active mode,
357 * the program does not terminate even if all the child thread
358 * terminates. The user has always to press Ctrl+C (or send a
359 * SIGTERM) to terminate the program.
363 struct addrinfo
*tempaddrinfo
;
366 if (sock_initaddress((address
[0]) ? address
: NULL
, port
, &mainhints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
368 SOCK_ASSERT(errbuf
, 1);
372 tempaddrinfo
= addrinfo
;
378 if ((sockmain
= sock_open(tempaddrinfo
, SOCKOPEN_SERVER
, SOCKET_MAXCONN
, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
380 SOCK_ASSERT(errbuf
, 1);
381 tempaddrinfo
= tempaddrinfo
->ai_next
;
385 // This trick is needed in order to allow the child thread to save the 'sockmain' variable
386 // withouth getting it overwritten by the sock_open, in case we want to open more than one waiting sockets
387 // For instance, the pthread_create() will accept the socktemp variable, and it will deallocate immediately that variable
388 socktemp
= (SOCKET
*) malloc (sizeof (SOCKET
));
389 if (socktemp
== NULL
)
392 *socktemp
= sockmain
;
395 /* GV we need this to create the thread as detached. */
396 /* GV otherwise, the thread handle is not destroyed */
397 pthread_attr_init(&detachedAttribute
);
398 pthread_attr_setdetachstate(&detachedAttribute
, PTHREAD_CREATE_DETACHED
);
400 if (pthread_create(&threadId
, &detachedAttribute
, (void *) &main_passive
, (void *) socktemp
))
402 SOCK_ASSERT("Error creating the passive child thread", 1);
403 pthread_attr_destroy(&detachedAttribute
);
407 pthread_attr_destroy(&detachedAttribute
);
409 if ((pid
= fork()) == 0) // I am the child
411 main_passive((void *) socktemp
);
415 tempaddrinfo
= tempaddrinfo
->ai_next
;
418 freeaddrinfo(addrinfo
);
421 // All the previous calls are no blocking, so the main line of execution goes here
422 // and I have to avoid that the program terminates
424 pthread_suspend(10*60*1000); // it wakes up every 10 minutes; it seems to me reasonable
429 \brief Closes gracefully (more or less) the program.
431 This function is called:
432 - when we're running in console
433 - when we're running as a Win32 service (in case we press STOP)
435 It is not called when we are running as a daemon on UNIX, since
436 we do not define a signal in order to terminate gracefully the daemon.
438 This function makes a fast cleanup (it does not clean everything, as
439 you can see from the fact that it uses kill() on UNIX), closes
440 the main socket, free winsock resources (on Win32) and exits the
443 void main_cleanup(int sign
)
446 // Sends a KILL signal to all the processes
447 // that share the same process group (i.e. kills all the childs)
451 SOCK_ASSERT(PROGRAM_NAME
" is closing.\n", 1);
454 // Here we close only the latest 'sockmain' created; if we opened more than one waiting sockets,
455 // only the latest one is closed correctly.
457 closesocket(sockmain
);
461 This code is executed under the following conditions:
462 - SIGTERM: we're under UNIX, and the user kills us with 'kill -15'
463 (no matter is we're a daemon or in a console mode)
464 - SIGINT: we're in console mode and the user sends us a Ctrl+C
465 (SIGINT signal), no matter if we're UNIX or Win32
467 In all these cases, we have to terminate the program.
468 The case that still remains is if we're a Win32 service: in this case,
469 we're a child thread, and we want just to terminate ourself. This is because
470 the exit(0) will be invoked by the main thread, which is blocked waiting that
471 all childs terminates. We are forced to call exit from the main thread otherwise
472 the Win32 service control manager (SCM) does not work well.
474 if ((sign
== SIGTERM
) || (sign
== SIGINT
))
481 static void main_cleanup_childs(int sign
)
486 // For reference, Stevens, pg 128
488 while ((pid
= waitpid(-1, &stat
, WNOHANG
)) > 0)
489 SOCK_ASSERT("Child terminated", 1);
496 \brief 'true' main of the program.
498 It must be in a separate function because:
499 - if we're in 'console' mode, we have to put the main thread waiting for a Ctrl+C
500 (in order to be able to stop everything)
501 - if we're in daemon mode, the main program must terminate and a new child must be
502 created in order to create the daemon
504 \param ptr: it keeps the main socket handler (what's called 'sockmain' in the main()), that
505 represents the socket used in the main connection. It is a 'void *' just because pthreads
508 static void main_passive(void *ptr
)
510 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
511 SOCKET sockctrl
; // keeps the socket ID for this control connection
512 struct sockaddr_storage from
; // generic sockaddr_storage variable
513 socklen_t fromlen
; // keeps the length of the sockaddr_storage variable
520 sockmain
= *((SOCKET
*) ptr
);
522 // Delete the pointer (which has been allocated in the main)
526 memset(errbuf
, 0, sizeof(errbuf
));
532 pthread_t threadId
; // Pthread variable that keeps the thread structures
533 pthread_attr_t detachedAttribute
;
535 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
537 // Connection creation
538 fromlen
= sizeof(struct sockaddr_storage
);
540 sockctrl
= accept(sockmain
, (struct sockaddr
*) &from
, &fromlen
);
544 // The accept() call can return this error when a signal is catched
545 // In this case, we have simply to ignore this error code
548 if (WSAGetLastError() == WSAEINTR
)
554 // Don't check for errors here, since the error can be due to the fact that the thread
556 sock_geterror("accept(): ", errbuf
, PCAP_ERRBUF_SIZE
);
557 SOCK_ASSERT(errbuf
, 1);
561 // checks if the connecting host is among the ones allowed
562 if (sock_check_hostlist(hostlist
, RPCAP_HOSTLIST_SEP
, &from
, errbuf
, PCAP_ERRBUF_SIZE
) < 0)
564 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_HOSTNOAUTH
, NULL
);
565 sock_close(sockctrl
, NULL
, 0);
571 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
572 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
575 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
579 pars
->sockctrl
= sockctrl
;
580 pars
->activeclose
= 0; // useless in passive mode
582 pars
->nullAuthAllowed
= nullAuthAllowed
;
584 /* GV we need this to create the thread as detached. */
585 /* GV otherwise, the thread handle is not destroyed */
586 pthread_attr_init(&detachedAttribute
);
587 pthread_attr_setdetachstate(&detachedAttribute
, PTHREAD_CREATE_DETACHED
);
588 if (pthread_create(&threadId
, &detachedAttribute
, (void *) &daemon_serviceloop
, (void *) pars
))
590 SOCK_ASSERT("Error creating the child thread", 1);
591 pthread_attr_destroy(&detachedAttribute
);
594 pthread_attr_destroy(&detachedAttribute
);
597 if ((pid
= fork()) == 0) // I am the child
599 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
600 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
603 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
607 pars
->sockctrl
= sockctrl
;
608 pars
->activeclose
= 0; // useless in passive mode
610 pars
->nullAuthAllowed
= nullAuthAllowed
;
612 // Close the main socket (must be open only in the parent)
613 closesocket(sockmain
);
615 daemon_serviceloop((void *) pars
);
620 // Close the childsocket (must be open only in the child)
621 closesocket(sockctrl
);
624 // loop forever, until interrupted
629 \brief 'true' main of the program in case the active mode is turned on.
631 It does not have any return value nor parameters.
632 This function loops forever trying to connect to the remote host, until the
633 daemon is turned down.
635 \param ptr: it keeps the 'activepars' parameters. It is a 'void *' just because pthreads
638 static void main_active(void *ptr
)
640 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
641 SOCKET sockctrl
; // keeps the socket ID for this control connection
642 struct addrinfo hints
; // temporary struct to keep settings needed to open the new socket
643 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
644 struct active_pars
*activepars
;
645 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
647 activepars
= (struct active_pars
*) ptr
;
649 // Prepare to open a new server socket
650 memset(&hints
, 0, sizeof(struct addrinfo
));
651 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
652 hints
.ai_family
= AF_INET
; // PF_UNSPEC to have both IPv4 and IPv6 server
653 hints
.ai_socktype
= SOCK_STREAM
;
654 hints
.ai_family
= activepars
->ai_family
;
656 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Connecting to host %s, port %s, using protocol %s",
657 activepars
->address
, activepars
->port
, (hints
.ai_family
== AF_INET
) ? "IPv4":
658 (hints
.ai_family
== AF_INET6
) ? "IPv6" : "Unspecified");
659 SOCK_ASSERT(errbuf
, 1);
662 memset(errbuf
, 0, sizeof(errbuf
));
665 if (sock_initaddress(activepars
->address
, activepars
->port
, &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
667 SOCK_ASSERT(errbuf
, 1);
675 if ((sockctrl
= sock_open(addrinfo
, SOCKOPEN_CLIENT
, 0, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
677 SOCK_ASSERT(errbuf
, 1);
679 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error connecting to host %s, port %s, using protocol %s",
680 activepars
->address
, activepars
->port
, (hints
.ai_family
== AF_INET
) ? "IPv4":
681 (hints
.ai_family
== AF_INET6
) ? "IPv6" : "Unspecified");
683 SOCK_ASSERT(errbuf
, 1);
685 pthread_suspend(RPCAP_ACTIVE_WAIT
* 1000);
690 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
693 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
697 pars
->sockctrl
= sockctrl
;
698 pars
->activeclose
= 0;
700 pars
->nullAuthAllowed
= nullAuthAllowed
;
702 daemon_serviceloop((void *) pars
);
704 activeclose
= pars
->activeclose
;
708 // If the connection is closed by the user explicitely, don't try to connect to it again
709 // just exit the program
710 if (activeclose
== 1)