Blame rpcapd/rpcapd.c

Packit 209cc3
/*
Packit 209cc3
 * Copyright (c) 2002 - 2003
Packit 209cc3
 * NetGroup, Politecnico di Torino (Italy)
Packit 209cc3
 * All rights reserved.
Packit 209cc3
 *
Packit 209cc3
 * Redistribution and use in source and binary forms, with or without
Packit 209cc3
 * modification, are permitted provided that the following conditions
Packit 209cc3
 * are met:
Packit 209cc3
 *
Packit 209cc3
 * 1. Redistributions of source code must retain the above copyright
Packit 209cc3
 * notice, this list of conditions and the following disclaimer.
Packit 209cc3
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 209cc3
 * notice, this list of conditions and the following disclaimer in the
Packit 209cc3
 * documentation and/or other materials provided with the distribution.
Packit 209cc3
 * 3. Neither the name of the Politecnico di Torino nor the names of its
Packit 209cc3
 * contributors may be used to endorse or promote products derived from
Packit 209cc3
 * this software without specific prior written permission.
Packit 209cc3
 *
Packit 209cc3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 209cc3
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 209cc3
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 209cc3
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 209cc3
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 209cc3
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 209cc3
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 209cc3
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 209cc3
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 209cc3
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 209cc3
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 209cc3
 *
Packit 209cc3
 */
Packit 209cc3
Packit 209cc3
#ifdef HAVE_CONFIG_H
Packit 209cc3
#include <config.h>
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
#include "ftmacros.h"
Packit 209cc3
Packit 209cc3
#include <errno.h>		// for the errno variable
Packit 209cc3
#include <string.h>		// for strtok, etc
Packit 209cc3
#include <stdlib.h>		// for malloc(), free(), ...
Packit 209cc3
#include <pcap.h>		// for PCAP_ERRBUF_SIZE
Packit 209cc3
#include <signal.h>		// for signal()
Packit 209cc3
Packit 209cc3
#include "fmtutils.h"
Packit 209cc3
#include "sockutils.h"		// for socket calls
Packit 209cc3
#include "varattrs.h"		// for _U_
Packit 209cc3
#include "portability.h"
Packit 209cc3
#include "rpcapd.h"
Packit 209cc3
#include "config_params.h"	// configuration file parameters
Packit 209cc3
#include "fileconf.h"		// for the configuration file management
Packit 209cc3
#include "rpcap-protocol.h"
Packit 209cc3
#include "daemon.h"		// the true main() method of this daemon
Packit 209cc3
#include "log.h"
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
  #include <process.h>		// for thread stuff
Packit 209cc3
  #include "win32-svc.h"	// for Win32 service stuff
Packit 209cc3
  #include "getopt.h"		// for getopt()-for-Windows
Packit 209cc3
#else
Packit 209cc3
  #include <fcntl.h>		// for open()
Packit 209cc3
  #include <unistd.h>		// for exit()
