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()
45 #include "sockutils.h" // for socket calls
46 #include "portability.h"
48 #include "fileconf.h" // for the configuration file management
49 #include "rpcap-protocol.h"
50 #include "daemon.h" // the true main() method of this daemon
52 #include "utils.h" // Missing calls and such
55 #include <process.h> // for thread stuff
56 #include "win32-svc.h" // for Win32 service stuff
58 #include <unistd.h> // for exit()
59 #include <sys/wait.h> // waitpid()
64 char hostlist
[MAX_HOST_LIST
+ 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
65 struct active_pars activelist
[MAX_ACTIVE_LIST
]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
66 int nullAuthAllowed
; //!< '1' if we permit NULL authentication, '0' otherwise
67 static SOCKET sockmain
; //!< keeps the main socket identifier
68 char loadfile
[MAX_LINE
+ 1]; //!< Name of the file from which we have to load the configuration
69 int passivemode
= 1; //!< '1' if we want to run in passive mode as well
70 struct addrinfo mainhints
; //!< temporary struct to keep settings needed to open the new socket
71 char address
[MAX_LINE
+ 1]; //!< keeps the network address (either numeric or literal) to bind to
72 char port
[MAX_LINE
+ 1]; //!< keeps the network port to bind to
74 extern char *optarg
; // for getopt()
76 // Function definition
78 static unsigned __stdcall
main_passive(void *ptr
);
79 static unsigned __stdcall
main_active(void *ptr
);
81 static void *main_passive(void *ptr
);
82 static void *main_active(void *ptr
);
85 static void main_terminate(int sign
);
87 static void main_abort(int sign
);
89 static void main_reap_children(int sign
);
92 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
95 \brief Prints the usage screen if it is launched in console mode.
97 static void printusage(void)
101 " " PROGRAM_NAME
" [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
102 " [-n] [-v] [-d] [-s <file>] [-f <file>]\n\n"
103 " -b <address> the address to bind to (either numeric or literal).\n"
104 " Default: binds to all local IPv4 and IPv6 addresses\n\n"
105 " -p <port> the port to bind to.\n"
106 " Default: binds to port " RPCAP_DEFAULT_NETPORT
"\n\n"
107 " -4 use only IPv4.\n"
108 " Default: use both IPv4 and IPv6 waiting sockets\n\n"
109 " -l <host_list> a file that contains a list of hosts that are allowed\n"
110 " to connect to this server (if more than one, list them one per line).\n"
111 " We suggest to use literal names (instead of numeric ones) in\n"
112 " order to avoid problems with different address families.\n\n"
113 " -n permit NULL authentication (usually used with '-l')\n\n"
114 " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
115 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE
") is used\n\n"
116 " -v run in active mode only (default: if '-a' is specified, it accepts\n"
117 " passive connections as well\n\n"
118 " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
119 " Warning (Win32): this switch is provided automatically when the service\n"
120 " is started from the control panel\n\n"
121 " -s <file> save the current configuration to file\n\n"
122 " -f <file> load the current configuration from file; all switches\n"
123 " specified from the command line are ignored\n\n"
124 " -h print this help screen\n\n";
126 (void)fprintf(stderr
, "RPCAPD, a remote packet capture daemon.\n"
127 "Compiled with %s\n\n", pcap_lib_version());
128 printf("%s", usagetext
);
134 int main(int argc
, char *argv
[], char *envp
[])
136 char savefile
[MAX_LINE
+ 1]; // name of the file on which we have to save the configuration
137 int isdaemon
= 0; // Not null if the user wants to run this program as a daemon
138 int retval
; // keeps the returning value from several functions
139 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
146 memset(errbuf
, 0, sizeof(errbuf
));
148 if (sock_init(errbuf
, PCAP_ERRBUF_SIZE
) == -1)
150 SOCK_ASSERT(errbuf
, 1);
154 strncpy(address
, RPCAP_DEFAULT_NETADDR
, MAX_LINE
);
155 strncpy(port
, RPCAP_DEFAULT_NETPORT
, MAX_LINE
);
157 // Prepare to open a new server socket
158 memset(&mainhints
, 0, sizeof(struct addrinfo
));
160 mainhints
.ai_family
= PF_UNSPEC
;
161 mainhints
.ai_flags
= AI_PASSIVE
; // Ready to a bind() socket
162 mainhints
.ai_socktype
= SOCK_STREAM
;
164 // Getting the proper command line options
165 while ((retval
= getopt(argc
, argv
, "b:dhp:4l:na:s:f:v")) != -1)
170 strncpy(address
, optarg
, MAX_LINE
);
173 strncpy(port
, optarg
, MAX_LINE
);
176 mainhints
.ai_family
= PF_INET
; // IPv4 server only
189 strncpy(hostlist
, optarg
, sizeof(hostlist
));
194 char *tmpaddress
, *tmpport
;
198 tmpaddress
= pcap_strtok_r(optarg
, RPCAP_HOSTLIST_SEP
, &lasts
);
200 while ((tmpaddress
!= NULL
) && (i
< MAX_ACTIVE_LIST
))
202 tmpport
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
204 strlcpy(activelist
[i
].address
, tmpaddress
, MAX_LINE
);
206 if ((tmpport
== NULL
) || (strcmp(tmpport
, "DEFAULT") == 0)) // the user choose a custom port
207 strlcpy(activelist
[i
].port
, RPCAP_DEFAULT_NETPORT_ACTIVE
, MAX_LINE
);
209 strlcpy(activelist
[i
].port
, tmpport
, MAX_LINE
);
211 tmpaddress
= pcap_strtok_r(NULL
, RPCAP_HOSTLIST_SEP
, &lasts
);
216 if (i
> MAX_ACTIVE_LIST
)
217 SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
219 // I don't initialize the remaining part of the structure, since
220 // it is already zeroed (it is a global var)
224 strlcpy(loadfile
, optarg
, MAX_LINE
);
227 strlcpy(savefile
, optarg
, MAX_LINE
);
239 if (fileconf_save(savefile
))
240 SOCK_ASSERT("Error when saving the configuration to file", 1);
243 // If the file does not exist, it keeps the settings provided by the command line
248 // SIGTERM (i.e. kill -15) is not generated in Win32, although it is included for ANSI compatibility
249 signal(SIGTERM
, main_terminate
);
250 signal(SIGCHLD
, main_reap_children
);
253 // forking a daemon, if it is needed
259 // Unix Network Programming, pg 336
260 if ((pid
= fork()) != 0)
261 exit(0); // Parent terminates
263 // First child continues
267 // generated under unix with 'kill -HUP', needed to reload the configuration
268 signal(SIGHUP
, fileconf_read
);
270 if ((pid
= fork()) != 0)
271 exit(0); // First child terminates
273 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
274 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
275 // created. Fom this point on, the number of threads active are always one more compared
276 // to the number you're expecting
278 // Second child continues
282 // We use the SIGABRT signal to kill the Win32 service
283 signal(SIGABRT
, main_abort
);
285 // If this call succeeds, it is blocking on Win32
286 if (svc_start() != 1)
287 SOCK_ASSERT("Unable to start the service", 1);
289 // When the previous call returns, the entire application has to be stopped.
295 // Enable the catching of Ctrl+C
296 signal(SIGINT
, main_terminate
);
299 // generated under unix with 'kill -HUP', needed to reload the configuration
300 // We do not have this kind of signal in Win32
301 signal(SIGHUP
, fileconf_read
);
304 printf("Press CTRL + C to stop the server...\n");
307 // If we're a Win32 service, we have already called this function in the service_main
310 // The code should never arrive here (since the main_startup is blocking)
311 // however this avoids a compiler warning
315 void main_startup(void)
317 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
318 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
321 HANDLE threadId
; // handle for the subthread
328 memset(errbuf
, 0, sizeof(errbuf
));
330 // Starts all the active threads
331 while ((i
< MAX_ACTIVE_LIST
) && (activelist
[i
].address
[0] != 0))
333 activelist
[i
].ai_family
= mainhints
.ai_family
;
336 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, main_active
,
337 (void *)&activelist
[i
], 0, NULL
);
340 SOCK_ASSERT("Error creating the active child threads", 1);
343 CloseHandle(threadId
);
345 if ((pid
= fork()) == 0) // I am the child
347 main_active((void *) &activelist
[i
]);
355 * The code that manages the active connections is not blocking;
356 * the code that manages the passive connection is blocking.
357 * So, if the user does not want to run in passive mode, we have
358 * to block the main thread here, otherwise the program ends and
359 * all threads are stopped.
361 * WARNING: this means that in case we have only active mode,
362 * the program does not terminate even if all the child thread
363 * terminates. The user has always to press Ctrl+C (or send a
364 * SIGTERM) to terminate the program.
368 struct addrinfo
*tempaddrinfo
;
371 if (sock_initaddress((address
[0]) ? address
: NULL
, port
, &mainhints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
373 SOCK_ASSERT(errbuf
, 1);
377 tempaddrinfo
= addrinfo
;
383 if ((sockmain
= sock_open(tempaddrinfo
, SOCKOPEN_SERVER
, SOCKET_MAXCONN
, errbuf
, PCAP_ERRBUF_SIZE
)) == INVALID_SOCKET
)
385 SOCK_ASSERT(errbuf
, 1);
386 tempaddrinfo
= tempaddrinfo
->ai_next
;
390 // This trick is needed in order to allow the child thread to save the 'sockmain' variable
391 // withouth getting it overwritten by the sock_open, in case we want to open more than one waiting sockets
392 // For instance, the rpcapd_thread_create() will accept the socktemp variable, and it will deallocate immediately that variable
393 socktemp
= (SOCKET
*) malloc (sizeof (SOCKET
));
394 if (socktemp
== NULL
)
397 *socktemp
= sockmain
;
400 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, main_passive
,
401 (void *) socktemp
, 0, NULL
);
404 SOCK_ASSERT("Error creating the passive child thread", 1);
407 CloseHandle(threadId
);
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
435 \brief Closes gracefully (more or less) the program.
437 This function is called:
438 - when we're running in console and are terminated with ^C;
439 - on UN*X, when we're terminated with SIGTERM.
441 static void main_terminate(int sign
)
443 SOCK_ASSERT(PROGRAM_NAME
" is closing.\n", 1);
447 // Sends a KILL signal to all the processes in this process's
448 // process group; i.e., it kills all the child processes
451 // XXX - that also includes us, so we will be killed as well;
452 // that may cause a message to be printed or logged.
458 // Just leave. We shouldn't need to clean up sockets or
459 // anything else, and if we try to do so, we'll could end
460 // up closing sockets, or shutting Winsock down, out from
461 // under service loops, causing all sorts of noisy error
464 // We shouldn't need to worry about cleaning up any resources
465 // such as handles, sockets, threads, etc. - exit() should
466 // terminate the process, causing all those resources to be
469 // Note that, on Windows, this will happen only for ^C, and
470 // thus will happen on a thread created to run the ^C handler,
471 // which is how it manages to cause the aforementioned service
472 // loop issues in service loops in other threads.
478 static void main_abort(int sign
)
480 SOCK_ASSERT(PROGRAM_NAME
" is closing due to a SIGABRT.\n", 1);
483 // XXX - there should be a way to poke the main thread to get
484 // it to shut down the service.
488 // Here we close only the latest 'sockmain' created; if we opened more than one waiting sockets,
489 // only the latest one is closed correctly.
491 closesocket(sockmain
);
495 * This is a Win32 service, so we're a child thread, and we want
496 * just to terminate ourself. This is because the exit(0) will
497 * be invoked by the main thread, which is blocked waiting that
498 * all childs terminates. We are forced to call exit from the
499 * main thread, otherwise the Win32 service control manager
500 * (SCM) does not work well.
506 static void main_reap_children(int sign
)
511 // Reap all child processes that have exited.
512 // For reference, Stevens, pg 128
514 while ((pid
= waitpid(-1, &stat
, WNOHANG
)) > 0)
515 SOCK_ASSERT("Child terminated", 1);
522 \brief 'true' main of the program.
524 It must be in a separate function because:
525 - if we're in 'console' mode, we have to put the main thread waiting for a Ctrl+C
526 (in order to be able to stop everything)
527 - if we're in daemon mode, the main program must terminate and a new child must be
528 created in order to create the daemon
530 \param ptr: it keeps the main socket handler (what's called
531 'sockmain' in the main()), that represents the socket used in
532 the main connection. It is a 'void *' just because the thread
533 APIs want this format.
536 static unsigned __stdcall
540 main_passive(void *ptr
)
542 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
543 SOCKET sockctrl
; // keeps the socket ID for this control connection
544 struct sockaddr_storage from
; // generic sockaddr_storage variable
545 socklen_t fromlen
; // keeps the length of the sockaddr_storage variable
552 sockmain
= *((SOCKET
*) ptr
);
554 // Delete the pointer (which has been allocated in the main)
558 memset(errbuf
, 0, sizeof(errbuf
));
564 HANDLE threadId
; // handle for the subthread
566 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
568 // Connection creation
569 fromlen
= sizeof(struct sockaddr_storage
);
571 sockctrl
= accept(sockmain
, (struct sockaddr
*) &from
, &fromlen
);
573 if (sockctrl
== INVALID_SOCKET
)
575 // The accept() call can return this error when a signal is catched
576 // In this case, we have simply to ignore this error code
579 if (WSAGetLastError() == WSAEINTR
)
585 // Don't check for errors here, since the error can be due to the fact that the thread
587 sock_geterror("accept(): ", errbuf
, PCAP_ERRBUF_SIZE
);
588 rpcapd_log(LOGPRIO_ERROR
, "Accept of control connection from client failed: %s",
593 // checks if the connecting host is among the ones allowed
594 if (sock_check_hostlist(hostlist
, RPCAP_HOSTLIST_SEP
, &from
, errbuf
, PCAP_ERRBUF_SIZE
) < 0)
596 rpcap_senderror(sockctrl
, 0, PCAP_ERR_HOSTNOAUTH
, errbuf
, NULL
);
597 sock_close(sockctrl
, NULL
, 0);
603 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
604 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
607 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
608 rpcap_senderror(sockctrl
, 0, PCAP_ERR_OPEN
, errbuf
, NULL
);
609 sock_close(sockctrl
, NULL
, 0);
613 pars
->sockctrl
= sockctrl
;
614 pars
->activeclose
= 0; // useless in passive mode
616 pars
->nullAuthAllowed
= nullAuthAllowed
;
618 threadId
= (HANDLE
)_beginthreadex(NULL
, 0, daemon_serviceloop
,
619 (void *) pars
, 0, NULL
);
622 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error creating the child thread");
623 rpcap_senderror(sockctrl
, 0, PCAP_ERR_OPEN
, errbuf
, NULL
);
624 sock_close(sockctrl
, NULL
, 0);
627 CloseHandle(threadId
);
629 if ((pid
= fork()) == 0) // I am the child
631 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
632 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
635 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
639 pars
->sockctrl
= sockctrl
;
640 pars
->activeclose
= 0; // useless in passive mode
642 pars
->nullAuthAllowed
= nullAuthAllowed
;
644 // Close the main socket (must be open only in the parent)
645 closesocket(sockmain
);
647 daemon_serviceloop((void *) pars
);
652 // Close the childsocket (must be open only in the child)
653 closesocket(sockctrl
);
656 // loop forever, until interrupted
662 \brief 'true' main of the program in case the active mode is turned on.
664 This function loops forever trying to connect to the remote host, until the
665 daemon is turned down.
667 \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
668 just because the thread APIs want this format.
671 static unsigned __stdcall
675 main_active(void *ptr
)
677 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
678 SOCKET sockctrl
; // keeps the socket ID for this control connection
679 struct addrinfo hints
; // temporary struct to keep settings needed to open the new socket
680 struct addrinfo
*addrinfo
; // keeps the addrinfo chain; required to open a new socket
681 struct active_pars
*activepars
;
682 struct daemon_slpars
*pars
; // parameters needed by the daemon_serviceloop()
684 activepars
= (struct active_pars
*) ptr
;
686 // Prepare to open a new server socket
687 memset(&hints
, 0, sizeof(struct addrinfo
));
688 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
689 hints
.ai_family
= AF_INET
; // PF_UNSPEC to have both IPv4 and IPv6 server
690 hints
.ai_socktype
= SOCK_STREAM
;
691 hints
.ai_family
= activepars
->ai_family
;
693 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Connecting to host %s, port %s, using protocol %s",
694 activepars
->address
, activepars
->port
, (hints
.ai_family
== AF_INET
) ? "IPv4":
695 (hints
.ai_family
== AF_INET6
) ? "IPv6" : "Unspecified");
696 SOCK_ASSERT(errbuf
, 1);
699 memset(errbuf
, 0, sizeof(errbuf
));
702 if (sock_initaddress(activepars
->address
, activepars
->port
, &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
704 SOCK_ASSERT(errbuf
, 1);
712 if ((sockctrl
= sock_open(addrinfo
, SOCKOPEN_CLIENT
, 0, errbuf
, PCAP_ERRBUF_SIZE
)) == INVALID_SOCKET
)
714 SOCK_ASSERT(errbuf
, 1);
716 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error 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");
720 SOCK_ASSERT(errbuf
, 1);
722 sleep_secs(RPCAP_ACTIVE_WAIT
);
727 pars
= (struct daemon_slpars
*) malloc (sizeof(struct daemon_slpars
));
730 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
734 pars
->sockctrl
= sockctrl
;
735 pars
->activeclose
= 0;
737 pars
->nullAuthAllowed
= nullAuthAllowed
;
739 daemon_serviceloop((void *) pars
);
741 activeclose
= pars
->activeclose
;
745 // If the connection is closed by the user explicitely, don't try to connect to it again
746 // just exit the program
747 if (activeclose
== 1)
751 freeaddrinfo(addrinfo
);