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.
39 #include <errno.h> // for the errno variable
40 #include <string.h> // for strtok, etc
41 #include <stdlib.h> // for malloc(), free(), ...
42 #include <pcap.h> // for PCAP_ERRBUF_SIZE
43 #include <signal.h> // for signal()
46 #include "sockutils.h" // for socket calls
47 #include "portability.h"
49 #include "fileconf.h" // for the configuration file management
50 #include "rpcap-protocol.h"
51 #include "daemon.h" // the true main() method of this daemon
55 #include <process.h> // for thread stuff
56 #include "win32-svc.h" // for Win32 service stuff
57 #include "getopt.h" // for getopt()-for-Windows
59 #include <unistd.h> // for exit()
60 #include <sys/wait.h> // waitpid()
65 char hostlist
[MAX_HOST_LIST
+ 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
66 struct active_pars activelist
[MAX_ACTIVE_LIST
]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
67 int nullAuthAllowed
; //!< '1' if we permit NULL authentication, '0' otherwise
68 static SOCKET sockmain
; //!< keeps the main socket identifier
69 char loadfile
[MAX_LINE
+ 1]; //!< Name of the file from which we have to load the configuration
70 int passivemode
= 1; //!< '1' if we want to run in passive mode as well
71 struct addrinfo mainhints
; //!< temporary struct to keep settings needed to open the new socket
72 char address
[MAX_LINE
+ 1]; //!< keeps the network address (either numeric or literal) to bind to
73 char port
[MAX_LINE
+ 1]; //!< keeps the network port to bind to
75 extern char *optarg
; // for getopt()
77 // Function definition
79 static unsigned __stdcall
main_passive(void *ptr
);
80 static unsigned __stdcall
main_active(void *ptr
);
82 static void *main_passive(void *ptr
);
83 static void *main_active(void *ptr
);
86 static void main_terminate(int sign
);
88 static void main_abort(int sign
);
90 static void main_reap_children(int sign
);
93 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
96 \brief Prints the usage screen if it is launched in console mode.
98 static void printusage(void)
102 " " PROGRAM_NAME
" [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
103 " [-n] [-v] [-d] [-s <file>] [-f <file>]\n\n"
104 " -b <address> the address to bind to (either numeric or literal).\n"
105 " Default: binds to all local IPv4 and IPv6 addresses\n\n"
106 " -p <port> the port to bind to.\n"
107 " Default: binds to port " RPCAP_DEFAULT_NETPORT
"\n\n"
108 " -4 use only IPv4.\n"
109 " Default: use both IPv4 and IPv6 waiting sockets\n\n"
110 " -l <host_list> a file that contains a list of hosts that are allowed\n"
111 " to connect to this server (if more than one, list them one per line).\n"
112 " We suggest to use literal names (instead of numeric ones) in\n"
113 " order to avoid problems with different address families.\n\n"
114 " -n permit NULL authentication (usually used with '-l')\n\n"
115 " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
116 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE
") is used\n\n"
117 " -v run in active mode only (default: if '-a' is specified, it accepts\n"
118 " passive connections as well\n\n"
119 " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
120 " Warning (Win32): this switch is provided automatically when the service\n"
121 " is started from the control panel\n\n"
122 " -s <file> save the current configuration to file\n\n"
123 " -f <file> load the current configuration from file; all switches\n"
124 " specified from the command line are ignored\n\n"
125 " -h print this help screen\n\n";
127 (void)fprintf(stderr
, "RPCAPD, a remote packet capture daemon.\n"
128 "Compiled with %s\n\n", pcap_lib_version());
129 printf("%s", usagetext
);
135 int main(int argc
, char *argv
[], char *envp
[])
137 char savefile
[MAX_LINE
+ 1]; // name of the file on which we have to save the configuration
138 int isdaemon
= 0; // Not null if the user wants to run this program as a daemon
139 int retval
; // keeps the returning value from several functions
140 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
147 memset(errbuf
, 0, sizeof(errbuf
));
149 if (sock_init(errbuf
, PCAP_ERRBUF_SIZE
) == -1)
151 SOCK_ASSERT(errbuf
, 1);
155 strncpy(address
, RPCAP_DEFAULT_NETADDR
, MAX_LINE
);
156 strncpy(port
, RPCAP_DEFAULT_NETPORT
, MAX_LINE
);
158 // Prepare to open a new server socket
159 memset(&mainhints
, 0, sizeof(struct addrinfo
));
161 mainhints
.ai_family
= PF_UNSPEC
;
162 mainhints
.ai_flags
= AI_PASSIVE
; // Ready to a bind() socket
163 mainhints
.ai_socktype
= SOCK_STREAM
;
165 // Getting the proper command line options
166 while ((retval
= getopt(argc
, argv
, "b:dhp:4l:na:s:f:v")) != -1)
171 strncpy(address
, optarg
, MAX_LINE
);
174 strncpy(port
, optarg
, MAX_LINE
);
177 mainhints
.ai_family
= PF_INET
; // IPv4 server only
190 strncpy(hostlist
, optarg
, sizeof(hostlist
));
195 char *tmpaddress
, *tmpport
;
199 tmpaddress
= pcap_strtok_r(optarg
, RPCAP_HOSTLIST_SEP
, &lasts
);
201 while ((tmpaddress
!= NULL
) && (i
< MAX_ACTIVE_LIST
))
203 tmpport
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
205 strlcpy(activelist
[i
].address
, tmpaddress
, MAX_LINE
);
207 if ((tmpport
== NULL
) || (strcmp(tmpport
, "DEFAULT") == 0)) // the user choose a custom port
208 strlcpy(activelist
[i
].port
, RPCAP_DEFAULT_NETPORT_ACTIVE
, MAX_LINE
);
210 strlcpy(activelist
[i
].port
, tmpport
, MAX_LINE
);
212 tmpaddress
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
217 if (i
> MAX_ACTIVE_LIST
)
218 SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
220 // I don't initialize the remaining part of the structure, since
221 // it is already zeroed (it is a global var)
225 strlcpy(loadfile
, optarg
, MAX_LINE
);
228 strlcpy(savefile
, optarg
, MAX_LINE
);
240 if (fileconf_save(savefile
))
241 SOCK_ASSERT("Error when saving the configuration to file", 1);
244 // If the file does not exist, it keeps the settings provided by the command line
249 // SIGTERM (i.e. kill -15) is not generated in Win32, although it is included for ANSI compatibility
250 signal(SIGTERM
, main_terminate
);
251 signal(SIGCHLD
, main_reap_children
);
252 // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
253 // connection, we don't want to get killed by a signal in that case
254 signal(SIGPIPE
, SIG_IGN
);
257 // forking a daemon, if it is needed
263 // Unix Network Programming, pg 336
264 if ((pid
= fork()) != 0)
265 exit(0); // Parent terminates
267 // First child continues
271 // generated under unix with 'kill -HUP', needed to reload the configuration
272 signal(SIGHUP
, fileconf_read
);
274 if ((pid
= fork()) != 0)
275 exit(0); // First child terminates
277 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
278 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
279 // created. Fom this point on, the number of threads active are always one more compared
280 // to the number you're expecting
282 // Second child continues
286 // We use the SIGABRT signal to kill the Win32 service
287 signal(SIGABRT
, main_abort
);
289 // If this call succeeds, it is blocking on Win32
290 if (svc_start() != 1)
291 SOCK_ASSERT("Unable to start the service", 1);
293 // When the previous call returns, the entire application has to be stopped.
299 // Enable the catching of Ctrl+C
300 signal(SIGINT
, main_terminate
);
303 // generated under unix with 'kill -HUP', needed to reload the configuration
304 // We do not have this kind of signal in Win32
305 signal(SIGHUP
, fileconf_read
);
308 printf("Press CTRL + C to stop the server...\n");
311 // If we're a Win32 service, we have already called this function in the service_main
314 // The code should never arrive here (since the main_startup is blocking)
315 // however this avoids a compiler warning
319 void main_startup(void)
321 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
322 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
325 HANDLE threadId
; // handle for the subthread
332 memset(errbuf
, 0, sizeof(errbuf
));
334 // Starts all the active threads
335 while ((i
< MAX_ACTIVE_LIST
) && (activelist
[i
].address
[0] != 0))
337 activelist
[i
].ai_family
= mainhints
.ai_family
;
340 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, main_active
,
341 (void *)&activelist
[i
], 0, NULL
);
344 SOCK_ASSERT("Error creating the active child threads", 1);
347 CloseHandle(threadId
);
349 if ((pid
= fork()) == 0) // I am the child
351 main_active((void *) &activelist
[i
]);
359 * The code that manages the active connections is not blocking;
360 * the code that manages the passive connection is blocking.
361 * So, if the user does not want to run in passive mode, we have
362 * to block the main thread here, otherwise the program ends and
363 * all threads are stopped.
365 * WARNING: this means that in case we have only active mode,
366 * the program does not terminate even if all the child thread
367 * terminates. The user has always to press Ctrl+C (or send a
368 * SIGTERM) to terminate the program.
372 struct addrinfo
*tempaddrinfo
;
375 if (sock_initaddress((address
[0]) ? address
: NULL
, port
, &mainhints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
377 SOCK_ASSERT(errbuf
, 1);
381 tempaddrinfo
= addrinfo
;
387 if ((sockmain
= sock_open(tempaddrinfo
, SOCKOPEN_SERVER
, SOCKET_MAXCONN
, errbuf
, PCAP_ERRBUF_SIZE
)) == INVALID_SOCKET
)
389 SOCK_ASSERT(errbuf
, 1);
390 tempaddrinfo
= tempaddrinfo
->ai_next
;
395 // This trick is needed in order to allow the child
396 // thread to save the 'sockmain' variable without
397 // getting it overwritten by the sock_open, in case
398 // we want to open more than one waiting socket.
400 // For instance, the rpcapd_thread_create() will
401 // accept the socktemp variable, and it will
402 // immediately deallocate that variable.
404 // XXX - this shouldn't be necessary if we're
405 // using subprocesses rather than threads, as
406 // the use and overwrite would be done in
407 // separate processes; we should be able to
408 // pass a pointer to sockmain in the child
411 socktemp
= (SOCKET
*) malloc (sizeof (SOCKET
));
412 if (socktemp
== NULL
)
415 *socktemp
= sockmain
;
418 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, main_passive
,
419 (void *) socktemp
, 0, NULL
);
422 SOCK_ASSERT("Error creating the passive child thread", 1);
426 CloseHandle(threadId
);
428 if ((pid
= fork()) == 0) // I am the child
430 freeaddrinfo(addrinfo
);
431 main_passive((void *) socktemp
);
436 tempaddrinfo
= tempaddrinfo
->ai_next
;
439 freeaddrinfo(addrinfo
);
442 // All the previous calls are no blocking, so the main line of execution goes here
443 // and I have to avoid that the program terminates
456 \brief Closes gracefully (more or less) the program.
458 This function is called:
459 - when we're running in console and are terminated with ^C;
460 - on UN*X, when we're terminated with SIGTERM.
462 static void main_terminate(int sign
)
464 SOCK_ASSERT(PROGRAM_NAME
" is closing.\n", 1);
468 // Sends a KILL signal to all the processes in this process's
469 // process group; i.e., it kills all the child processes
472 // XXX - that also includes us, so we will be killed as well;
473 // that may cause a message to be printed or logged.
479 // Just leave. We shouldn't need to clean up sockets or
480 // anything else, and if we try to do so, we'll could end
481 // up closing sockets, or shutting Winsock down, out from
482 // under service loops, causing all sorts of noisy error
485 // We shouldn't need to worry about cleaning up any resources
486 // such as handles, sockets, threads, etc. - exit() should
487 // terminate the process, causing all those resources to be
490 // Note that, on Windows, this will happen only for ^C, and
491 // thus will happen on a thread created to run the ^C handler,
492 // which is how it manages to cause the aforementioned service
493 // loop issues in service loops in other threads.
499 static void main_abort(int sign
)
501 SOCK_ASSERT(PROGRAM_NAME
" is closing due to a SIGABRT.\n", 1);
504 // XXX - there should be a way to poke the main thread to get
505 // it to shut down the service.
509 // Here we close only the latest 'sockmain' created; if we opened more than one waiting sockets,
510 // only the latest one is closed correctly.
512 closesocket(sockmain
);
516 * This is a Win32 service, so we're a child thread, and we want
517 * just to terminate ourself. This is because the exit(0) will
518 * be invoked by the main thread, which is blocked waiting that
519 * all childs terminates. We are forced to call exit from the
520 * main thread, otherwise the Win32 service control manager
521 * (SCM) does not work well.
527 static void main_reap_children(int sign
)
532 // Reap all child processes that have exited.
533 // For reference, Stevens, pg 128
535 while ((pid
= waitpid(-1, &exitstat
, WNOHANG
)) > 0)
536 SOCK_ASSERT("Child terminated", 1);
543 \brief 'true' main of the program.
545 It must be in a separate function because:
546 - if we're in 'console' mode, we have to put the main thread waiting for a Ctrl+C
547 (in order to be able to stop everything)
548 - if we're in daemon mode, the main program must terminate and a new child must be
549 created in order to create the daemon
551 \param ptr: it keeps the main socket handler (what's called
552 'sockmain' in the main()), that represents the socket used in
553 the main connection. It is a 'void *' just because the thread
554 APIs want this format.
557 static unsigned __stdcall
561 main_passive(void *ptr
)
563 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
564 SOCKET sockctrl
; // keeps the socket ID for this control connection
565 struct sockaddr_storage from
; // generic sockaddr_storage variable
566 socklen_t fromlen
; // keeps the length of the sockaddr_storage variable
573 sockmain
= *((SOCKET
*) ptr
);
575 // Delete the pointer (which has been allocated in the main)
579 memset(errbuf
, 0, sizeof(errbuf
));
585 HANDLE threadId
; // handle for the subthread
587 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
589 // Connection creation
590 fromlen
= sizeof(struct sockaddr_storage
);
592 sockctrl
= accept(sockmain
, (struct sockaddr
*) &from
, &fromlen
);
594 if (sockctrl
== INVALID_SOCKET
)
596 // The accept() call can return this error when a signal is catched
597 // In this case, we have simply to ignore this error code
600 if (WSAGetLastError() == WSAEINTR
)
606 // Don't check for errors here, since the error can be due to the fact that the thread
608 sock_geterror("accept(): ", errbuf
, PCAP_ERRBUF_SIZE
);
609 rpcapd_log(LOGPRIO_ERROR
, "Accept of control connection from client failed: %s",
614 // checks if the connecting host is among the ones allowed
615 if (sock_check_hostlist(hostlist
, RPCAP_HOSTLIST_SEP
, &from
, errbuf
, PCAP_ERRBUF_SIZE
) < 0)
617 rpcap_senderror(sockctrl
, 0, PCAP_ERR_HOSTNOAUTH
, errbuf
, NULL
);
618 sock_close(sockctrl
, NULL
, 0);
624 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
625 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
628 pcap_fmt_errmsg_for_errno(errbuf
, PCAP_ERRBUF_SIZE
,
629 errno
, "malloc() failed");
630 rpcap_senderror(sockctrl
, 0, PCAP_ERR_OPEN
, errbuf
, NULL
);
631 sock_close(sockctrl
, NULL
, 0);
635 pars
->sockctrl
= sockctrl
;
636 pars
->activeclose
= 0; // useless in passive mode
638 pars
->nullAuthAllowed
= nullAuthAllowed
;
640 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, daemon_serviceloop
,
641 (void *) pars
, 0, NULL
);
644 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error creating the child thread");
645 rpcap_senderror(sockctrl
, 0, PCAP_ERR_OPEN
, errbuf
, NULL
);
646 sock_close(sockctrl
, NULL
, 0);
649 CloseHandle(threadId
);
651 if ((pid
= fork()) == 0) // I am the child
653 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
654 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
657 pcap_fmt_errmsg_for_errno(errbuf
,
658 PCAP_ERRBUF_SIZE
, errno
, "malloc() failed");
662 pars
->sockctrl
= sockctrl
;
663 pars
->activeclose
= 0; // useless in passive mode
665 pars
->nullAuthAllowed
= nullAuthAllowed
;
667 // Close the main socket (must be open only in the parent)
668 closesocket(sockmain
);
670 daemon_serviceloop((void *) pars
);
675 // Close the childsocket (must be open only in the child)
676 closesocket(sockctrl
);
679 // loop forever, until interrupted
685 \brief 'true' main of the program in case the active mode is turned on.
687 This function loops forever trying to connect to the remote host, until the
688 daemon is turned down.
690 \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
691 just because the thread APIs want this format.
694 static unsigned __stdcall
698 main_active(void *ptr
)
700 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
701 SOCKET sockctrl
; // keeps the socket ID for this control connection
702 struct addrinfo hints
; // temporary struct to keep settings needed to open the new socket
703 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
704 struct active_pars
*activepars
;
705 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
707 activepars
= (struct active_pars
*) ptr
;
709 // Prepare to open a new server socket
710 memset(&hints
, 0, sizeof(struct addrinfo
));
711 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
712 hints
.ai_family
= AF_INET
; // PF_UNSPEC to have both IPv4 and IPv6 server
713 hints
.ai_socktype
= SOCK_STREAM
;
714 hints
.ai_family
= activepars
->ai_family
;
716 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Connecting to host %s, port %s, using protocol %s",
717 activepars
->address
, activepars
->port
, (hints
.ai_family
== AF_INET
) ? "IPv4":
718 (hints
.ai_family
== AF_INET6
) ? "IPv6" : "Unspecified");
719 SOCK_ASSERT(errbuf
, 1);
722 memset(errbuf
, 0, sizeof(errbuf
));
725 if (sock_initaddress(activepars
->address
, activepars
->port
, &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
727 SOCK_ASSERT(errbuf
, 1);
735 if ((sockctrl
= sock_open(addrinfo
, SOCKOPEN_CLIENT
, 0, errbuf
, PCAP_ERRBUF_SIZE
)) == INVALID_SOCKET
)
737 SOCK_ASSERT(errbuf
, 1);
739 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error connecting to host %s, port %s, using protocol %s",
740 activepars
->address
, activepars
->port
, (hints
.ai_family
== AF_INET
) ? "IPv4":
741 (hints
.ai_family
== AF_INET6
) ? "IPv6" : "Unspecified");
743 SOCK_ASSERT(errbuf
, 1);
745 sleep_secs(RPCAP_ACTIVE_WAIT
);
750 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
753 pcap_fmt_errmsg_for_errno(errbuf
, PCAP_ERRBUF_SIZE
,
754 errno
, "malloc() failed");
758 pars
->sockctrl
= sockctrl
;
759 pars
->activeclose
= 0;
761 pars
->nullAuthAllowed
= nullAuthAllowed
;
763 daemon_serviceloop((void *) pars
);
765 activeclose
= pars
->activeclose
;
769 // If the connection is closed by the user explicitely, don't try to connect to it again
770 // just exit the program
771 if (activeclose
== 1)
775 freeaddrinfo(addrinfo
);