Packit 209cc3
  #include <sys/wait.h>		// waitpid()
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
//
Packit 209cc3
// Element in list of sockets on which we're listening for connections.
Packit 209cc3
//
Packit 209cc3
struct listen_sock {
Packit 209cc3
	struct listen_sock *next;
Packit 209cc3
	SOCKET sock;
Packit 209cc3
};
Packit 209cc3
Packit 209cc3
// Global variables
Packit 209cc3
char hostlist[MAX_HOST_LIST + 1];		//!< Keeps the list of the hosts that are allowed to connect to this server
Packit 209cc3
struct active_pars activelist[MAX_ACTIVE_LIST];	//!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
Packit 209cc3
int nullAuthAllowed;				//!< '1' if we permit NULL authentication, '0' otherwise
Packit 209cc3
static struct listen_sock *listen_socks;	//!< sockets on which we listen
Packit 209cc3
char loadfile[MAX_LINE + 1];			//!< Name of the file from which we have to load the configuration
Packit 209cc3
static int passivemode = 1;			//!< '1' if we want to run in passive mode as well
Packit 209cc3
static struct addrinfo mainhints;		//!< temporary struct to keep settings needed to open the new socket
Packit 209cc3
static char address[MAX_LINE + 1];		//!< keeps the network address (either numeric or literal) to bind to
Packit 209cc3
static char port[MAX_LINE + 1];			//!< keeps the network port to bind to
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
static HANDLE state_change_event;		//!< event to signal that a state change should take place
Packit 209cc3
#endif
Packit 209cc3
static volatile sig_atomic_t shutdown_server;	//!< '1' if the server is to shut down
Packit 209cc3
static volatile sig_atomic_t reread_config;	//!< '1' if the server is to re-read its configuration
Packit 209cc3
Packit 209cc3
extern char *optarg;	// for getopt()
Packit 209cc3
Packit 209cc3
// Function definition
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
static unsigned __stdcall main_active(void *ptr);
Packit 209cc3
static BOOL WINAPI main_ctrl_event(DWORD);
Packit 209cc3
#else
Packit 209cc3
static void *main_active(void *ptr);
Packit 209cc3
static void main_terminate(int sign);
Packit 209cc3
static void main_reread_config(int sign);
Packit 209cc3
#endif
Packit 209cc3
static void accept_connections(void);
Packit 209cc3
static void accept_connection(SOCKET listen_sock);
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
static void main_reap_children(int sign);
Packit 209cc3
#endif
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
#define RPCAP_ACTIVE_WAIT 30		/* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
Packit 209cc3
Packit 209cc3
/*!
Packit 209cc3
	\brief Prints the usage screen if it is launched in console mode.
Packit 209cc3
*/
Packit 209cc3
static void printusage(void)
Packit 209cc3
{
Packit 209cc3
	const char *usagetext =
Packit 209cc3
	"USAGE:"
Packit 209cc3
	" "  PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
Packit 209cc3
	"              [-n] [-v] [-d] "
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	"[-i] "
Packit 209cc3
#endif
Packit 209cc3
        "[-D] [-s <config_file>] [-f <config_file>]\n\n"
Packit 209cc3
	"  -b <address>    the address to bind to (either numeric or literal).\n"
Packit 209cc3
	"                  Default: binds to all local IPv4 and IPv6 addresses\n\n"
Packit 209cc3
	"  -p <port>       the port to bind to.\n"
Packit 209cc3
	"                  Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
Packit 209cc3
	"  -4              use only IPv4.\n"
Packit 209cc3
	"                  Default: use both IPv4 and IPv6 waiting sockets\n\n"
Packit 209cc3
	"  -l <host_list>  a file that contains a list of hosts that are allowed\n"
Packit 209cc3
	"                  to connect to this server (if more than one, list them one\n"
Packit 209cc3
	"                  per line).\n"
Packit 209cc3
	"                  We suggest to use literal names (instead of numeric ones)\n"
Packit 209cc3
	"                  in order to avoid problems with different address families.\n\n"
Packit 209cc3
	"  -n              permit NULL authentication (usually used with '-l')\n\n"
Packit 209cc3
	"  -a <host,port>  run in active mode when connecting to 'host' on port 'port'\n"
Packit 209cc3
	"                  In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
Packit 209cc3
	"  -v              run in active mode only (default: if '-a' is specified, it\n"
Packit 209cc3
	"                  accepts passive connections as well)\n\n"
Packit 209cc3
	"  -d              run in daemon mode (UNIX only) or as a service (Win32 only)\n"
Packit 209cc3
	"                  Warning (Win32): this switch is provided automatically when\n"
Packit 209cc3
	"                  the service is started from the control panel\n\n"
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	"  -i              run in inetd mode (UNIX only)\n\n"
Packit 209cc3
#endif
Packit 209cc3
	"  -D              log debugging messages\n\n"
Packit 209cc3
	"  -s <config_file> save the current configuration to file\n\n"
Packit 209cc3
	"  -f <config_file> load the current configuration from file; all switches\n"
Packit 209cc3
	"                  specified from the command line are ignored\n\n"
Packit 209cc3
	"  -h              print this help screen\n\n";
Packit 209cc3
Packit 209cc3
	(void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
Packit 209cc3
	"Compiled with %s\n\n", pcap_lib_version());
Packit 209cc3
	printf("%s", usagetext);
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
Packit 209cc3
Packit 209cc3
//! Program main
Packit 209cc3
int main(int argc, char *argv[])
Packit 209cc3
{
Packit 209cc3
	char savefile[MAX_LINE + 1];		// name of the file on which we have to save the configuration
Packit 209cc3
	int log_to_systemlog = 0;		// Non-zero if we should log to the "system log" rather than the standard error
Packit 209cc3
	int isdaemon = 0;			// Non-zero if the user wants to run this program as a daemon
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	int isrunbyinetd = 0;			// Non-zero if this is being run by inetd or something inetd-like
Packit 209cc3
#endif
Packit 209cc3
	int log_debug_messages = 0;		// Non-zero if the user wants debug messages logged
Packit 209cc3
	int retval;				// keeps the returning value from several functions
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	struct sigaction action;
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	savefile[0] = 0;
Packit 209cc3
	loadfile[0] = 0;
Packit 209cc3
	hostlist[0] = 0;
Packit 209cc3
Packit 209cc3
	// Initialize errbuf
Packit 209cc3
	memset(errbuf, 0, sizeof(errbuf));
Packit 209cc3
Packit 209cc3
	strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
Packit 209cc3
	strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
Packit 209cc3
Packit 209cc3
	// Prepare to open a new server socket
Packit 209cc3
	memset(&mainhints, 0, sizeof(struct addrinfo));
Packit 209cc3
Packit 209cc3
	mainhints.ai_family = PF_UNSPEC;
Packit 209cc3
	mainhints.ai_flags = AI_PASSIVE;	// Ready to a bind() socket
Packit 209cc3
	mainhints.ai_socktype = SOCK_STREAM;
Packit 209cc3
Packit 209cc3
	// Getting the proper command line options
Packit 209cc3
	while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1)
Packit 209cc3
	{
Packit 209cc3
		switch (retval)
Packit 209cc3
		{
Packit 209cc3
			case 'D':
Packit 209cc3
				log_debug_messages = 1;
Packit 209cc3
				rpcapd_log_set(log_to_systemlog, log_debug_messages);
Packit 209cc3
				break;
Packit 209cc3
			case 'b':
Packit 209cc3
				strncpy(address, optarg, MAX_LINE);
Packit 209cc3
				break;
Packit 209cc3
			case 'p':
Packit 209cc3
				strncpy(port, optarg, MAX_LINE);
Packit 209cc3
				break;
Packit 209cc3
			case '4':
Packit 209cc3
				mainhints.ai_family = PF_INET;		// IPv4 server only
Packit 209cc3
				break;
Packit 209cc3
			case 'd':
Packit 209cc3
				isdaemon = 1;
Packit 209cc3
				log_to_systemlog = 1;
Packit 209cc3
				rpcapd_log_set(log_to_systemlog, log_debug_messages);
Packit 209cc3
				break;
Packit 209cc3
			case 'i':
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
				printusage();
Packit 209cc3
				exit(1);
Packit 209cc3
#else
Packit 209cc3
				isrunbyinetd = 1;
Packit 209cc3
				log_to_systemlog = 1;
Packit 209cc3
				rpcapd_log_set(log_to_systemlog, log_debug_messages);
Packit 209cc3
#endif
Packit 209cc3
				break;
Packit 209cc3
			case 'n':
Packit 209cc3
				nullAuthAllowed = 1;
Packit 209cc3
				break;
Packit 209cc3
			case 'v':
Packit 209cc3
				passivemode = 0;
Packit 209cc3
				break;
Packit 209cc3
			case 'l':
Packit 209cc3
			{
Packit 209cc3
				strncpy(hostlist, optarg, sizeof(hostlist));
Packit 209cc3
				break;
Packit 209cc3
			}
Packit 209cc3
			case 'a':
Packit 209cc3
			{
Packit 209cc3
				char *tmpaddress, *tmpport;
Packit 209cc3
				char *lasts;
Packit 209cc3
				int i = 0;
Packit 209cc3
Packit 209cc3
				tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
Packit 209cc3
Packit 209cc3
				while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
Packit 209cc3
				{
Packit 209cc3
					tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
Packit 209cc3
Packit 209cc3
					pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
Packit 209cc3
Packit 209cc3
					if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
Packit 209cc3
						pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
Packit 209cc3
					else
Packit 209cc3
						pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE);
Packit 209cc3
Packit 209cc3
					tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
Packit 209cc3
Packit 209cc3
					i++;
Packit 209cc3
				}
Packit 209cc3
Packit 209cc3
				if (i > MAX_ACTIVE_LIST)
Packit 209cc3
					rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
Packit 209cc3
Packit 209cc3
				// I don't initialize the remaining part of the structure, since
Packit 209cc3
				// it is already zeroed (it is a global var)
Packit 209cc3
				break;
Packit 209cc3
			}
Packit 209cc3
			case 'f':
Packit 209cc3
				pcap_strlcpy(loadfile, optarg, MAX_LINE);
Packit 209cc3
				break;
Packit 209cc3
			case 's':
Packit 209cc3
				pcap_strlcpy(savefile, optarg, MAX_LINE);
Packit 209cc3
				break;
Packit 209cc3
			case 'h':
Packit 209cc3
				printusage();
Packit 209cc3
				exit(0);
Packit 209cc3
				/*NOTREACHED*/
Packit 209cc3
			default:
Packit 209cc3
				exit(1);
Packit 209cc3
				/*NOTREACHED*/
Packit 209cc3
		}
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	if (isdaemon && isrunbyinetd)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
Packit 209cc3
		exit(1);
Packit 209cc3
	}
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
		exit(-1);
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	if (savefile[0] && fileconf_save(savefile))
Packit 209cc3
		rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
