xref: /freebsd/contrib/libpcap/rpcapd/rpcapd.c (revision afdbf109c6a661a729938f68211054a0a50d38ac)
157e22627SCy Schubert /*
257e22627SCy Schubert  * Copyright (c) 2002 - 2003
357e22627SCy Schubert  * NetGroup, Politecnico di Torino (Italy)
457e22627SCy Schubert  * All rights reserved.
557e22627SCy Schubert  *
657e22627SCy Schubert  * Redistribution and use in source and binary forms, with or without
757e22627SCy Schubert  * modification, are permitted provided that the following conditions
857e22627SCy Schubert  * are met:
957e22627SCy Schubert  *
1057e22627SCy Schubert  * 1. Redistributions of source code must retain the above copyright
1157e22627SCy Schubert  * notice, this list of conditions and the following disclaimer.
1257e22627SCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
1357e22627SCy Schubert  * notice, this list of conditions and the following disclaimer in the
1457e22627SCy Schubert  * documentation and/or other materials provided with the distribution.
1557e22627SCy Schubert  * 3. Neither the name of the Politecnico di Torino nor the names of its
1657e22627SCy Schubert  * contributors may be used to endorse or promote products derived from
1757e22627SCy Schubert  * this software without specific prior written permission.
1857e22627SCy Schubert  *
1957e22627SCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2057e22627SCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2157e22627SCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2257e22627SCy Schubert  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2357e22627SCy Schubert  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2457e22627SCy Schubert  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2557e22627SCy Schubert  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2657e22627SCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2757e22627SCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2857e22627SCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2957e22627SCy Schubert  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3057e22627SCy Schubert  *
3157e22627SCy Schubert  */
3257e22627SCy Schubert 
3357e22627SCy Schubert #include <config.h>
3457e22627SCy Schubert 
3557e22627SCy Schubert #include "ftmacros.h"
366f9cba8fSJoseph Mingrone #include "diag-control.h"
3757e22627SCy Schubert 
3857e22627SCy Schubert #include <errno.h>		// for the errno variable
3957e22627SCy Schubert #include <string.h>		// for strtok, etc
4057e22627SCy Schubert #include <stdlib.h>		// for malloc(), free(), ...
416f9cba8fSJoseph Mingrone #include <stdio.h>		// for fprintf(), stderr, FILE etc
4257e22627SCy Schubert #include <pcap.h>		// for PCAP_ERRBUF_SIZE
4357e22627SCy Schubert #include <signal.h>		// for signal()
4457e22627SCy Schubert 
4557e22627SCy Schubert #include "fmtutils.h"
4657e22627SCy Schubert #include "sockutils.h"		// for socket calls
4757e22627SCy Schubert #include "varattrs.h"		// for _U_
4857e22627SCy Schubert #include "portability.h"
4957e22627SCy Schubert #include "rpcapd.h"
5057e22627SCy Schubert #include "config_params.h"	// configuration file parameters
5157e22627SCy Schubert #include "fileconf.h"		// for the configuration file management
5257e22627SCy Schubert #include "rpcap-protocol.h"
5357e22627SCy Schubert #include "daemon.h"		// the true main() method of this daemon
5457e22627SCy Schubert #include "log.h"
5557e22627SCy Schubert 
566f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
576f9cba8fSJoseph Mingrone #include "sslutils.h"
586f9cba8fSJoseph Mingrone #endif
596f9cba8fSJoseph Mingrone 
6057e22627SCy Schubert #ifdef _WIN32
6157e22627SCy Schubert   #include <process.h>		// for thread stuff
6257e22627SCy Schubert   #include "win32-svc.h"	// for Win32 service stuff
6357e22627SCy Schubert   #include "getopt.h"		// for getopt()-for-Windows
6457e22627SCy Schubert #else
6557e22627SCy Schubert   #include <fcntl.h>		// for open()
6657e22627SCy Schubert   #include <unistd.h>		// for exit()
6757e22627SCy Schubert   #include <sys/wait.h>		// waitpid()
6857e22627SCy Schubert #endif
6957e22627SCy Schubert 
7057e22627SCy Schubert //
7157e22627SCy Schubert // Element in list of sockets on which we're listening for connections.
7257e22627SCy Schubert //
7357e22627SCy Schubert struct listen_sock {
7457e22627SCy Schubert 	struct listen_sock *next;
75*afdbf109SJoseph Mingrone 	PCAP_SOCKET sock;
7657e22627SCy Schubert };
7757e22627SCy Schubert 
7857e22627SCy Schubert // Global variables
7957e22627SCy Schubert char hostlist[MAX_HOST_LIST + 1];		//!< Keeps the list of the hosts that are allowed to connect to this server
8057e22627SCy Schubert struct active_pars activelist[MAX_ACTIVE_LIST];	//!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
8157e22627SCy Schubert int nullAuthAllowed;				//!< '1' if we permit NULL authentication, '0' otherwise
8257e22627SCy Schubert static struct listen_sock *listen_socks;	//!< sockets on which we listen
8357e22627SCy Schubert char loadfile[MAX_LINE + 1];			//!< Name of the file from which we have to load the configuration
8457e22627SCy Schubert static int passivemode = 1;			//!< '1' if we want to run in passive mode as well
8557e22627SCy Schubert static struct addrinfo mainhints;		//!< temporary struct to keep settings needed to open the new socket
8657e22627SCy Schubert static char address[MAX_LINE + 1];		//!< keeps the network address (either numeric or literal) to bind to
8757e22627SCy Schubert static char port[MAX_LINE + 1];			//!< keeps the network port to bind to
8857e22627SCy Schubert #ifdef _WIN32
8957e22627SCy Schubert static HANDLE state_change_event;		//!< event to signal that a state change should take place
9057e22627SCy Schubert #endif
9157e22627SCy Schubert static volatile sig_atomic_t shutdown_server;	//!< '1' if the server is to shut down
9257e22627SCy Schubert static volatile sig_atomic_t reread_config;	//!< '1' if the server is to re-read its configuration
93*afdbf109SJoseph Mingrone static int uses_ssl;				//!< '1' to use TLS over TCP
9457e22627SCy Schubert 
9557e22627SCy Schubert extern char *optarg;	// for getopt()
9657e22627SCy Schubert 
9757e22627SCy Schubert // Function definition
9857e22627SCy Schubert #ifdef _WIN32
9957e22627SCy Schubert static unsigned __stdcall main_active(void *ptr);
10057e22627SCy Schubert static BOOL WINAPI main_ctrl_event(DWORD);
10157e22627SCy Schubert #else
10257e22627SCy Schubert static void *main_active(void *ptr);
10357e22627SCy Schubert static void main_terminate(int sign);
10457e22627SCy Schubert static void main_reread_config(int sign);
10557e22627SCy Schubert #endif
10657e22627SCy Schubert static void accept_connections(void);
107*afdbf109SJoseph Mingrone static void accept_connection(PCAP_SOCKET listen_sock);
10857e22627SCy Schubert #ifndef _WIN32
10957e22627SCy Schubert static void main_reap_children(int sign);
11057e22627SCy Schubert #endif
11157e22627SCy Schubert #ifdef _WIN32
11257e22627SCy Schubert static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
11357e22627SCy Schubert #endif
11457e22627SCy Schubert 
11557e22627SCy Schubert #define RPCAP_ACTIVE_WAIT 30		/* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
11657e22627SCy Schubert 
11757e22627SCy Schubert /*!
11857e22627SCy Schubert 	\brief Prints the usage screen if it is launched in console mode.
11957e22627SCy Schubert */
printusage(FILE * f)1206f9cba8fSJoseph Mingrone static void printusage(FILE * f)
12157e22627SCy Schubert {
12257e22627SCy Schubert 	const char *usagetext =
12357e22627SCy Schubert 	"USAGE:"
12457e22627SCy Schubert 	" "  PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
12557e22627SCy Schubert 	"              [-n] [-v] [-d] "
12657e22627SCy Schubert #ifndef _WIN32
12757e22627SCy Schubert 	"[-i] "
12857e22627SCy Schubert #endif
12957e22627SCy Schubert         "[-D] [-s <config_file>] [-f <config_file>]\n\n"
13057e22627SCy Schubert 	"  -b <address>    the address to bind to (either numeric or literal).\n"
13157e22627SCy Schubert 	"                  Default: binds to all local IPv4 and IPv6 addresses\n\n"
13257e22627SCy Schubert 	"  -p <port>       the port to bind to.\n"
13357e22627SCy Schubert 	"                  Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
13457e22627SCy Schubert 	"  -4              use only IPv4.\n"
13557e22627SCy Schubert 	"                  Default: use both IPv4 and IPv6 waiting sockets\n\n"
13657e22627SCy Schubert 	"  -l <host_list>  a file that contains a list of hosts that are allowed\n"
13757e22627SCy Schubert 	"                  to connect to this server (if more than one, list them one\n"
13857e22627SCy Schubert 	"                  per line).\n"
13957e22627SCy Schubert 	"                  We suggest to use literal names (instead of numeric ones)\n"
14057e22627SCy Schubert 	"                  in order to avoid problems with different address families.\n\n"
14157e22627SCy Schubert 	"  -n              permit NULL authentication (usually used with '-l')\n\n"
14257e22627SCy Schubert 	"  -a <host,port>  run in active mode when connecting to 'host' on port 'port'\n"
14357e22627SCy Schubert 	"                  In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
14457e22627SCy Schubert 	"  -v              run in active mode only (default: if '-a' is specified, it\n"
14557e22627SCy Schubert 	"                  accepts passive connections as well)\n\n"
14657e22627SCy Schubert 	"  -d              run in daemon mode (UNIX only) or as a service (Win32 only)\n"
14757e22627SCy Schubert 	"                  Warning (Win32): this switch is provided automatically when\n"
14857e22627SCy Schubert 	"                  the service is started from the control panel\n\n"
14957e22627SCy Schubert #ifndef _WIN32
15057e22627SCy Schubert 	"  -i              run in inetd mode (UNIX only)\n\n"
15157e22627SCy Schubert #endif
15257e22627SCy Schubert 	"  -D              log debugging messages\n\n"
1536f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
1546f9cba8fSJoseph Mingrone 	"  -S              encrypt all communication with SSL (implements rpcaps://)\n"
1556f9cba8fSJoseph Mingrone 	"  -C              enable compression\n"
1566f9cba8fSJoseph Mingrone 	"  -K <pem_file>   uses the SSL private key in this file (default: key.pem)\n"
1576f9cba8fSJoseph Mingrone 	"  -X <pem_file>   uses the certificate from this file (default: cert.pem)\n"
1586f9cba8fSJoseph Mingrone #endif
15957e22627SCy Schubert 	"  -s <config_file> save the current configuration to file\n\n"
16057e22627SCy Schubert 	"  -f <config_file> load the current configuration from file; all switches\n"
16157e22627SCy Schubert 	"                  specified from the command line are ignored\n\n"
16257e22627SCy Schubert 	"  -h              print this help screen\n\n";
16357e22627SCy Schubert 
1646f9cba8fSJoseph Mingrone 	(void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
1656f9cba8fSJoseph Mingrone 	"Compiled with %s\n", pcap_lib_version());
1666f9cba8fSJoseph Mingrone #if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
1676f9cba8fSJoseph Mingrone 	(void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
1686f9cba8fSJoseph Mingrone #endif
1696f9cba8fSJoseph Mingrone 	(void)fprintf(f, "\n%s", usagetext);
17057e22627SCy Schubert }
17157e22627SCy Schubert 
17257e22627SCy Schubert 
17357e22627SCy Schubert 
17457e22627SCy Schubert //! Program main
main(int argc,char * argv[])17557e22627SCy Schubert int main(int argc, char *argv[])
17657e22627SCy Schubert {
17757e22627SCy Schubert 	char savefile[MAX_LINE + 1];		// name of the file on which we have to save the configuration
17857e22627SCy Schubert 	int log_to_systemlog = 0;		// Non-zero if we should log to the "system log" rather than the standard error
17957e22627SCy Schubert 	int isdaemon = 0;			// Non-zero if the user wants to run this program as a daemon
18057e22627SCy Schubert #ifndef _WIN32
18157e22627SCy Schubert 	int isrunbyinetd = 0;			// Non-zero if this is being run by inetd or something inetd-like
18257e22627SCy Schubert #endif
18357e22627SCy Schubert 	int log_debug_messages = 0;		// Non-zero if the user wants debug messages logged
18457e22627SCy Schubert 	int retval;				// keeps the returning value from several functions
18557e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
18657e22627SCy Schubert #ifndef _WIN32
18757e22627SCy Schubert 	struct sigaction action;
18857e22627SCy Schubert #endif
1896f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
1906f9cba8fSJoseph Mingrone 	int enable_compression = 0;
1916f9cba8fSJoseph Mingrone #endif
19257e22627SCy Schubert 
19357e22627SCy Schubert 	savefile[0] = 0;
19457e22627SCy Schubert 	loadfile[0] = 0;
19557e22627SCy Schubert 	hostlist[0] = 0;
19657e22627SCy Schubert 
19757e22627SCy Schubert 	// Initialize errbuf
19857e22627SCy Schubert 	memset(errbuf, 0, sizeof(errbuf));
19957e22627SCy Schubert 
200*afdbf109SJoseph Mingrone 	pcapint_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
201*afdbf109SJoseph Mingrone 	pcapint_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
20257e22627SCy Schubert 
20357e22627SCy Schubert 	// Prepare to open a new server socket
20457e22627SCy Schubert 	memset(&mainhints, 0, sizeof(struct addrinfo));
20557e22627SCy Schubert 
20657e22627SCy Schubert 	mainhints.ai_family = PF_UNSPEC;
20757e22627SCy Schubert 	mainhints.ai_flags = AI_PASSIVE;	// Ready to a bind() socket
20857e22627SCy Schubert 	mainhints.ai_socktype = SOCK_STREAM;
20957e22627SCy Schubert 
21057e22627SCy Schubert 	// Getting the proper command line options
2116f9cba8fSJoseph Mingrone #	ifdef HAVE_OPENSSL
2126f9cba8fSJoseph Mingrone #		define SSL_CLOPTS  "SK:X:C"
2136f9cba8fSJoseph Mingrone #	else
2146f9cba8fSJoseph Mingrone #		define SSL_CLOPTS ""
2156f9cba8fSJoseph Mingrone #	endif
2166f9cba8fSJoseph Mingrone 
2176f9cba8fSJoseph Mingrone #	define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
2186f9cba8fSJoseph Mingrone 
2196f9cba8fSJoseph Mingrone 	while ((retval = getopt(argc, argv, CLOPTS)) != -1)
22057e22627SCy Schubert 	{
22157e22627SCy Schubert 		switch (retval)
22257e22627SCy Schubert 		{
22357e22627SCy Schubert 			case 'D':
22457e22627SCy Schubert 				log_debug_messages = 1;
22557e22627SCy Schubert 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
22657e22627SCy Schubert 				break;
22757e22627SCy Schubert 			case 'b':
228*afdbf109SJoseph Mingrone 				pcapint_strlcpy(address, optarg, sizeof (address));
22957e22627SCy Schubert 				break;
23057e22627SCy Schubert 			case 'p':
231*afdbf109SJoseph Mingrone 				pcapint_strlcpy(port, optarg, sizeof (port));
23257e22627SCy Schubert 				break;
23357e22627SCy Schubert 			case '4':
23457e22627SCy Schubert 				mainhints.ai_family = PF_INET;		// IPv4 server only
23557e22627SCy Schubert 				break;
23657e22627SCy Schubert 			case 'd':
23757e22627SCy Schubert 				isdaemon = 1;
23857e22627SCy Schubert 				log_to_systemlog = 1;
23957e22627SCy Schubert 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
24057e22627SCy Schubert 				break;
24157e22627SCy Schubert 			case 'i':
24257e22627SCy Schubert #ifdef _WIN32
2436f9cba8fSJoseph Mingrone 				printusage(stderr);
24457e22627SCy Schubert 				exit(1);
24557e22627SCy Schubert #else
24657e22627SCy Schubert 				isrunbyinetd = 1;
24757e22627SCy Schubert 				log_to_systemlog = 1;
24857e22627SCy Schubert 				rpcapd_log_set(log_to_systemlog, log_debug_messages);
24957e22627SCy Schubert #endif
25057e22627SCy Schubert 				break;
25157e22627SCy Schubert 			case 'n':
25257e22627SCy Schubert 				nullAuthAllowed = 1;
25357e22627SCy Schubert 				break;
25457e22627SCy Schubert 			case 'v':
25557e22627SCy Schubert 				passivemode = 0;
25657e22627SCy Schubert 				break;
25757e22627SCy Schubert 			case 'l':
25857e22627SCy Schubert 			{
259*afdbf109SJoseph Mingrone 				pcapint_strlcpy(hostlist, optarg, sizeof(hostlist));
26057e22627SCy Schubert 				break;
26157e22627SCy Schubert 			}
26257e22627SCy Schubert 			case 'a':
26357e22627SCy Schubert 			{
26457e22627SCy Schubert 				char *tmpaddress, *tmpport;
26557e22627SCy Schubert 				char *lasts;
26657e22627SCy Schubert 				int i = 0;
26757e22627SCy Schubert 
268*afdbf109SJoseph Mingrone 				tmpaddress = pcapint_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
26957e22627SCy Schubert 
27057e22627SCy Schubert 				while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
27157e22627SCy Schubert 				{
272*afdbf109SJoseph Mingrone 					tmpport = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
27357e22627SCy Schubert 
274*afdbf109SJoseph Mingrone 					pcapint_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
27557e22627SCy Schubert 
27657e22627SCy Schubert 					if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
277*afdbf109SJoseph Mingrone 						pcapint_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
27857e22627SCy Schubert 					else
279*afdbf109SJoseph Mingrone 						pcapint_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
28057e22627SCy Schubert 
281*afdbf109SJoseph Mingrone 					tmpaddress = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
28257e22627SCy Schubert 
28357e22627SCy Schubert 					i++;
28457e22627SCy Schubert 				}
28557e22627SCy Schubert 
28657e22627SCy Schubert 				if (i > MAX_ACTIVE_LIST)
28757e22627SCy Schubert 					rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
28857e22627SCy Schubert 
28957e22627SCy Schubert 				// I don't initialize the remaining part of the structure, since
29057e22627SCy Schubert 				// it is already zeroed (it is a global var)
29157e22627SCy Schubert 				break;
29257e22627SCy Schubert 			}
29357e22627SCy Schubert 			case 'f':
294*afdbf109SJoseph Mingrone 				pcapint_strlcpy(loadfile, optarg, sizeof (loadfile));
29557e22627SCy Schubert 				break;
29657e22627SCy Schubert 			case 's':
297*afdbf109SJoseph Mingrone 				pcapint_strlcpy(savefile, optarg, sizeof (savefile));
29857e22627SCy Schubert 				break;
2996f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
3006f9cba8fSJoseph Mingrone 			case 'S':
3016f9cba8fSJoseph Mingrone 				uses_ssl = 1;
3026f9cba8fSJoseph Mingrone 				break;
3036f9cba8fSJoseph Mingrone 			case 'C':
3046f9cba8fSJoseph Mingrone 				enable_compression = 1;
3056f9cba8fSJoseph Mingrone 				break;
3066f9cba8fSJoseph Mingrone 			case 'K':
3076f9cba8fSJoseph Mingrone 				ssl_set_keyfile(optarg);
3086f9cba8fSJoseph Mingrone 				break;
3096f9cba8fSJoseph Mingrone 			case 'X':
3106f9cba8fSJoseph Mingrone 				ssl_set_certfile(optarg);
3116f9cba8fSJoseph Mingrone 				break;
3126f9cba8fSJoseph Mingrone #endif
31357e22627SCy Schubert 			case 'h':
3146f9cba8fSJoseph Mingrone 				printusage(stdout);
31557e22627SCy Schubert 				exit(0);
31657e22627SCy Schubert 				/*NOTREACHED*/
31757e22627SCy Schubert 			default:
31857e22627SCy Schubert 				exit(1);
31957e22627SCy Schubert 				/*NOTREACHED*/
32057e22627SCy Schubert 		}
32157e22627SCy Schubert 	}
32257e22627SCy Schubert 
32357e22627SCy Schubert #ifndef _WIN32
32457e22627SCy Schubert 	if (isdaemon && isrunbyinetd)
32557e22627SCy Schubert 	{
32657e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
32757e22627SCy Schubert 		exit(1);
32857e22627SCy Schubert 	}
32957e22627SCy Schubert #endif
33057e22627SCy Schubert 
3316f9cba8fSJoseph Mingrone 	//
3326f9cba8fSJoseph Mingrone 	// We want UTF-8 error messages.
3336f9cba8fSJoseph Mingrone 	//
3346f9cba8fSJoseph Mingrone 	if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
3356f9cba8fSJoseph Mingrone 	{
3366f9cba8fSJoseph Mingrone 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3376f9cba8fSJoseph Mingrone 		exit(-1);
3386f9cba8fSJoseph Mingrone 	}
339*afdbf109SJoseph Mingrone 	pcapint_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
3406f9cba8fSJoseph Mingrone 
34157e22627SCy Schubert 	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
34257e22627SCy Schubert 	{
34357e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
34457e22627SCy Schubert 		exit(-1);
34557e22627SCy Schubert 	}
34657e22627SCy Schubert 
34757e22627SCy Schubert 	if (savefile[0] && fileconf_save(savefile))
34857e22627SCy Schubert 		rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
34957e22627SCy Schubert 
35057e22627SCy Schubert 	// If the file does not exist, it keeps the settings provided by the command line
35157e22627SCy Schubert 	if (loadfile[0])
35257e22627SCy Schubert 		fileconf_read();
35357e22627SCy Schubert 
3546f9cba8fSJoseph Mingrone #ifdef _WIN32
35557e22627SCy Schubert 	//
35657e22627SCy Schubert 	// Create a handle to signal the main loop to tell it to do
35757e22627SCy Schubert 	// something.
35857e22627SCy Schubert 	//
35957e22627SCy Schubert 	state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
36057e22627SCy Schubert 	if (state_change_event == NULL)
36157e22627SCy Schubert 	{
3626f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
3636f9cba8fSJoseph Mingrone 		    "Can't create state change event");
36457e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
36557e22627SCy Schubert 		exit(2);
36657e22627SCy Schubert 	}
36757e22627SCy Schubert 
36857e22627SCy Schubert 	//
36957e22627SCy Schubert 	// Catch control signals.
37057e22627SCy Schubert 	//
37157e22627SCy Schubert 	if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
37257e22627SCy Schubert 	{
3736f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
3746f9cba8fSJoseph Mingrone 		    "Can't set control handler");
37557e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
37657e22627SCy Schubert 		exit(2);
37757e22627SCy Schubert 	}
37857e22627SCy Schubert #else
37957e22627SCy Schubert 	memset(&action, 0, sizeof (action));
38057e22627SCy Schubert 	action.sa_handler = main_terminate;
38157e22627SCy Schubert 	action.sa_flags = 0;
38257e22627SCy Schubert 	sigemptyset(&action.sa_mask);
38357e22627SCy Schubert 	sigaction(SIGTERM, &action, NULL);
38457e22627SCy Schubert 	memset(&action, 0, sizeof (action));
38557e22627SCy Schubert 	action.sa_handler = main_reap_children;
38657e22627SCy Schubert 	action.sa_flags = 0;
38757e22627SCy Schubert 	sigemptyset(&action.sa_mask);
38857e22627SCy Schubert 	sigaction(SIGCHLD, &action, NULL);
38957e22627SCy Schubert 	// Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
39057e22627SCy Schubert 	// connection, we don't want to get killed by a signal in that case
391*afdbf109SJoseph Mingrone #ifdef __illumos__
392*afdbf109SJoseph Mingrone 	DIAG_OFF_STRICT_PROTOTYPES
393*afdbf109SJoseph Mingrone #endif /* __illumos__ */
39457e22627SCy Schubert 	signal(SIGPIPE, SIG_IGN);
395*afdbf109SJoseph Mingrone #ifdef __illumos__
396*afdbf109SJoseph Mingrone 	DIAG_ON_STRICT_PROTOTYPES
397*afdbf109SJoseph Mingrone #endif /* __illumos__ */
39857e22627SCy Schubert #endif
39957e22627SCy Schubert 
4006f9cba8fSJoseph Mingrone # ifdef HAVE_OPENSSL
4016f9cba8fSJoseph Mingrone 	if (uses_ssl) {
4026f9cba8fSJoseph Mingrone 		if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
4036f9cba8fSJoseph Mingrone 		{
4046f9cba8fSJoseph Mingrone 			rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
4056f9cba8fSJoseph Mingrone 			    errbuf);
4066f9cba8fSJoseph Mingrone 			exit(2);
4076f9cba8fSJoseph Mingrone 		}
4086f9cba8fSJoseph Mingrone 	}
4096f9cba8fSJoseph Mingrone # endif
4106f9cba8fSJoseph Mingrone 
41157e22627SCy Schubert #ifndef _WIN32
41257e22627SCy Schubert 	if (isrunbyinetd)
41357e22627SCy Schubert 	{
41457e22627SCy Schubert 		//
41557e22627SCy Schubert 		// -i was specified, indicating that this is being run
41657e22627SCy Schubert 		// by inetd or something that can run network daemons
41757e22627SCy Schubert 		// as if it were inetd (xinetd, launchd, systemd, etc.).
41857e22627SCy Schubert 		//
41957e22627SCy Schubert 		// We assume that the program that launched us just
42057e22627SCy Schubert 		// duplicated a single socket for the connection
42157e22627SCy Schubert 		// to our standard input, output, and error, so we
42257e22627SCy Schubert 		// can just use the standard input as our control
42357e22627SCy Schubert 		// socket.
42457e22627SCy Schubert 		//
42557e22627SCy Schubert 		int sockctrl;
42657e22627SCy Schubert 		int devnull_fd;
42757e22627SCy Schubert 
42857e22627SCy Schubert 		//
42957e22627SCy Schubert 		// Duplicate the standard input as the control socket.
43057e22627SCy Schubert 		//
43157e22627SCy Schubert 		sockctrl = dup(0);
43257e22627SCy Schubert 		if (sockctrl == -1)
43357e22627SCy Schubert 		{
4346f9cba8fSJoseph Mingrone 			sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
4356f9cba8fSJoseph Mingrone 			    "Can't dup standard input");
43657e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
43757e22627SCy Schubert 			exit(2);
43857e22627SCy Schubert 		}
43957e22627SCy Schubert 
44057e22627SCy Schubert 		//
44157e22627SCy Schubert 		// Try to set the standard input, output, and error
44257e22627SCy Schubert 		// to /dev/null.
44357e22627SCy Schubert 		//
44457e22627SCy Schubert 		devnull_fd = open("/dev/null", O_RDWR);
44557e22627SCy Schubert 		if (devnull_fd != -1)
44657e22627SCy Schubert 		{
44757e22627SCy Schubert 			//
44857e22627SCy Schubert 			// If this fails, just drive on.
44957e22627SCy Schubert 			//
45057e22627SCy Schubert 			(void)dup2(devnull_fd, 0);
45157e22627SCy Schubert 			(void)dup2(devnull_fd, 1);
45257e22627SCy Schubert 			(void)dup2(devnull_fd, 2);
45357e22627SCy Schubert 			close(devnull_fd);
45457e22627SCy Schubert 		}
45557e22627SCy Schubert 
45657e22627SCy Schubert 		//
45757e22627SCy Schubert 		// Handle this client.
45857e22627SCy Schubert 		// This is passive mode, so we don't care whether we were
45957e22627SCy Schubert 		// told by the client to close.
46057e22627SCy Schubert 		//
46157e22627SCy Schubert 		char *hostlist_copy = strdup(hostlist);
46257e22627SCy Schubert 		if (hostlist_copy == NULL)
46357e22627SCy Schubert 		{
46457e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
46557e22627SCy Schubert 			exit(0);
46657e22627SCy Schubert 		}
46757e22627SCy Schubert 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
4686f9cba8fSJoseph Mingrone 		    nullAuthAllowed, uses_ssl);
46957e22627SCy Schubert 
47057e22627SCy Schubert 		//
47157e22627SCy Schubert 		// Nothing more to do.
47257e22627SCy Schubert 		//
47357e22627SCy Schubert 		exit(0);
47457e22627SCy Schubert 	}
47557e22627SCy Schubert #endif
47657e22627SCy Schubert 
47757e22627SCy Schubert 	if (isdaemon)
47857e22627SCy Schubert 	{
47957e22627SCy Schubert 		//
48057e22627SCy Schubert 		// This is being run as a daemon.
48157e22627SCy Schubert 		// On UN*X, it might be manually run, or run from an
48257e22627SCy Schubert 		// rc file.
48357e22627SCy Schubert 		//
48457e22627SCy Schubert #ifndef _WIN32
48557e22627SCy Schubert 		int pid;
48657e22627SCy Schubert 
48757e22627SCy Schubert 		//
48857e22627SCy Schubert 		// Daemonize ourselves.
48957e22627SCy Schubert 		//
49057e22627SCy Schubert 		// Unix Network Programming, pg 336
49157e22627SCy Schubert 		//
49257e22627SCy Schubert 		if ((pid = fork()) != 0)
49357e22627SCy Schubert 			exit(0);		// Parent terminates
49457e22627SCy Schubert 
49557e22627SCy Schubert 		// First child continues
49657e22627SCy Schubert 		// Set daemon mode
49757e22627SCy Schubert 		setsid();
49857e22627SCy Schubert 
49957e22627SCy Schubert 		// generated under unix with 'kill -HUP', needed to reload the configuration
50057e22627SCy Schubert 		memset(&action, 0, sizeof (action));
50157e22627SCy Schubert 		action.sa_handler = main_reread_config;
50257e22627SCy Schubert 		action.sa_flags = 0;
50357e22627SCy Schubert 		sigemptyset(&action.sa_mask);
50457e22627SCy Schubert 		sigaction(SIGHUP, &action, NULL);
50557e22627SCy Schubert 
50657e22627SCy Schubert 		if ((pid = fork()) != 0)
50757e22627SCy Schubert 			exit(0);		// First child terminates
50857e22627SCy Schubert 
50957e22627SCy Schubert 		// LINUX WARNING: the current linux implementation of pthreads requires a management thread
51057e22627SCy Schubert 		// to handle some hidden stuff. So, as soon as you create the first thread, two threads are
5116f9cba8fSJoseph Mingrone 		// created. From this point on, the number of threads active are always one more compared
51257e22627SCy Schubert 		// to the number you're expecting
51357e22627SCy Schubert 
51457e22627SCy Schubert 		// Second child continues
51557e22627SCy Schubert //		umask(0);
51657e22627SCy Schubert //		chdir("/");
51757e22627SCy Schubert #else
51857e22627SCy Schubert 		//
51957e22627SCy Schubert 		// This is being run as a service on Windows.
52057e22627SCy Schubert 		//
52157e22627SCy Schubert 		// If this call succeeds, it is blocking on Win32
52257e22627SCy Schubert 		//
5236f9cba8fSJoseph Mingrone 		if (!svc_start())
52457e22627SCy Schubert 			rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
52557e22627SCy Schubert 
52657e22627SCy Schubert 		// When the previous call returns, the entire application has to be stopped.
52757e22627SCy Schubert 		exit(0);
52857e22627SCy Schubert #endif
52957e22627SCy Schubert 	}
53057e22627SCy Schubert 	else	// Console mode
53157e22627SCy Schubert 	{
53257e22627SCy Schubert #ifndef _WIN32
53357e22627SCy Schubert 		// Enable the catching of Ctrl+C
53457e22627SCy Schubert 		memset(&action, 0, sizeof (action));
53557e22627SCy Schubert 		action.sa_handler = main_terminate;
53657e22627SCy Schubert 		action.sa_flags = 0;
53757e22627SCy Schubert 		sigemptyset(&action.sa_mask);
53857e22627SCy Schubert 		sigaction(SIGINT, &action, NULL);
53957e22627SCy Schubert 
54057e22627SCy Schubert 		// generated under unix with 'kill -HUP', needed to reload the configuration
54157e22627SCy Schubert 		// We do not have this kind of signal in Win32
54257e22627SCy Schubert 		memset(&action, 0, sizeof (action));
54357e22627SCy Schubert 		action.sa_handler = main_reread_config;
54457e22627SCy Schubert 		action.sa_flags = 0;
54557e22627SCy Schubert 		sigemptyset(&action.sa_mask);
54657e22627SCy Schubert 		sigaction(SIGHUP, &action, NULL);
54757e22627SCy Schubert #endif
54857e22627SCy Schubert 
54957e22627SCy Schubert 		printf("Press CTRL + C to stop the server...\n");
55057e22627SCy Schubert 	}
55157e22627SCy Schubert 
55257e22627SCy Schubert 	// If we're a Win32 service, we have already called this function in the service_main
55357e22627SCy Schubert 	main_startup();
55457e22627SCy Schubert 
55557e22627SCy Schubert 	// The code should never arrive here (since the main_startup is blocking)
55657e22627SCy Schubert 	//  however this avoids a compiler warning
55757e22627SCy Schubert 	exit(0);
55857e22627SCy Schubert }
55957e22627SCy Schubert 
main_startup(void)56057e22627SCy Schubert void main_startup(void)
56157e22627SCy Schubert {
56257e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
56357e22627SCy Schubert 	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
56457e22627SCy Schubert 	int i;
56557e22627SCy Schubert #ifdef _WIN32
56657e22627SCy Schubert 	HANDLE threadId;			// handle for the subthread
56757e22627SCy Schubert #else
56857e22627SCy Schubert 	pid_t pid;
56957e22627SCy Schubert #endif
57057e22627SCy Schubert 
57157e22627SCy Schubert 	i = 0;
57257e22627SCy Schubert 	addrinfo = NULL;
57357e22627SCy Schubert 	memset(errbuf, 0, sizeof(errbuf));
57457e22627SCy Schubert 
57557e22627SCy Schubert 	// Starts all the active threads
57657e22627SCy Schubert 	while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
57757e22627SCy Schubert 	{
57857e22627SCy Schubert 		activelist[i].ai_family = mainhints.ai_family;
57957e22627SCy Schubert 
58057e22627SCy Schubert #ifdef _WIN32
58157e22627SCy Schubert 		threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
58257e22627SCy Schubert 		    (void *)&activelist[i], 0, NULL);
58357e22627SCy Schubert 		if (threadId == 0)
58457e22627SCy Schubert 		{
58557e22627SCy Schubert 			rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
58657e22627SCy Schubert 			continue;
58757e22627SCy Schubert 		}
58857e22627SCy Schubert 		CloseHandle(threadId);
58957e22627SCy Schubert #else
59057e22627SCy Schubert 		if ((pid = fork()) == 0)	// I am the child
59157e22627SCy Schubert 		{
59257e22627SCy Schubert 			main_active((void *) &activelist[i]);
59357e22627SCy Schubert 			exit(0);
59457e22627SCy Schubert 		}
59557e22627SCy Schubert #endif
59657e22627SCy Schubert 		i++;
59757e22627SCy Schubert 	}
59857e22627SCy Schubert 
59957e22627SCy Schubert 	/*
60057e22627SCy Schubert 	 * The code that manages the active connections is not blocking;
60157e22627SCy Schubert 	 * the code that manages the passive connection is blocking.
60257e22627SCy Schubert 	 * So, if the user does not want to run in passive mode, we have
60357e22627SCy Schubert 	 * to block the main thread here, otherwise the program ends and
60457e22627SCy Schubert 	 * all threads are stopped.
60557e22627SCy Schubert 	 *
60657e22627SCy Schubert 	 * WARNING: this means that in case we have only active mode,
60757e22627SCy Schubert 	 * the program does not terminate even if all the child thread
60857e22627SCy Schubert 	 * terminates. The user has always to press Ctrl+C (or send a
60957e22627SCy Schubert 	 * SIGTERM) to terminate the program.
61057e22627SCy Schubert 	 */
61157e22627SCy Schubert 	if (passivemode)
61257e22627SCy Schubert 	{
61357e22627SCy Schubert 		struct addrinfo *tempaddrinfo;
61457e22627SCy Schubert 
61557e22627SCy Schubert 		//
61657e22627SCy Schubert 		// Get a list of sockets on which to listen.
61757e22627SCy Schubert 		//
618*afdbf109SJoseph Mingrone 		addrinfo = sock_initaddress((address[0]) ? address : NULL,
619*afdbf109SJoseph Mingrone 		    port, &mainhints, errbuf, PCAP_ERRBUF_SIZE);
620*afdbf109SJoseph Mingrone 		if (addrinfo == NULL)
62157e22627SCy Schubert 		{
62257e22627SCy Schubert 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
62357e22627SCy Schubert 			return;
62457e22627SCy Schubert 		}
62557e22627SCy Schubert 
62657e22627SCy Schubert 		for (tempaddrinfo = addrinfo; tempaddrinfo;
62757e22627SCy Schubert 		     tempaddrinfo = tempaddrinfo->ai_next)
62857e22627SCy Schubert 		{
629*afdbf109SJoseph Mingrone 			PCAP_SOCKET sock;
63057e22627SCy Schubert 			struct listen_sock *sock_info;
63157e22627SCy Schubert 
6326f9cba8fSJoseph Mingrone 			if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
63357e22627SCy Schubert 			{
63457e22627SCy Schubert 				switch (tempaddrinfo->ai_family)
63557e22627SCy Schubert 				{
63657e22627SCy Schubert 				case AF_INET:
63757e22627SCy Schubert 				{
63857e22627SCy Schubert 					struct sockaddr_in *in;
63957e22627SCy Schubert 					char addrbuf[INET_ADDRSTRLEN];
64057e22627SCy Schubert 
64157e22627SCy Schubert 					in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
64257e22627SCy Schubert 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
64357e22627SCy Schubert 					    inet_ntop(AF_INET, &in->sin_addr,
64457e22627SCy Schubert 						addrbuf, sizeof (addrbuf)),
64557e22627SCy Schubert 					    ntohs(in->sin_port),
64657e22627SCy Schubert 					    errbuf);
64757e22627SCy Schubert 					break;
64857e22627SCy Schubert 				}
64957e22627SCy Schubert 
65057e22627SCy Schubert 				case AF_INET6:
65157e22627SCy Schubert 				{
65257e22627SCy Schubert 					struct sockaddr_in6 *in6;
65357e22627SCy Schubert 					char addrbuf[INET6_ADDRSTRLEN];
65457e22627SCy Schubert 
65557e22627SCy Schubert 					in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
65657e22627SCy Schubert 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
65757e22627SCy Schubert 					    inet_ntop(AF_INET6, &in6->sin6_addr,
65857e22627SCy Schubert 						addrbuf, sizeof (addrbuf)),
65957e22627SCy Schubert 					    ntohs(in6->sin6_port),
66057e22627SCy Schubert 					    errbuf);
66157e22627SCy Schubert 					break;
66257e22627SCy Schubert 				}
66357e22627SCy Schubert 
66457e22627SCy Schubert 				default:
66557e22627SCy Schubert 					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
66657e22627SCy Schubert 					    tempaddrinfo->ai_family,
66757e22627SCy Schubert 					    errbuf);
66857e22627SCy Schubert 					break;
66957e22627SCy Schubert 				}
67057e22627SCy Schubert 				continue;
67157e22627SCy Schubert 			}
67257e22627SCy Schubert 
67357e22627SCy Schubert 			sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
67457e22627SCy Schubert 			if (sock_info == NULL)
67557e22627SCy Schubert 			{
67657e22627SCy Schubert 				rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
67757e22627SCy Schubert 				exit(2);
67857e22627SCy Schubert 			}
67957e22627SCy Schubert 			sock_info->sock = sock;
68057e22627SCy Schubert 			sock_info->next = listen_socks;
68157e22627SCy Schubert 			listen_socks = sock_info;
68257e22627SCy Schubert 		}
68357e22627SCy Schubert 
68457e22627SCy Schubert 		freeaddrinfo(addrinfo);
68557e22627SCy Schubert 
68657e22627SCy Schubert 		if (listen_socks == NULL)
68757e22627SCy Schubert 		{
68857e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
68957e22627SCy Schubert 			exit(2);
69057e22627SCy Schubert 		}
69157e22627SCy Schubert 
69257e22627SCy Schubert 		//
69357e22627SCy Schubert 		// Now listen on all of them, waiting for connections.
69457e22627SCy Schubert 		//
69557e22627SCy Schubert 		accept_connections();
69657e22627SCy Schubert 	}
69757e22627SCy Schubert 
69857e22627SCy Schubert 	//
69957e22627SCy Schubert 	// We're done; exit.
70057e22627SCy Schubert 	//
70157e22627SCy Schubert 	rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
70257e22627SCy Schubert 
70357e22627SCy Schubert #ifndef _WIN32
70457e22627SCy Schubert 	//
70557e22627SCy Schubert 	// Sends a KILL signal to all the processes in this process's
70657e22627SCy Schubert 	// process group; i.e., it kills all the child processes
70757e22627SCy Schubert 	// we've created.
70857e22627SCy Schubert 	//
70957e22627SCy Schubert 	// XXX - that also includes us, so we will be killed as well;
71057e22627SCy Schubert 	// that may cause a message to be printed or logged.
71157e22627SCy Schubert 	//
71257e22627SCy Schubert 	kill(0, SIGKILL);
71357e22627SCy Schubert #endif
71457e22627SCy Schubert 
71557e22627SCy Schubert 	//
71657e22627SCy Schubert 	// Just leave.  We shouldn't need to clean up sockets or
71757e22627SCy Schubert 	// anything else, and if we try to do so, we'll could end
71857e22627SCy Schubert 	// up closing sockets, or shutting Winsock down, out from
71957e22627SCy Schubert 	// under service loops, causing all sorts of noisy error
72057e22627SCy Schubert 	// messages.
72157e22627SCy Schubert 	//
72257e22627SCy Schubert 	// We shouldn't need to worry about cleaning up any resources
72357e22627SCy Schubert 	// such as handles, sockets, threads, etc. - exit() should
72457e22627SCy Schubert 	// terminate the process, causing all those resources to be
72557e22627SCy Schubert 	// cleaned up (including the threads; Microsoft claims in the
72657e22627SCy Schubert 	// ExitProcess() documentation that, if ExitProcess() is called,
72757e22627SCy Schubert 	// "If a thread is waiting on a kernel object, it will not be
72857e22627SCy Schubert 	// terminated until the wait has completed.", but claims in the
72957e22627SCy Schubert 	// _beginthread()/_beginthreadex() documentation that "All threads
73057e22627SCy Schubert 	// are terminated if any thread calls abort, exit, _exit, or
73157e22627SCy Schubert 	// ExitProcess." - the latter appears to be the case, even for
73257e22627SCy Schubert 	// threads waiting on the event for a pcap_t).
73357e22627SCy Schubert 	//
73457e22627SCy Schubert 	exit(0);
73557e22627SCy Schubert }
73657e22627SCy Schubert 
73757e22627SCy Schubert #ifdef _WIN32
73857e22627SCy Schubert static void
send_state_change_event(void)73957e22627SCy Schubert send_state_change_event(void)
74057e22627SCy Schubert {
74157e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
74257e22627SCy Schubert 
74357e22627SCy Schubert 	if (!SetEvent(state_change_event))
74457e22627SCy Schubert 	{
7456f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
7466f9cba8fSJoseph Mingrone 		    "SetEvent on shutdown event failed");
74757e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
74857e22627SCy Schubert 	}
74957e22627SCy Schubert }
75057e22627SCy Schubert 
75157e22627SCy Schubert void
send_shutdown_notification(void)75257e22627SCy Schubert send_shutdown_notification(void)
75357e22627SCy Schubert {
75457e22627SCy Schubert 	//
75557e22627SCy Schubert 	// Indicate that the server should shut down.
75657e22627SCy Schubert 	//
75757e22627SCy Schubert 	shutdown_server = 1;
75857e22627SCy Schubert 
75957e22627SCy Schubert 	//
76057e22627SCy Schubert 	// Send a state change event, to wake up WSAWaitForMultipleEvents().
76157e22627SCy Schubert 	//
76257e22627SCy Schubert 	send_state_change_event();
76357e22627SCy Schubert }
76457e22627SCy Schubert 
76557e22627SCy Schubert void
send_reread_configuration_notification(void)76657e22627SCy Schubert send_reread_configuration_notification(void)
76757e22627SCy Schubert {
76857e22627SCy Schubert 	//
76957e22627SCy Schubert 	// Indicate that the server should re-read its configuration file.
77057e22627SCy Schubert 	//
77157e22627SCy Schubert 	reread_config = 1;
77257e22627SCy Schubert 
77357e22627SCy Schubert 	//
77457e22627SCy Schubert 	// Send a state change event, to wake up WSAWaitForMultipleEvents().
77557e22627SCy Schubert 	//
77657e22627SCy Schubert 	send_state_change_event();
77757e22627SCy Schubert }
77857e22627SCy Schubert 
main_ctrl_event(DWORD ctrltype)77957e22627SCy Schubert static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
78057e22627SCy Schubert {
78157e22627SCy Schubert 	//
78257e22627SCy Schubert 	// ctrltype is one of:
78357e22627SCy Schubert 	//
78457e22627SCy Schubert 	// CTRL_C_EVENT - we got a ^C; this is like SIGINT
78557e22627SCy Schubert 	// CTRL_BREAK_EVENT - we got Ctrl+Break
78657e22627SCy Schubert 	// CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
78757e22627SCy Schubert 	// CTRL_LOGOFF_EVENT - a user is logging off; this is received
78857e22627SCy Schubert 	//   only by services
78957e22627SCy Schubert 	// CTRL_SHUTDOWN_EVENT - the system is shutting down; this is
79057e22627SCy Schubert 	//   received only by services
79157e22627SCy Schubert 	//
79257e22627SCy Schubert 	// For now, we treat all but CTRL_LOGOFF_EVENT as indications
79357e22627SCy Schubert 	// that we should shut down.
79457e22627SCy Schubert 	//
79557e22627SCy Schubert 	switch (ctrltype)
79657e22627SCy Schubert 	{
79757e22627SCy Schubert 		case CTRL_C_EVENT:
79857e22627SCy Schubert 		case CTRL_BREAK_EVENT:
79957e22627SCy Schubert 		case CTRL_CLOSE_EVENT:
80057e22627SCy Schubert 		case CTRL_SHUTDOWN_EVENT:
80157e22627SCy Schubert 			//
80257e22627SCy Schubert 			// Set a shutdown notification.
80357e22627SCy Schubert 			//
80457e22627SCy Schubert 			send_shutdown_notification();
80557e22627SCy Schubert 			break;
80657e22627SCy Schubert 
80757e22627SCy Schubert 		default:
80857e22627SCy Schubert 			break;
80957e22627SCy Schubert 	}
81057e22627SCy Schubert 
81157e22627SCy Schubert 	//
81257e22627SCy Schubert 	// We handled this.
81357e22627SCy Schubert 	//
81457e22627SCy Schubert 	return TRUE;
81557e22627SCy Schubert }
81657e22627SCy Schubert #else
main_terminate(int sign _U_)81757e22627SCy Schubert static void main_terminate(int sign _U_)
81857e22627SCy Schubert {
81957e22627SCy Schubert 	//
82057e22627SCy Schubert 	// Note that the server should shut down.
82157e22627SCy Schubert 	// select() should get an EINTR error when we return,
82257e22627SCy Schubert 	// so it will wake up and know it needs to check the flag.
82357e22627SCy Schubert 	//
82457e22627SCy Schubert 	shutdown_server = 1;
82557e22627SCy Schubert }
82657e22627SCy Schubert 
main_reread_config(int sign _U_)82757e22627SCy Schubert static void main_reread_config(int sign _U_)
82857e22627SCy Schubert {
82957e22627SCy Schubert 	//
83057e22627SCy Schubert 	// Note that the server should re-read its configuration file.
83157e22627SCy Schubert 	// select() should get an EINTR error when we return,
83257e22627SCy Schubert 	// so it will wake up and know it needs to check the flag.
83357e22627SCy Schubert 	//
83457e22627SCy Schubert 	reread_config = 1;
83557e22627SCy Schubert }
83657e22627SCy Schubert 
main_reap_children(int sign _U_)83757e22627SCy Schubert static void main_reap_children(int sign _U_)
83857e22627SCy Schubert {
83957e22627SCy Schubert 	pid_t pid;
84057e22627SCy Schubert 	int exitstat;
84157e22627SCy Schubert 
84257e22627SCy Schubert 	// Reap all child processes that have exited.
84357e22627SCy Schubert 	// For reference, Stevens, pg 128
84457e22627SCy Schubert 
84557e22627SCy Schubert 	while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
84657e22627SCy Schubert 		rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
84757e22627SCy Schubert 
84857e22627SCy Schubert 	return;
84957e22627SCy Schubert }
85057e22627SCy Schubert #endif
85157e22627SCy Schubert 
85257e22627SCy Schubert //
85357e22627SCy Schubert // Loop waiting for incoming connections and accepting them.
85457e22627SCy Schubert //
85557e22627SCy Schubert static void
accept_connections(void)85657e22627SCy Schubert accept_connections(void)
85757e22627SCy Schubert {
85857e22627SCy Schubert #ifdef _WIN32
85957e22627SCy Schubert 	struct listen_sock *sock_info;
86057e22627SCy Schubert 	DWORD num_events;
86157e22627SCy Schubert 	WSAEVENT *events;
86257e22627SCy Schubert 	int i;
86357e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
86457e22627SCy Schubert 
86557e22627SCy Schubert 	//
86657e22627SCy Schubert 	// How big does the set of events need to be?
86757e22627SCy Schubert 	// One for the shutdown event, plus one for every socket on which
86857e22627SCy Schubert 	// we'll be listening.
86957e22627SCy Schubert 	//
87057e22627SCy Schubert 	num_events = 1;		// shutdown event
87157e22627SCy Schubert 	for (sock_info = listen_socks; sock_info;
87257e22627SCy Schubert 	    sock_info = sock_info->next)
87357e22627SCy Schubert 	{
87457e22627SCy Schubert 		if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
87557e22627SCy Schubert 		{
87657e22627SCy Schubert 			//
87757e22627SCy Schubert 			// WSAWaitForMultipleEvents() doesn't support
87857e22627SCy Schubert 			// more than WSA_MAXIMUM_WAIT_EVENTS events
87957e22627SCy Schubert 			// on which to wait.
88057e22627SCy Schubert 			//
88157e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
88257e22627SCy Schubert 			exit(2);
88357e22627SCy Schubert 		}
88457e22627SCy Schubert 		num_events++;
88557e22627SCy Schubert 	}
88657e22627SCy Schubert 
88757e22627SCy Schubert 	//
88857e22627SCy Schubert 	// Allocate the array of events.
88957e22627SCy Schubert 	//
89057e22627SCy Schubert 	events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
89157e22627SCy Schubert 	if (events == NULL)
89257e22627SCy Schubert 	{
89357e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
89457e22627SCy Schubert 		exit(2);
89557e22627SCy Schubert 	}
89657e22627SCy Schubert 
89757e22627SCy Schubert 	//
89857e22627SCy Schubert 	// Fill it in.
89957e22627SCy Schubert 	//
90057e22627SCy Schubert 	events[0] = state_change_event;	// state change event first
90157e22627SCy Schubert 	for (sock_info = listen_socks, i = 1; sock_info;
90257e22627SCy Schubert 	    sock_info = sock_info->next, i++)
90357e22627SCy Schubert 	{
90457e22627SCy Schubert 		WSAEVENT event;
90557e22627SCy Schubert 
90657e22627SCy Schubert 		//
90757e22627SCy Schubert 		// Create an event that is signaled if there's a connection
90857e22627SCy Schubert 		// to accept on the socket in question.
90957e22627SCy Schubert 		//
91057e22627SCy Schubert 		event = WSACreateEvent();
91157e22627SCy Schubert 		if (event == WSA_INVALID_EVENT)
91257e22627SCy Schubert 		{
9136f9cba8fSJoseph Mingrone 			sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9146f9cba8fSJoseph Mingrone 			    "Can't create socket event");
91557e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
91657e22627SCy Schubert 			exit(2);
91757e22627SCy Schubert 		}
91857e22627SCy Schubert 		if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
91957e22627SCy Schubert 		{
9206f9cba8fSJoseph Mingrone 			sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9216f9cba8fSJoseph Mingrone 			    "Can't setup socket event");
92257e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
92357e22627SCy Schubert 			exit(2);
92457e22627SCy Schubert 		}
92557e22627SCy Schubert 		events[i] = event;
92657e22627SCy Schubert 	}
92757e22627SCy Schubert 
92857e22627SCy Schubert 	for (;;)
92957e22627SCy Schubert 	{
93057e22627SCy Schubert 		//
93157e22627SCy Schubert 		// Wait for incoming connections.
93257e22627SCy Schubert 		//
93357e22627SCy Schubert 		DWORD ret;
93457e22627SCy Schubert 
93557e22627SCy Schubert 		ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
93657e22627SCy Schubert 		    WSA_INFINITE, FALSE);
93757e22627SCy Schubert 		if (ret == WSA_WAIT_FAILED)
93857e22627SCy Schubert 		{
9396f9cba8fSJoseph Mingrone 			sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9406f9cba8fSJoseph Mingrone 			    "WSAWaitForMultipleEvents failed");
94157e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
94257e22627SCy Schubert 			exit(2);
94357e22627SCy Schubert 		}
94457e22627SCy Schubert 
94557e22627SCy Schubert 		if (ret == WSA_WAIT_EVENT_0)
94657e22627SCy Schubert 		{
94757e22627SCy Schubert 			//
94857e22627SCy Schubert 			// The state change event was set.
94957e22627SCy Schubert 			//
95057e22627SCy Schubert 			if (shutdown_server)
95157e22627SCy Schubert 			{
95257e22627SCy Schubert 				//
95357e22627SCy Schubert 				// Time to quit. Exit the loop.
95457e22627SCy Schubert 				//
95557e22627SCy Schubert 				break;
95657e22627SCy Schubert 			}
95757e22627SCy Schubert 			if (reread_config)
95857e22627SCy Schubert 			{
95957e22627SCy Schubert 				//
96057e22627SCy Schubert 				// We should re-read the configuration
96157e22627SCy Schubert 				// file.
96257e22627SCy Schubert 				//
96357e22627SCy Schubert 				reread_config = 0;	// clear the indicator
96457e22627SCy Schubert 				fileconf_read();
96557e22627SCy Schubert 			}
96657e22627SCy Schubert 		}
96757e22627SCy Schubert 
96857e22627SCy Schubert 		//
96957e22627SCy Schubert 		// Check each socket.
97057e22627SCy Schubert 		//
97157e22627SCy Schubert 		for (sock_info = listen_socks, i = 1; sock_info;
97257e22627SCy Schubert 		    sock_info = sock_info->next, i++)
97357e22627SCy Schubert 		{
97457e22627SCy Schubert 			WSANETWORKEVENTS network_events;
97557e22627SCy Schubert 
97657e22627SCy Schubert 			if (WSAEnumNetworkEvents(sock_info->sock,
97757e22627SCy Schubert 			    events[i], &network_events) == SOCKET_ERROR)
97857e22627SCy Schubert 			{
9796f9cba8fSJoseph Mingrone 				sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9806f9cba8fSJoseph Mingrone 				    "WSAEnumNetworkEvents failed");
98157e22627SCy Schubert 				rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
98257e22627SCy Schubert 				exit(2);
98357e22627SCy Schubert 			}
98457e22627SCy Schubert 			if (network_events.lNetworkEvents & FD_ACCEPT)
98557e22627SCy Schubert 			{
98657e22627SCy Schubert 				//
98757e22627SCy Schubert 				// Did an error occur?
98857e22627SCy Schubert 				//
98957e22627SCy Schubert 				if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
99057e22627SCy Schubert 				{
99157e22627SCy Schubert 					//
99257e22627SCy Schubert 					// Yes - report it and keep going.
99357e22627SCy Schubert 					//
9946f9cba8fSJoseph Mingrone 					sock_fmterrmsg(errbuf,
9956f9cba8fSJoseph Mingrone 					    PCAP_ERRBUF_SIZE,
99657e22627SCy Schubert 					    network_events.iErrorCode[FD_ACCEPT_BIT],
9976f9cba8fSJoseph Mingrone 					    "Socket error");
99857e22627SCy Schubert 					rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
99957e22627SCy Schubert 					continue;
100057e22627SCy Schubert 				}
100157e22627SCy Schubert 
100257e22627SCy Schubert 				//
100357e22627SCy Schubert 				// Accept the connection.
100457e22627SCy Schubert 				//
100557e22627SCy Schubert 				accept_connection(sock_info->sock);
100657e22627SCy Schubert 			}
100757e22627SCy Schubert 		}
100857e22627SCy Schubert 	}
100957e22627SCy Schubert #else
101057e22627SCy Schubert 	struct listen_sock *sock_info;
101157e22627SCy Schubert 	int num_sock_fds;
101257e22627SCy Schubert 
101357e22627SCy Schubert 	//
101457e22627SCy Schubert 	// How big does the bitset of sockets on which to select() have
101557e22627SCy Schubert 	// to be?
101657e22627SCy Schubert 	//
101757e22627SCy Schubert 	num_sock_fds = 0;
101857e22627SCy Schubert 	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
101957e22627SCy Schubert 	{
102057e22627SCy Schubert 		if (sock_info->sock + 1 > num_sock_fds)
102157e22627SCy Schubert 		{
102257e22627SCy Schubert 			if ((unsigned int)(sock_info->sock + 1) >
102357e22627SCy Schubert 			    (unsigned int)FD_SETSIZE)
102457e22627SCy Schubert 			{
102557e22627SCy Schubert 				rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
102657e22627SCy Schubert 				exit(2);
102757e22627SCy Schubert 			}
102857e22627SCy Schubert 			num_sock_fds = sock_info->sock + 1;
102957e22627SCy Schubert 		}
103057e22627SCy Schubert 	}
103157e22627SCy Schubert 
103257e22627SCy Schubert 	for (;;)
103357e22627SCy Schubert 	{
103457e22627SCy Schubert 		fd_set sock_fds;
103557e22627SCy Schubert 		int ret;
103657e22627SCy Schubert 
103757e22627SCy Schubert 		//
103857e22627SCy Schubert 		// Set up an fd_set for all the sockets on which we're
103957e22627SCy Schubert 		// listening.
104057e22627SCy Schubert 		//
104157e22627SCy Schubert 		// This set is modified by select(), so we have to
104257e22627SCy Schubert 		// construct it anew each time.
104357e22627SCy Schubert 		//
104457e22627SCy Schubert 		FD_ZERO(&sock_fds);
104557e22627SCy Schubert 		for (sock_info = listen_socks; sock_info;
104657e22627SCy Schubert 		    sock_info = sock_info->next)
104757e22627SCy Schubert 		{
104857e22627SCy Schubert 			FD_SET(sock_info->sock, &sock_fds);
104957e22627SCy Schubert 		}
105057e22627SCy Schubert 
105157e22627SCy Schubert 		//
105257e22627SCy Schubert 		// Wait for incoming connections.
105357e22627SCy Schubert 		//
105457e22627SCy Schubert 		ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
105557e22627SCy Schubert 		if (ret == -1)
105657e22627SCy Schubert 		{
105757e22627SCy Schubert 			if (errno == EINTR)
105857e22627SCy Schubert 			{
105957e22627SCy Schubert 				//
106057e22627SCy Schubert 				// If this is a "terminate the
106157e22627SCy Schubert 				// server" signal, exit the loop,
106257e22627SCy Schubert 				// otherwise just keep trying.
106357e22627SCy Schubert 				//
106457e22627SCy Schubert 				if (shutdown_server)
106557e22627SCy Schubert 				{
106657e22627SCy Schubert 					//
106757e22627SCy Schubert 					// Time to quit.  Exit the loop.
106857e22627SCy Schubert 					//
106957e22627SCy Schubert 					break;
107057e22627SCy Schubert 				}
107157e22627SCy Schubert 				if (reread_config)
107257e22627SCy Schubert 				{
107357e22627SCy Schubert 					//
107457e22627SCy Schubert 					// We should re-read the configuration
107557e22627SCy Schubert 					// file.
107657e22627SCy Schubert 					//
107757e22627SCy Schubert 					reread_config = 0;	// clear the indicator
107857e22627SCy Schubert 					fileconf_read();
107957e22627SCy Schubert 				}
108057e22627SCy Schubert 
108157e22627SCy Schubert 				//
108257e22627SCy Schubert 				// Go back and wait again.
108357e22627SCy Schubert 				//
108457e22627SCy Schubert 				continue;
108557e22627SCy Schubert 			}
108657e22627SCy Schubert 			else
108757e22627SCy Schubert 			{
108857e22627SCy Schubert 				rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
108957e22627SCy Schubert 				    strerror(errno));
109057e22627SCy Schubert 				exit(2);
109157e22627SCy Schubert 			}
109257e22627SCy Schubert 		}
109357e22627SCy Schubert 
109457e22627SCy Schubert 		//
109557e22627SCy Schubert 		// Check each socket.
109657e22627SCy Schubert 		//
109757e22627SCy Schubert 		for (sock_info = listen_socks; sock_info;
109857e22627SCy Schubert 		    sock_info = sock_info->next)
109957e22627SCy Schubert 		{
110057e22627SCy Schubert 			if (FD_ISSET(sock_info->sock, &sock_fds))
110157e22627SCy Schubert 			{
110257e22627SCy Schubert 				//
110357e22627SCy Schubert 				// Accept the connection.
110457e22627SCy Schubert 				//
110557e22627SCy Schubert 				accept_connection(sock_info->sock);
110657e22627SCy Schubert 			}
110757e22627SCy Schubert 		}
110857e22627SCy Schubert 	}
110957e22627SCy Schubert #endif
111057e22627SCy Schubert 
111157e22627SCy Schubert 	//
111257e22627SCy Schubert 	// Close all the listen sockets.
111357e22627SCy Schubert 	//
111457e22627SCy Schubert 	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
111557e22627SCy Schubert 	{
111657e22627SCy Schubert 		closesocket(sock_info->sock);
111757e22627SCy Schubert 	}
111857e22627SCy Schubert 	sock_cleanup();
111957e22627SCy Schubert }
112057e22627SCy Schubert 
112157e22627SCy Schubert #ifdef _WIN32
112257e22627SCy Schubert //
112357e22627SCy Schubert // A structure to hold the parameters to the daemon service loop
112457e22627SCy Schubert // thread on Windows.
112557e22627SCy Schubert //
112657e22627SCy Schubert // (On UN*X, there is no need for this explicit copy since the
112757e22627SCy Schubert // fork "inherits" the parent stack.)
112857e22627SCy Schubert //
112957e22627SCy Schubert struct params_copy {
1130*afdbf109SJoseph Mingrone 	PCAP_SOCKET sockctrl;
113157e22627SCy Schubert 	char *hostlist;
113257e22627SCy Schubert };
113357e22627SCy Schubert #endif
113457e22627SCy Schubert 
113557e22627SCy Schubert //
113657e22627SCy Schubert // Accept a connection and start a worker thread, on Windows, or a
113757e22627SCy Schubert // worker process, on UN*X, to handle the connection.
113857e22627SCy Schubert //
113957e22627SCy Schubert static void
accept_connection(PCAP_SOCKET listen_sock)1140*afdbf109SJoseph Mingrone accept_connection(PCAP_SOCKET listen_sock)
114157e22627SCy Schubert {
114257e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
1143*afdbf109SJoseph Mingrone 	PCAP_SOCKET sockctrl;			// keeps the socket ID for this control connection
114457e22627SCy Schubert 	struct sockaddr_storage from;		// generic sockaddr_storage variable
114557e22627SCy Schubert 	socklen_t fromlen;			// keeps the length of the sockaddr_storage variable
114657e22627SCy Schubert 
114757e22627SCy Schubert #ifdef _WIN32
114857e22627SCy Schubert 	HANDLE threadId;			// handle for the subthread
114957e22627SCy Schubert 	u_long off = 0;
115057e22627SCy Schubert 	struct params_copy *params_copy = NULL;
115157e22627SCy Schubert #else
115257e22627SCy Schubert 	pid_t pid;
115357e22627SCy Schubert #endif
115457e22627SCy Schubert 
115557e22627SCy Schubert 	// Initialize errbuf
115657e22627SCy Schubert 	memset(errbuf, 0, sizeof(errbuf));
115757e22627SCy Schubert 
115857e22627SCy Schubert 	for (;;)
115957e22627SCy Schubert 	{
116057e22627SCy Schubert 		// Accept the connection
116157e22627SCy Schubert 		fromlen = sizeof(struct sockaddr_storage);
116257e22627SCy Schubert 
116357e22627SCy Schubert 		sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
116457e22627SCy Schubert 
116557e22627SCy Schubert 		if (sockctrl != INVALID_SOCKET)
116657e22627SCy Schubert 		{
116757e22627SCy Schubert 			// Success.
116857e22627SCy Schubert 			break;
116957e22627SCy Schubert 		}
117057e22627SCy Schubert 
11716f9cba8fSJoseph Mingrone 		// The accept() call can return this error when a signal is caught
117257e22627SCy Schubert 		// In this case, we have simply to ignore this error code
117357e22627SCy Schubert 		// Stevens, pg 124
117457e22627SCy Schubert #ifdef _WIN32
117557e22627SCy Schubert 		if (WSAGetLastError() == WSAEINTR)
117657e22627SCy Schubert #else
117757e22627SCy Schubert 		if (errno == EINTR)
117857e22627SCy Schubert #endif
117957e22627SCy Schubert 			continue;
118057e22627SCy Schubert 
118157e22627SCy Schubert 		// Don't check for errors here, since the error can be due to the fact that the thread
118257e22627SCy Schubert 		// has been killed
11836f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed");
118457e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
118557e22627SCy Schubert 		    errbuf);
118657e22627SCy Schubert 		return;
118757e22627SCy Schubert 	}
118857e22627SCy Schubert 
118957e22627SCy Schubert #ifdef _WIN32
119057e22627SCy Schubert 	//
119157e22627SCy Schubert 	// Put the socket back into blocking mode; doing WSAEventSelect()
119257e22627SCy Schubert 	// on the listen socket makes that socket non-blocking, and it
119357e22627SCy Schubert 	// appears that sockets returned from an accept() on that socket
119457e22627SCy Schubert 	// are also non-blocking.
119557e22627SCy Schubert 	//
119657e22627SCy Schubert 	// First, we have to un-WSAEventSelect() this socket, and then
119757e22627SCy Schubert 	// we can turn non-blocking mode off.
119857e22627SCy Schubert 	//
119957e22627SCy Schubert 	// If this fails, we aren't guaranteed that, for example, any
120057e22627SCy Schubert 	// of the error message will be sent - if it can't be put in
120157e22627SCy Schubert 	// the socket queue, the send will just fail.
120257e22627SCy Schubert 	//
120357e22627SCy Schubert 	// So we just log the message and close the connection.
120457e22627SCy Schubert 	//
120557e22627SCy Schubert 	if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
120657e22627SCy Schubert 	{
12076f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
12086f9cba8fSJoseph Mingrone 		    "WSAEventSelect() failed");
120957e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
121057e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
121157e22627SCy Schubert 		return;
121257e22627SCy Schubert 	}
121357e22627SCy Schubert 	if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
121457e22627SCy Schubert 	{
12156f9cba8fSJoseph Mingrone 		sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
12166f9cba8fSJoseph Mingrone 		    "ioctlsocket(FIONBIO) failed");
121757e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
121857e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
121957e22627SCy Schubert 		return;
122057e22627SCy Schubert 	}
122157e22627SCy Schubert 
122257e22627SCy Schubert 	//
122357e22627SCy Schubert 	// Make a copy of the host list to pass to the new thread, so that
122457e22627SCy Schubert 	// if we update it in the main thread, it won't catch us in the
122557e22627SCy Schubert 	// middle of updating it.
122657e22627SCy Schubert 	//
122757e22627SCy Schubert 	// daemon_serviceloop() will free it once it's done with it.
122857e22627SCy Schubert 	//
122957e22627SCy Schubert 	char *hostlist_copy = strdup(hostlist);
123057e22627SCy Schubert 	if (hostlist_copy == NULL)
123157e22627SCy Schubert 	{
123257e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
123357e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
123457e22627SCy Schubert 		return;
123557e22627SCy Schubert 	}
123657e22627SCy Schubert 
123757e22627SCy Schubert 	//
123857e22627SCy Schubert 	// Allocate a location to hold the values of sockctrl.
123957e22627SCy Schubert 	// It will be freed in the newly-created thread once it's
124057e22627SCy Schubert 	// finished with it.
124157e22627SCy Schubert 	//
124257e22627SCy Schubert 	params_copy = malloc(sizeof(*params_copy));
124357e22627SCy Schubert 	if (params_copy == NULL)
124457e22627SCy Schubert 	{
124557e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
124657e22627SCy Schubert 		free(hostlist_copy);
124757e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
124857e22627SCy Schubert 		return;
124957e22627SCy Schubert 	}
125057e22627SCy Schubert 	params_copy->sockctrl = sockctrl;
125157e22627SCy Schubert 	params_copy->hostlist = hostlist_copy;
125257e22627SCy Schubert 
125357e22627SCy Schubert 	threadId = (HANDLE)_beginthreadex(NULL, 0,
125457e22627SCy Schubert 	    main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
125557e22627SCy Schubert 	if (threadId == 0)
125657e22627SCy Schubert 	{
125757e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
125857e22627SCy Schubert 		free(params_copy);
125957e22627SCy Schubert 		free(hostlist_copy);
126057e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
126157e22627SCy Schubert 		return;
126257e22627SCy Schubert 	}
126357e22627SCy Schubert 	CloseHandle(threadId);
126457e22627SCy Schubert #else /* _WIN32 */
126557e22627SCy Schubert 	pid = fork();
126657e22627SCy Schubert 	if (pid == -1)
126757e22627SCy Schubert 	{
126857e22627SCy Schubert 		rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
126957e22627SCy Schubert 		    strerror(errno));
127057e22627SCy Schubert 		sock_close(sockctrl, NULL, 0);
127157e22627SCy Schubert 		return;
127257e22627SCy Schubert 	}
127357e22627SCy Schubert 	if (pid == 0)
127457e22627SCy Schubert 	{
127557e22627SCy Schubert 		//
127657e22627SCy Schubert 		// Child process.
127757e22627SCy Schubert 		//
127857e22627SCy Schubert 		// Close the socket on which we're listening (must
127957e22627SCy Schubert 		// be open only in the parent).
128057e22627SCy Schubert 		//
128157e22627SCy Schubert 		closesocket(listen_sock);
128257e22627SCy Schubert 
128357e22627SCy Schubert #if 0
128457e22627SCy Schubert 		//
128557e22627SCy Schubert 		// Modify thread params so that it can be killed at any time
128657e22627SCy Schubert 		// XXX - is this necessary?  This is the main and, currently,
128757e22627SCy Schubert 		// only thread in the child process, and nobody tries to
128857e22627SCy Schubert 		// cancel us, although *we* may cancel the thread that's
128957e22627SCy Schubert 		// handling the capture loop.
129057e22627SCy Schubert 		//
129157e22627SCy Schubert 		if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
129257e22627SCy Schubert 			goto end;
129357e22627SCy Schubert 		if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
129457e22627SCy Schubert 			goto end;
129557e22627SCy Schubert #endif
129657e22627SCy Schubert 
129757e22627SCy Schubert 		//
129857e22627SCy Schubert 		// Run the service loop.
129957e22627SCy Schubert 		// This is passive mode, so we don't care whether we were
130057e22627SCy Schubert 		// told by the client to close.
130157e22627SCy Schubert 		//
130257e22627SCy Schubert 		char *hostlist_copy = strdup(hostlist);
130357e22627SCy Schubert 		if (hostlist_copy == NULL)
130457e22627SCy Schubert 		{
130557e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
130657e22627SCy Schubert 			exit(0);
130757e22627SCy Schubert 		}
130857e22627SCy Schubert 		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
13096f9cba8fSJoseph Mingrone 		    nullAuthAllowed, uses_ssl);
131057e22627SCy Schubert 
131157e22627SCy Schubert 		exit(0);
131257e22627SCy Schubert 	}
131357e22627SCy Schubert 
131457e22627SCy Schubert 	// I am the parent
131557e22627SCy Schubert 	// Close the socket for this session (must be open only in the child)
131657e22627SCy Schubert 	closesocket(sockctrl);
131757e22627SCy Schubert #endif /* _WIN32 */
131857e22627SCy Schubert }
131957e22627SCy Schubert 
132057e22627SCy Schubert /*!
132157e22627SCy Schubert 	\brief 'true' main of the program in case the active mode is turned on.
132257e22627SCy Schubert 
132357e22627SCy Schubert 	This function loops forever trying to connect to the remote host, until the
132457e22627SCy Schubert 	daemon is turned down.
132557e22627SCy Schubert 
132657e22627SCy Schubert 	\param ptr: it keeps the 'activepars' parameters.  It is a 'void *'
132757e22627SCy Schubert 	just because the thread APIs want this format.
132857e22627SCy Schubert */
132957e22627SCy Schubert #ifdef _WIN32
133057e22627SCy Schubert static unsigned __stdcall
133157e22627SCy Schubert #else
133257e22627SCy Schubert static void *
133357e22627SCy Schubert #endif
main_active(void * ptr)133457e22627SCy Schubert main_active(void *ptr)
133557e22627SCy Schubert {
133657e22627SCy Schubert 	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
1337*afdbf109SJoseph Mingrone 	PCAP_SOCKET sockctrl;			// keeps the socket ID for this control connection
133857e22627SCy Schubert 	struct addrinfo hints;			// temporary struct to keep settings needed to open the new socket
133957e22627SCy Schubert 	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
134057e22627SCy Schubert 	struct active_pars *activepars;
134157e22627SCy Schubert 
134257e22627SCy Schubert 	activepars = (struct active_pars *) ptr;
134357e22627SCy Schubert 
134457e22627SCy Schubert 	// Prepare to open a new server socket
134557e22627SCy Schubert 	memset(&hints, 0, sizeof(struct addrinfo));
134657e22627SCy Schubert 						// WARNING Currently it supports only ONE socket family among IPv4 and IPv6
134757e22627SCy Schubert 	hints.ai_family = AF_INET;		// PF_UNSPEC to have both IPv4 and IPv6 server
134857e22627SCy Schubert 	hints.ai_socktype = SOCK_STREAM;
134957e22627SCy Schubert 	hints.ai_family = activepars->ai_family;
135057e22627SCy Schubert 
135157e22627SCy Schubert 	rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
135257e22627SCy Schubert 	    activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
135357e22627SCy Schubert 	    (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
135457e22627SCy Schubert 
135557e22627SCy Schubert 	// Initialize errbuf
135657e22627SCy Schubert 	memset(errbuf, 0, sizeof(errbuf));
135757e22627SCy Schubert 
135857e22627SCy Schubert 	// Do the work
1359*afdbf109SJoseph Mingrone 	addrinfo = sock_initaddress(activepars->address, activepars->port,
1360*afdbf109SJoseph Mingrone 	    &hints, errbuf, PCAP_ERRBUF_SIZE);
1361*afdbf109SJoseph Mingrone 	if (addrinfo == NULL)
136257e22627SCy Schubert 	{
136357e22627SCy Schubert 		rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
136457e22627SCy Schubert 		return 0;
136557e22627SCy Schubert 	}
136657e22627SCy Schubert 
136757e22627SCy Schubert 	for (;;)
136857e22627SCy Schubert 	{
136957e22627SCy Schubert 		int activeclose;
137057e22627SCy Schubert 
13716f9cba8fSJoseph Mingrone 		if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
137257e22627SCy Schubert 		{
137357e22627SCy Schubert 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
137457e22627SCy Schubert 
13756f9cba8fSJoseph Mingrone 			DIAG_OFF_FORMAT_TRUNCATION
13766f9cba8fSJoseph Mingrone 			snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
137757e22627SCy Schubert 					activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
137857e22627SCy Schubert 					(hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
13796f9cba8fSJoseph Mingrone 			DIAG_ON_FORMAT_TRUNCATION
138057e22627SCy Schubert 
138157e22627SCy Schubert 			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
138257e22627SCy Schubert 
138357e22627SCy Schubert 			sleep_secs(RPCAP_ACTIVE_WAIT);
138457e22627SCy Schubert 
138557e22627SCy Schubert 			continue;
138657e22627SCy Schubert 		}
138757e22627SCy Schubert 
138857e22627SCy Schubert 		char *hostlist_copy = strdup(hostlist);
138957e22627SCy Schubert 		if (hostlist_copy == NULL)
139057e22627SCy Schubert 		{
139157e22627SCy Schubert 			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
139257e22627SCy Schubert 			activeclose = 0;
139357e22627SCy Schubert 			sock_close(sockctrl, NULL, 0);
139457e22627SCy Schubert 		}
139557e22627SCy Schubert 		else
139657e22627SCy Schubert 		{
139757e22627SCy Schubert 			//
139857e22627SCy Schubert 			// daemon_serviceloop() will free the copy.
139957e22627SCy Schubert 			//
140057e22627SCy Schubert 			activeclose = daemon_serviceloop(sockctrl, 1,
14016f9cba8fSJoseph Mingrone 			    hostlist_copy, nullAuthAllowed, uses_ssl);
140257e22627SCy Schubert 		}
140357e22627SCy Schubert 
14046f9cba8fSJoseph Mingrone 		// If the connection is closed by the user explicitly, don't try to connect to it again
140557e22627SCy Schubert 		// just exit the program
140657e22627SCy Schubert 		if (activeclose == 1)
140757e22627SCy Schubert 			break;
140857e22627SCy Schubert 	}
140957e22627SCy Schubert 
141057e22627SCy Schubert 	freeaddrinfo(addrinfo);
141157e22627SCy Schubert 	return 0;
141257e22627SCy Schubert }
141357e22627SCy Schubert 
141457e22627SCy Schubert #ifdef _WIN32
141557e22627SCy Schubert //
141657e22627SCy Schubert // Main routine of a passive-mode service thread.
141757e22627SCy Schubert //
main_passive_serviceloop_thread(void * ptr)141857e22627SCy Schubert unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
141957e22627SCy Schubert {
142057e22627SCy Schubert 	struct params_copy params = *(struct params_copy *)ptr;
142157e22627SCy Schubert 	free(ptr);
142257e22627SCy Schubert 
142357e22627SCy Schubert 	//
142457e22627SCy Schubert 	// Handle this client.
142557e22627SCy Schubert 	// This is passive mode, so we don't care whether we were
142657e22627SCy Schubert 	// told by the client to close.
142757e22627SCy Schubert 	//
142857e22627SCy Schubert 	(void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
14296f9cba8fSJoseph Mingrone 	    nullAuthAllowed, uses_ssl);
143057e22627SCy Schubert 
143157e22627SCy Schubert 	return 0;
143257e22627SCy Schubert }
143357e22627SCy Schubert #endif
1434