Packit 209cc3
Packit 209cc3
	// If the file does not exist, it keeps the settings provided by the command line
Packit 209cc3
	if (loadfile[0])
Packit 209cc3
		fileconf_read();
Packit 209cc3
Packit 209cc3
#ifdef WIN32
Packit 209cc3
	//
Packit 209cc3
	// Create a handle to signal the main loop to tell it to do
Packit 209cc3
	// something.
Packit 209cc3
	//
Packit 209cc3
	state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
Packit 209cc3
	if (state_change_event == NULL)
Packit 209cc3
	{
Packit 209cc3
		sock_geterror("Can't create state change event", errbuf,
Packit 209cc3
		    PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
		exit(2);
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Catch control signals.
Packit 209cc3
	//
Packit 209cc3
	if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
Packit 209cc3
	{
Packit 209cc3
		sock_geterror("Can't set control handler", errbuf,
Packit 209cc3
		    PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
		exit(2);
Packit 209cc3
	}
Packit 209cc3
#else
Packit 209cc3
	memset(&action, 0, sizeof (action));
Packit 209cc3
	action.sa_handler = main_terminate;
Packit 209cc3
	action.sa_flags = 0;
Packit 209cc3
	sigemptyset(&action.sa_mask);
Packit 209cc3
	sigaction(SIGTERM, &action, NULL);
Packit 209cc3
	memset(&action, 0, sizeof (action));
Packit 209cc3
	action.sa_handler = main_reap_children;
Packit 209cc3
	action.sa_flags = 0;
Packit 209cc3
	sigemptyset(&action.sa_mask);
Packit 209cc3
	sigaction(SIGCHLD, &action, NULL);
Packit 209cc3
	// Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
Packit 209cc3
	// connection, we don't want to get killed by a signal in that case
Packit 209cc3
	signal(SIGPIPE, SIG_IGN);
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	if (isrunbyinetd)
Packit 209cc3
	{
Packit 209cc3
		//
Packit 209cc3
		// -i was specified, indicating that this is being run
Packit 209cc3
		// by inetd or something that can run network daemons
Packit 209cc3
		// as if it were inetd (xinetd, launchd, systemd, etc.).
Packit 209cc3
		//
Packit 209cc3
		// We assume that the program that launched us just
Packit 209cc3
		// duplicated a single socket for the connection
Packit 209cc3
		// to our standard input, output, and error, so we
Packit 209cc3
		// can just use the standard input as our control
Packit 209cc3
		// socket.
Packit 209cc3
		//
Packit 209cc3
		int sockctrl;
Packit 209cc3
		int devnull_fd;
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Duplicate the standard input as the control socket.
Packit 209cc3
		//
Packit 209cc3
		sockctrl = dup(0);
Packit 209cc3
		if (sockctrl == -1)
Packit 209cc3
		{
Packit 209cc3
			sock_geterror("Can't dup standard input", errbuf,
Packit 209cc3
			    PCAP_ERRBUF_SIZE);
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Try to set the standard input, output, and error
Packit 209cc3
		// to /dev/null.
Packit 209cc3
		//
Packit 209cc3
		devnull_fd = open("/dev/null", O_RDWR);
Packit 209cc3
		if (devnull_fd != -1)
Packit 209cc3
		{
Packit 209cc3
			//
Packit 209cc3
			// If this fails, just drive on.
Packit 209cc3
			//
Packit 209cc3
			(void)dup2(devnull_fd, 0);
Packit 209cc3
			(void)dup2(devnull_fd, 1);
Packit 209cc3
			(void)dup2(devnull_fd, 2);
Packit 209cc3
			close(devnull_fd);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Handle this client.
Packit 209cc3
		// This is passive mode, so we don't care whether we were
Packit 209cc3
		// told by the client to close.
Packit 209cc3
		//
Packit 209cc3
		char *hostlist_copy = strdup(hostlist);
Packit 209cc3
		if (hostlist_copy == NULL)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
Packit 209cc3
			exit(0);
Packit 209cc3
		}
Packit 209cc3
		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
Packit 209cc3
		    nullAuthAllowed);
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Nothing more to do.
Packit 209cc3
		//
Packit 209cc3
		exit(0);
Packit 209cc3
	}
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	if (isdaemon)
Packit 209cc3
	{
Packit 209cc3
		//
Packit 209cc3
		// This is being run as a daemon.
Packit 209cc3
		// On UN*X, it might be manually run, or run from an
Packit 209cc3
		// rc file.
Packit 209cc3
		//
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
		int pid;
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Daemonize ourselves.
Packit 209cc3
		//
Packit 209cc3
		// Unix Network Programming, pg 336
Packit 209cc3
		//
Packit 209cc3
		if ((pid = fork()) != 0)
Packit 209cc3
			exit(0);		// Parent terminates
Packit 209cc3
Packit 209cc3
		// First child continues
Packit 209cc3
		// Set daemon mode
Packit 209cc3
		setsid();
Packit 209cc3
Packit 209cc3
		// generated under unix with 'kill -HUP', needed to reload the configuration
Packit 209cc3
		memset(&action, 0, sizeof (action));
Packit 209cc3
		action.sa_handler = main_reread_config;
Packit 209cc3
		action.sa_flags = 0;
Packit 209cc3
		sigemptyset(&action.sa_mask);
Packit 209cc3
		sigaction(SIGHUP, &action, NULL);
Packit 209cc3
Packit 209cc3
		if ((pid = fork()) != 0)
Packit 209cc3
			exit(0);		// First child terminates
Packit 209cc3
Packit 209cc3
		// LINUX WARNING: the current linux implementation of pthreads requires a management thread
Packit 209cc3
		// to handle some hidden stuff. So, as soon as you create the first thread, two threads are
Packit 209cc3
		// created. Fom this point on, the number of threads active are always one more compared
Packit 209cc3
		// to the number you're expecting
Packit 209cc3
Packit 209cc3
		// Second child continues
Packit 209cc3
//		umask(0);
Packit 209cc3
//		chdir("/");
Packit 209cc3
#else
Packit 209cc3
		//
Packit 209cc3
		// This is being run as a service on Windows.
Packit 209cc3
		//
Packit 209cc3
		// If this call succeeds, it is blocking on Win32
Packit 209cc3
		//
Packit 209cc3
		if (svc_start() != 1)
Packit 209cc3
			rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
Packit 209cc3
Packit 209cc3
		// When the previous call returns, the entire application has to be stopped.
Packit 209cc3
		exit(0);
Packit 209cc3
#endif
Packit 209cc3
	}
Packit 209cc3
	else	// Console mode
Packit 209cc3
	{
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
		// Enable the catching of Ctrl+C
Packit 209cc3
		memset(&action, 0, sizeof (action));
Packit 209cc3
		action.sa_handler = main_terminate;
Packit 209cc3
		action.sa_flags = 0;
Packit 209cc3
		sigemptyset(&action.sa_mask);
Packit 209cc3
		sigaction(SIGINT, &action, NULL);
Packit 209cc3
Packit 209cc3
		// generated under unix with 'kill -HUP', needed to reload the configuration
Packit 209cc3
		// We do not have this kind of signal in Win32
Packit 209cc3
		memset(&action, 0, sizeof (action));
Packit 209cc3
		action.sa_handler = main_reread_config;
Packit 209cc3
		action.sa_flags = 0;
Packit 209cc3
		sigemptyset(&action.sa_mask);
Packit 209cc3
		sigaction(SIGHUP, &action, NULL);
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
		printf("Press CTRL + C to stop the server...\n");
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	// If we're a Win32 service, we have already called this function in the service_main
Packit 209cc3
	main_startup();
Packit 209cc3
Packit 209cc3
	// The code should never arrive here (since the main_startup is blocking)
Packit 209cc3
	//  however this avoids a compiler warning
Packit 209cc3
	exit(0);
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
void main_startup(void)
Packit 209cc3
{
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
Packit 209cc3
	int i;
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
	HANDLE threadId;			// handle for the subthread
Packit 209cc3
#else
Packit 209cc3
	pid_t pid;
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	i = 0;
Packit 209cc3
	addrinfo = NULL;
Packit 209cc3
	memset(errbuf, 0, sizeof(errbuf));
Packit 209cc3
Packit 209cc3
	// Starts all the active threads
Packit 209cc3
	while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
Packit 209cc3
	{
Packit 209cc3
		activelist[i].ai_family = mainhints.ai_family;
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
		threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
Packit 209cc3
		    (void *)&activelist[i], 0, NULL);
Packit 209cc3
		if (threadId == 0)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
Packit 209cc3
			continue;
Packit 209cc3
		}
Packit 209cc3
		CloseHandle(threadId);
Packit 209cc3
#else
Packit 209cc3
		if ((pid = fork()) == 0)	// I am the child
Packit 209cc3
		{
Packit 209cc3
			main_active((void *) &activelist[i]);
Packit 209cc3
			exit(0);
Packit 209cc3
		}
Packit 209cc3
#endif
Packit 209cc3
		i++;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	/*
Packit 209cc3
	 * The code that manages the active connections is not blocking;
Packit 209cc3
	 * the code that manages the passive connection is blocking.
Packit 209cc3
	 * So, if the user does not want to run in passive mode, we have
Packit 209cc3
	 * to block the main thread here, otherwise the program ends and
Packit 209cc3
	 * all threads are stopped.
Packit 209cc3
	 *
Packit 209cc3
	 * WARNING: this means that in case we have only active mode,
Packit 209cc3
	 * the program does not terminate even if all the child thread
Packit 209cc3
	 * terminates. The user has always to press Ctrl+C (or send a
Packit 209cc3
	 * SIGTERM) to terminate the program.
Packit 209cc3
	 */
Packit 209cc3
	if (passivemode)
Packit 209cc3
	{
Packit 209cc3
		struct addrinfo *tempaddrinfo;
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Get a list of sockets on which to listen.
Packit 209cc3
		//
Packit 209cc3
		if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
Packit 209cc3
			return;
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		for (tempaddrinfo = addrinfo; tempaddrinfo;
Packit 209cc3
		     tempaddrinfo = tempaddrinfo->ai_next)
Packit 209cc3
		{
Packit 209cc3
			SOCKET sock;
Packit 209cc3
			struct listen_sock *sock_info;
Packit 209cc3
Packit 209cc3
			if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
Packit 209cc3
			{
Packit 209cc3
				switch (tempaddrinfo->ai_family)
Packit 209cc3
				{
Packit 209cc3
				case AF_INET:
Packit 209cc3
				{
Packit 209cc3
					struct sockaddr_in *in;
Packit 209cc3
					char addrbuf[INET_ADDRSTRLEN];
Packit 209cc3
Packit 209cc3
					in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
Packit 209cc3
					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
Packit 209cc3
					    inet_ntop(AF_INET, &in->sin_addr,
Packit 209cc3
						addrbuf, sizeof (addrbuf)),
Packit 209cc3
					    ntohs(in->sin_port),
Packit 209cc3
					    errbuf);
Packit 209cc3
					break;
Packit 209cc3
				}
Packit 209cc3
Packit 209cc3
				case AF_INET6:
Packit 209cc3
				{
Packit 209cc3
					struct sockaddr_in6 *in6;
Packit 209cc3
					char addrbuf[INET6_ADDRSTRLEN];
Packit 209cc3
Packit 209cc3
					in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
Packit 209cc3
					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
Packit 209cc3
					    inet_ntop(AF_INET6, &in6->sin6_addr,
Packit 209cc3
						addrbuf, sizeof (addrbuf)),
Packit 209cc3
					    ntohs(in6->sin6_port),
Packit 209cc3
					    errbuf);
Packit 209cc3
					break;
Packit 209cc3
				}
Packit 209cc3
Packit 209cc3
				default:
Packit 209cc3
					rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
Packit 209cc3
					    tempaddrinfo->ai_family,
Packit 209cc3
					    errbuf);
Packit 209cc3
					break;
Packit 209cc3
				}
Packit 209cc3
				continue;
Packit 209cc3
			}
Packit 209cc3
Packit 209cc3
			sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
Packit 209cc3
			if (sock_info == NULL)
Packit 209cc3
			{
Packit 209cc3
				rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
Packit 209cc3
				exit(2);
Packit 209cc3
			}
Packit 209cc3
			sock_info->sock = sock;
Packit 209cc3
			sock_info->next = listen_socks;
Packit 209cc3
			listen_socks = sock_info;
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		freeaddrinfo(addrinfo);
Packit 209cc3
Packit 209cc3
		if (listen_socks == NULL)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Now listen on all of them, waiting for connections.
Packit 209cc3
		//
Packit 209cc3
		accept_connections();
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// We're done; exit.
Packit 209cc3
	//
Packit 209cc3
	rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
Packit 209cc3
Packit 209cc3
#ifndef _WIN32
Packit 209cc3
	//
Packit 209cc3
	// Sends a KILL signal to all the processes in this process's
Packit 209cc3
	// process group; i.e., it kills all the child processes
Packit 209cc3
	// we've created.
Packit 209cc3
	//
Packit 209cc3
	// XXX - that also includes us, so we will be killed as well;
Packit 209cc3
	// that may cause a message to be printed or logged.
Packit 209cc3
	//
Packit 209cc3
	kill(0, SIGKILL);
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Just leave.  We shouldn't need to clean up sockets or
Packit 209cc3
	// anything else, and if we try to do so, we'll could end
Packit 209cc3
	// up closing sockets, or shutting Winsock down, out from
Packit 209cc3
	// under service loops, causing all sorts of noisy error
Packit 209cc3
	// messages.
Packit 209cc3
	//
Packit 209cc3
	// We shouldn't need to worry about cleaning up any resources
Packit 209cc3
	// such as handles, sockets, threads, etc. - exit() should
Packit 209cc3
	// terminate the process, causing all those resources to be
Packit 209cc3
	// cleaned up (including the threads; Microsoft claims in the
Packit 209cc3
	// ExitProcess() documentation that, if ExitProcess() is called,
Packit 209cc3
	// "If a thread is waiting on a kernel object, it will not be
Packit 209cc3
	// terminated until the wait has completed.", but claims in the
Packit 209cc3
	// _beginthread()/_beginthreadex() documentation that "All threads
Packit 209cc3
	// are terminated if any thread calls abort, exit, _exit, or
Packit 209cc3
	// ExitProcess." - the latter appears to be the case, even for
Packit 209cc3
	// threads waiting on the event for a pcap_t).
Packit 209cc3
	//
Packit 209cc3
	exit(0);
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
static void
Packit 209cc3
send_state_change_event(void)
Packit 209cc3
{
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
Packit 209cc3
	if (!SetEvent(state_change_event))
Packit 209cc3
	{
Packit 209cc3
		sock_geterror("SetEvent on shutdown event failed", errbuf,
Packit 209cc3
		    PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
	}
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
void
Packit 209cc3
send_shutdown_notification(void)
Packit 209cc3
{
Packit 209cc3
	//
Packit 209cc3
	// Indicate that the server should shut down.
Packit 209cc3
	//
Packit 209cc3
	shutdown_server = 1;
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Send a state change event, to wake up WSAWaitForMultipleEvents().
Packit 209cc3
	//
Packit 209cc3
	send_state_change_event();
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
void
Packit 209cc3
send_reread_configuration_notification(void)
Packit 209cc3
{
Packit 209cc3
	//
Packit 209cc3
	// Indicate that the server should re-read its configuration file.
Packit 209cc3
	//
Packit 209cc3
	reread_config = 1;
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Send a state change event, to wake up WSAWaitForMultipleEvents().
Packit 209cc3
	//
Packit 209cc3
	send_state_change_event();
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
Packit 209cc3
{
Packit 209cc3
	//
Packit 209cc3
	// ctrltype is one of:
Packit 209cc3
	//
Packit 209cc3
	// CTRL_C_EVENT - we got a ^C; this is like SIGINT
Packit 209cc3
	// CTRL_BREAK_EVENT - we got Ctrl+Break
Packit 209cc3
	// CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
Packit 209cc3
	// CTRL_LOGOFF_EVENT - a user is logging off; this is received
Packit 209cc3
	//   only by services
Packit 209cc3
	// CTRL_SHUTDOWN_EVENT - the systemis shutting down; this is
Packit 209cc3
	//   received only by services
Packit 209cc3
	//
Packit 209cc3
	// For now, we treat all but CTRL_LOGOFF_EVENT as indications
Packit 209cc3
	// that we should shut down.
Packit 209cc3
	//
Packit 209cc3
	switch (ctrltype)
Packit 209cc3
	{
Packit 209cc3
		case CTRL_C_EVENT:
Packit 209cc3
		case CTRL_BREAK_EVENT:
Packit 209cc3
		case CTRL_CLOSE_EVENT:
Packit 209cc3
		case CTRL_SHUTDOWN_EVENT:
Packit 209cc3
			//
Packit 209cc3
			// Set a shutdown notification.
Packit 209cc3
			//
Packit 209cc3
			send_shutdown_notification();
Packit 209cc3
			break;
Packit 209cc3
Packit 209cc3
		default:
Packit 209cc3
			break;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// We handled this.
Packit 209cc3
	//
Packit 209cc3
	return TRUE;
Packit 209cc3
}
Packit 209cc3
#else
Packit 209cc3
static void main_terminate(int sign _U_)
Packit 209cc3
{
Packit 209cc3
	//
Packit 209cc3
	// Note that the server should shut down.
Packit 209cc3
	// select() should get an EINTR error when we return,
Packit 209cc3
	// so it will wake up and know it needs to check the flag.
Packit 209cc3
	//
Packit 209cc3
	shutdown_server = 1;
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
static void main_reread_config(int sign _U_)
Packit 209cc3
{
Packit 209cc3
	//
Packit 209cc3
	// Note that the server should re-read its configuration file.
Packit 209cc3
	// select() should get an EINTR error when we return,
Packit 209cc3
	// so it will wake up and know it needs to check the flag.
Packit 209cc3
	//
Packit 209cc3
	reread_config = 1;
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
static void main_reap_children(int sign _U_)
Packit 209cc3
{
Packit 209cc3
	pid_t pid;
Packit 209cc3
	int exitstat;
Packit 209cc3
Packit 209cc3
	// Reap all child processes that have exited.
Packit 209cc3
	// For reference, Stevens, pg 128
Packit 209cc3
Packit 209cc3
	while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
Packit 209cc3
		rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
Packit 209cc3
Packit 209cc3
	return;
Packit 209cc3
}
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
//
Packit 209cc3
// Loop waiting for incoming connections and accepting them.
Packit 209cc3
//
Packit 209cc3
static void
Packit 209cc3
accept_connections(void)
Packit 209cc3
{
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
	struct listen_sock *sock_info;
Packit 209cc3
	DWORD num_events;
Packit 209cc3
	WSAEVENT *events;
Packit 209cc3
	int i;
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// How big does the set of events need to be?
Packit 209cc3
	// One for the shutdown event, plus one for every socket on which
Packit 209cc3
	// we'll be listening.
Packit 209cc3
	//
Packit 209cc3
	num_events = 1;		// shutdown event
Packit 209cc3
	for (sock_info = listen_socks; sock_info;
Packit 209cc3
	    sock_info = sock_info->next)
Packit 209cc3
	{
Packit 209cc3
		if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
Packit 209cc3
		{
Packit 209cc3
			//
Packit 209cc3
			// WSAWaitForMultipleEvents() doesn't support
Packit 209cc3
			// more than WSA_MAXIMUM_WAIT_EVENTS events
Packit 209cc3
			// on which to wait.
Packit 209cc3
			//
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
		num_events++;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Allocate the array of events.
Packit 209cc3
	//
Packit 209cc3
	events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
Packit 209cc3
	if (events == NULL)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
Packit 209cc3
		exit(2);
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Fill it in.
Packit 209cc3
	//
Packit 209cc3
	events[0] = state_change_event;	// state change event first
Packit 209cc3
	for (sock_info = listen_socks, i = 1; sock_info;
Packit 209cc3
	    sock_info = sock_info->next, i++)
Packit 209cc3
	{
Packit 209cc3
		WSAEVENT event;
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Create an event that is signaled if there's a connection
Packit 209cc3
		// to accept on the socket in question.
Packit 209cc3
		//
Packit 209cc3
		event = WSACreateEvent();
Packit 209cc3
		if (event == WSA_INVALID_EVENT)
Packit 209cc3
		{
Packit 209cc3
			sock_geterror("Can't create socket event", errbuf,
Packit 209cc3
			    PCAP_ERRBUF_SIZE);
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
		if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
Packit 209cc3
		{
Packit 209cc3
			sock_geterror("Can't setup socket event", errbuf,
Packit 209cc3
			    PCAP_ERRBUF_SIZE);
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
		events[i] = event;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	for (;;)
Packit 209cc3
	{
Packit 209cc3
		//
Packit 209cc3
		// Wait for incoming connections.
Packit 209cc3
		//
Packit 209cc3
		DWORD ret;
Packit 209cc3
Packit 209cc3
		ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
Packit 209cc3
		    WSA_INFINITE, FALSE);
Packit 209cc3
		if (ret == WSA_WAIT_FAILED)
Packit 209cc3
		{
Packit 209cc3
			sock_geterror("WSAWaitForMultipleEvents failed", errbuf,
Packit 209cc3
			    PCAP_ERRBUF_SIZE);
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
			exit(2);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		if (ret == WSA_WAIT_EVENT_0)
Packit 209cc3
		{
Packit 209cc3
			//
Packit 209cc3
			// The state change event was set.
Packit 209cc3
			//
Packit 209cc3
			if (shutdown_server)
Packit 209cc3
			{
Packit 209cc3
				//
Packit 209cc3
				// Time to quit. Exit the loop.
Packit 209cc3
				//
Packit 209cc3
				break;
Packit 209cc3
			}
Packit 209cc3
			if (reread_config)
Packit 209cc3
			{
Packit 209cc3
				//
Packit 209cc3
				// We should re-read the configuration
Packit 209cc3
				// file.
Packit 209cc3
				//
Packit 209cc3
				reread_config = 0;	// clear the indicator
Packit 209cc3
				fileconf_read();
Packit 209cc3
			}
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Check each socket.
Packit 209cc3
		//
Packit 209cc3
		for (sock_info = listen_socks, i = 1; sock_info;
Packit 209cc3
		    sock_info = sock_info->next, i++)
Packit 209cc3
		{
Packit 209cc3
			WSANETWORKEVENTS network_events;
Packit 209cc3
Packit 209cc3
			if (WSAEnumNetworkEvents(sock_info->sock,
Packit 209cc3
			    events[i], &network_events) == SOCKET_ERROR)
Packit 209cc3
			{
Packit 209cc3
				sock_geterror("WSAEnumNetworkEvents failed",
Packit 209cc3
				    errbuf, PCAP_ERRBUF_SIZE);
Packit 209cc3
				rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
				exit(2);
Packit 209cc3
			}
Packit 209cc3
			if (network_events.lNetworkEvents & FD_ACCEPT)
Packit 209cc3
			{
Packit 209cc3
				//
Packit 209cc3
				// Did an error occur?
Packit 209cc3
				//
Packit 209cc3
			 	if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
Packit 209cc3
			 	{
Packit 209cc3
					//
Packit 209cc3
					// Yes - report it and keep going.
Packit 209cc3
					//
Packit 209cc3
					sock_fmterror("Socket error",
Packit 209cc3
					    network_events.iErrorCode[FD_ACCEPT_BIT],
Packit 209cc3
					    errbuf,
Packit 209cc3
					    PCAP_ERRBUF_SIZE);
Packit 209cc3
					rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
					continue;
Packit 209cc3
				}
Packit 209cc3
Packit 209cc3
				//
Packit 209cc3
				// Accept the connection.
Packit 209cc3
				//
Packit 209cc3
				accept_connection(sock_info->sock);
Packit 209cc3
			}
Packit 209cc3
		}
Packit 209cc3
	}
Packit 209cc3
#else
Packit 209cc3
	struct listen_sock *sock_info;
Packit 209cc3
	int num_sock_fds;
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// How big does the bitset of sockets on which to select() have
Packit 209cc3
	// to be?
Packit 209cc3
	//
Packit 209cc3
	num_sock_fds = 0;
Packit 209cc3
	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
Packit 209cc3
	{
Packit 209cc3
		if (sock_info->sock + 1 > num_sock_fds)
Packit 209cc3
		{
Packit 209cc3
			if ((unsigned int)(sock_info->sock + 1) >
Packit 209cc3
			    (unsigned int)FD_SETSIZE)
Packit 209cc3
			{
Packit 209cc3
				rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
Packit 209cc3
				exit(2);
Packit 209cc3
			}
Packit 209cc3
			num_sock_fds = sock_info->sock + 1;
Packit 209cc3
		}
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	for (;;)
Packit 209cc3
	{
Packit 209cc3
		fd_set sock_fds;
Packit 209cc3
		int ret;
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Set up an fd_set for all the sockets on which we're
Packit 209cc3
		// listening.
Packit 209cc3
		//
Packit 209cc3
		// This set is modified by select(), so we have to
Packit 209cc3
		// construct it anew each time.
Packit 209cc3
		//
Packit 209cc3
		FD_ZERO(&sock_fds);
Packit 209cc3
		for (sock_info = listen_socks; sock_info;
Packit 209cc3
		    sock_info = sock_info->next)
Packit 209cc3
		{
Packit 209cc3
			FD_SET(sock_info->sock, &sock_fds);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Wait for incoming connections.
Packit 209cc3
		//
Packit 209cc3
		ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
Packit 209cc3
		if (ret == -1)
Packit 209cc3
		{
Packit 209cc3
			if (errno == EINTR)
Packit 209cc3
			{
Packit 209cc3
				//
Packit 209cc3
				// If this is a "terminate the
Packit 209cc3
				// server" signal, exit the loop,
Packit 209cc3
				// otherwise just keep trying.
Packit 209cc3
				//
Packit 209cc3
				if (shutdown_server)
Packit 209cc3
				{
Packit 209cc3
					//
Packit 209cc3
					// Time to quit.  Exit the loop.
Packit 209cc3
					//
Packit 209cc3
					break;
Packit 209cc3
				}
Packit 209cc3
				if (reread_config)
Packit 209cc3
				{
Packit 209cc3
					//
Packit 209cc3
					// We should re-read the configuration
Packit 209cc3
					// file.
Packit 209cc3
					//
Packit 209cc3
					reread_config = 0;	// clear the indicator
Packit 209cc3
					fileconf_read();
Packit 209cc3
				}
Packit 209cc3
Packit 209cc3
				//
Packit 209cc3
				// Go back and wait again.
Packit 209cc3
				//
Packit 209cc3
				continue;
Packit 209cc3
			}
Packit 209cc3
			else
Packit 209cc3
			{
Packit 209cc3
				rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
Packit 209cc3
				    strerror(errno));
Packit 209cc3
				exit(2);
Packit 209cc3
			}
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Check each socket.
Packit 209cc3
		//
Packit 209cc3
		for (sock_info = listen_socks; sock_info;
Packit 209cc3
		    sock_info = sock_info->next)
Packit 209cc3
		{
Packit 209cc3
			if (FD_ISSET(sock_info->sock, &sock_fds))
Packit 209cc3
			{
Packit 209cc3
				//
Packit 209cc3
				// Accept the connection.
Packit 209cc3
				//
Packit 209cc3
				accept_connection(sock_info->sock);
Packit 209cc3
			}
Packit 209cc3
		}
Packit 209cc3
	}
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Close all the listen sockets.
Packit 209cc3
	//
Packit 209cc3
	for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
Packit 209cc3
	{
Packit 209cc3
		closesocket(sock_info->sock);
Packit 209cc3
	}
Packit 209cc3
	sock_cleanup();
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
//
Packit 209cc3
// A structure to hold the parameters to the daemon service loop
Packit 209cc3
// thread on Windows.
Packit 209cc3
//
Packit 209cc3
// (On UN*X, there is no need for this explicit copy since the
Packit 209cc3
// fork "inherits" the parent stack.)
Packit 209cc3
//
Packit 209cc3
struct params_copy {
Packit 209cc3
	SOCKET sockctrl;
Packit 209cc3
	char *hostlist;
Packit 209cc3
};
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
//
Packit 209cc3
// Accept a connection and start a worker thread, on Windows, or a
Packit 209cc3
// worker process, on UN*X, to handle the connection.
Packit 209cc3
//
Packit 209cc3
static void
Packit 209cc3
accept_connection(SOCKET listen_sock)
Packit 209cc3
{
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
	SOCKET sockctrl;			// keeps the socket ID for this control connection
Packit 209cc3
	struct sockaddr_storage from;		// generic sockaddr_storage variable
Packit 209cc3
	socklen_t fromlen;			// keeps the length of the sockaddr_storage variable
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
	HANDLE threadId;			// handle for the subthread
Packit 209cc3
	u_long off = 0;
Packit 209cc3
	struct params_copy *params_copy = NULL;
Packit 209cc3
#else
Packit 209cc3
	pid_t pid;
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
	// Initialize errbuf
Packit 209cc3
	memset(errbuf, 0, sizeof(errbuf));
Packit 209cc3
Packit 209cc3
	for (;;)
Packit 209cc3
	{
Packit 209cc3
		// Accept the connection
Packit 209cc3
		fromlen = sizeof(struct sockaddr_storage);
Packit 209cc3
Packit 209cc3
		sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
Packit 209cc3
Packit 209cc3
		if (sockctrl != INVALID_SOCKET)
Packit 209cc3
		{
Packit 209cc3
			// Success.
Packit 209cc3
			break;
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		// The accept() call can return this error when a signal is catched
Packit 209cc3
		// In this case, we have simply to ignore this error code
Packit 209cc3
		// Stevens, pg 124
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
		if (WSAGetLastError() == WSAEINTR)
Packit 209cc3
#else
Packit 209cc3
		if (errno == EINTR)
Packit 209cc3
#endif
Packit 209cc3
			continue;
Packit 209cc3
Packit 209cc3
		// Don't check for errors here, since the error can be due to the fact that the thread
Packit 209cc3
		// has been killed
Packit 209cc3
		sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
Packit 209cc3
		    errbuf);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
	//
Packit 209cc3
	// Put the socket back into blocking mode; doing WSAEventSelect()
Packit 209cc3
	// on the listen socket makes that socket non-blocking, and it
Packit 209cc3
	// appears that sockets returned from an accept() on that socket
Packit 209cc3
	// are also non-blocking.
Packit 209cc3
	//
Packit 209cc3
	// First, we have to un-WSAEventSelect() this socket, and then
Packit 209cc3
	// we can turn non-blocking mode off.
Packit 209cc3
	//
Packit 209cc3
	// If this fails, we aren't guaranteed that, for example, any
Packit 209cc3
	// of the error message will be sent - if it can't be put in
Packit 209cc3
	// the socket queue, the send will just fail.
Packit 209cc3
	//
Packit 209cc3
	// So we just log the message and close the connection.
Packit 209cc3
	//
Packit 209cc3
	if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
Packit 209cc3
	{
Packit 209cc3
		sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
	if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
Packit 209cc3
	{
Packit 209cc3
		sock_geterror("ioctlsocket(FIONBIO)", errbuf, PCAP_ERRBUF_SIZE);
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Make a copy of the host list to pass to the new thread, so that
Packit 209cc3
	// if we update it in the main thread, it won't catch us in the
Packit 209cc3
	// middle of updating it.
Packit 209cc3
	//
Packit 209cc3
	// daemon_serviceloop() will free it once it's done with it.
Packit 209cc3
	//
Packit 209cc3
	char *hostlist_copy = strdup(hostlist);
Packit 209cc3
	if (hostlist_copy == NULL)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Allocate a location to hold the values of sockctrl.
Packit 209cc3
	// It will be freed in the newly-created thread once it's
Packit 209cc3
	// finished with it.
Packit 209cc3
	//
Packit 209cc3
	params_copy = malloc(sizeof(*params_copy));
Packit 209cc3
	if (params_copy == NULL)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
Packit 209cc3
		free(hostlist_copy);
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
	params_copy->sockctrl = sockctrl;
Packit 209cc3
	params_copy->hostlist = hostlist_copy;
Packit 209cc3
Packit 209cc3
	threadId = (HANDLE)_beginthreadex(NULL, 0,
Packit 209cc3
	    main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
Packit 209cc3
	if (threadId == 0)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
Packit 209cc3
		free(params_copy);
Packit 209cc3
		free(hostlist_copy);
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
	CloseHandle(threadId);
Packit 209cc3
#else /* _WIN32 */
Packit 209cc3
	pid = fork();
Packit 209cc3
	if (pid == -1)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
Packit 209cc3
		    strerror(errno));
Packit 209cc3
		sock_close(sockctrl, NULL, 0);
Packit 209cc3
		return;
Packit 209cc3
	}
Packit 209cc3
	if (pid == 0)
Packit 209cc3
	{
Packit 209cc3
		//
Packit 209cc3
		// Child process.
Packit 209cc3
		//
Packit 209cc3
		// Close the socket on which we're listening (must
Packit 209cc3
		// be open only in the parent).
Packit 209cc3
		//
Packit 209cc3
		closesocket(listen_sock);
Packit 209cc3
Packit 209cc3
#if 0
Packit 209cc3
		//
Packit 209cc3
		// Modify thread params so that it can be killed at any time
Packit 209cc3
		// XXX - is this necessary?  This is the main and, currently,
Packit 209cc3
		// only thread in the child process, and nobody tries to
Packit 209cc3
		// cancel us, although *we* may cancel the thread that's
Packit 209cc3
		// handling the capture loop.
Packit 209cc3
		//
Packit 209cc3
		if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
Packit 209cc3
			goto end;
Packit 209cc3
		if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
Packit 209cc3
			goto end;
Packit 209cc3
#endif
Packit 209cc3
Packit 209cc3
		//
Packit 209cc3
		// Run the service loop.
Packit 209cc3
		// This is passive mode, so we don't care whether we were
Packit 209cc3
		// told by the client to close.
Packit 209cc3
		//
Packit 209cc3
		char *hostlist_copy = strdup(hostlist);
Packit 209cc3
		if (hostlist_copy == NULL)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
Packit 209cc3
			exit(0);
Packit 209cc3
		}
Packit 209cc3
		(void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
Packit 209cc3
		    nullAuthAllowed);
Packit 209cc3
Packit 209cc3
		exit(0);
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	// I am the parent
Packit 209cc3
	// Close the socket for this session (must be open only in the child)
Packit 209cc3
	closesocket(sockctrl);
Packit 209cc3
#endif /* _WIN32 */
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
/*!
Packit 209cc3
	\brief 'true' main of the program in case the active mode is turned on.
Packit 209cc3
Packit 209cc3
	This function loops forever trying to connect to the remote host, until the
Packit 209cc3
	daemon is turned down.
Packit 209cc3
Packit 209cc3
	\param ptr: it keeps the 'activepars' parameters.  It is a 'void *'
Packit 209cc3
	just because the thread APIs want this format.
Packit 209cc3
*/
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
static unsigned __stdcall
Packit 209cc3
#else
Packit 209cc3
static void *
Packit 209cc3
#endif
Packit 209cc3
main_active(void *ptr)
Packit 209cc3
{
Packit 209cc3
	char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
Packit 209cc3
	SOCKET sockctrl;			// keeps the socket ID for this control connection
Packit 209cc3
	struct addrinfo hints;			// temporary struct to keep settings needed to open the new socket
Packit 209cc3
	struct addrinfo *addrinfo;		// keeps the addrinfo chain; required to open a new socket
Packit 209cc3
	struct active_pars *activepars;
Packit 209cc3
Packit 209cc3
	activepars = (struct active_pars *) ptr;
Packit 209cc3
Packit 209cc3
	// Prepare to open a new server socket
Packit 209cc3
	memset(&hints, 0, sizeof(struct addrinfo));
Packit 209cc3
						// WARNING Currently it supports only ONE socket family among IPv4 and IPv6
Packit 209cc3
	hints.ai_family = AF_INET;		// PF_UNSPEC to have both IPv4 and IPv6 server
Packit 209cc3
	hints.ai_socktype = SOCK_STREAM;
Packit 209cc3
	hints.ai_family = activepars->ai_family;
Packit 209cc3
Packit 209cc3
	rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
Packit 209cc3
	    activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
Packit 209cc3
	    (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
Packit 209cc3
Packit 209cc3
	// Initialize errbuf
Packit 209cc3
	memset(errbuf, 0, sizeof(errbuf));
Packit 209cc3
Packit 209cc3
	// Do the work
Packit 209cc3
	if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
Packit 209cc3
	{
Packit 209cc3
		rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
Packit 209cc3
		return 0;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	for (;;)
Packit 209cc3
	{
Packit 209cc3
		int activeclose;
Packit 209cc3
Packit 209cc3
		if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
Packit 209cc3
Packit 209cc3
			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
Packit 209cc3
					activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
Packit 209cc3
					(hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
Packit 209cc3
Packit 209cc3
			rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
Packit 209cc3
Packit 209cc3
			sleep_secs(RPCAP_ACTIVE_WAIT);
Packit 209cc3
Packit 209cc3
			continue;
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		char *hostlist_copy = strdup(hostlist);
Packit 209cc3
		if (hostlist_copy == NULL)
Packit 209cc3
		{
Packit 209cc3
			rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
Packit 209cc3
			activeclose = 0;
Packit 209cc3
			sock_close(sockctrl, NULL, 0);
Packit 209cc3
		}
Packit 209cc3
		else
Packit 209cc3
		{
Packit 209cc3
			//
Packit 209cc3
			// daemon_serviceloop() will free the copy.
Packit 209cc3
			//
Packit 209cc3
			activeclose = daemon_serviceloop(sockctrl, 1,
Packit 209cc3
			    hostlist_copy, nullAuthAllowed);
Packit 209cc3
		}
Packit 209cc3
Packit 209cc3
		// If the connection is closed by the user explicitely, don't try to connect to it again
Packit 209cc3
		// just exit the program
Packit 209cc3
		if (activeclose == 1)
Packit 209cc3
			break;
Packit 209cc3
	}
Packit 209cc3
Packit 209cc3
	freeaddrinfo(addrinfo);
Packit 209cc3
	return 0;
Packit 209cc3
}
Packit 209cc3
Packit 209cc3
#ifdef _WIN32
Packit 209cc3
//
Packit 209cc3
// Main routine of a passive-mode service thread.
Packit 209cc3
//
Packit 209cc3
unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
Packit 209cc3
{
Packit 209cc3
	struct params_copy params = *(struct params_copy *)ptr;
Packit 209cc3
	free(ptr);
Packit 209cc3
Packit 209cc3
	//
Packit 209cc3
	// Handle this client.
Packit 209cc3
	// This is passive mode, so we don't care whether we were
Packit 209cc3
	// told by the client to close.
Packit 209cc3
	//
Packit 209cc3
	(void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
Packit 209cc3
	    nullAuthAllowed);
Packit 209cc3
Packit 209cc3
	return 0;
Packit 209cc3
}
Packit 209cc3
#endif