⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpcapd.c

📁 用来监视网络通信数据的源代码和应用程序,方便网络程序底层开发.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2002 - 2003
 * NetGroup, Politecnico di Torino (Italy)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright 
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution. 
 * 3. Neither the name of the Politecnico di Torino nor the names of its 
 * contributors may be used to endorse or promote products derived from 
 * this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */





#include <errno.h>		// for the errno variable
#include <string.h>		// for strtok, etc
#include <stdlib.h>		// for malloc(), free(), ...
#include <pcap.h>		// for PCAP_ERRBUF_SIZE
#include <signal.h>		// for signal()
#include <pthread.h>
#include "rpcapd.h"
#include "fileconf.h"	// for the configuration file management
#include "pcap-remote.h"
#include "daemon.h"		// the true main() method of this daemon
#include "utils.h"		// Missing calls and such
#include "sockutils.h"	// for socket calls

#ifndef WIN32
#include <unistd.h>		// for exit()
#include <sys/wait.h>	// waitpid()
#else
#include "win32-svc.h"	// for Win32 service stuff
#endif


// Global variables
char hostlist[MAX_HOST_LIST + 1];		//!< Keeps the list of the hosts that are allowed to connect to this server
struct active_pars activelist[MAX_ACTIVE_LIST];		//!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
int nullAuthAllowed;					//!< '1' if we permit NULL authentication, '0' otherwise
SOCKET sockmain;						//!< keeps the main socket identifier
char loadfile[MAX_LINE + 1];			//!< Name of the file from which we have to load the configuration
int passivemode= 1;						//!< '1' if we want to run in passive mode as well
struct addrinfo mainhints;				//!< temporary struct to keep settings needed to open the new socket
char address[MAX_LINE + 1];				//!< keeps the network address (either numeric or literal) to bind to
char port[MAX_LINE + 1];				//!< keeps the network port to bind to

extern char *optarg;	// for getopt()



// Function definition
void main_passive(void *ptr);
void main_active(void *ptr);


#ifndef WIN32
void main_cleanup_childs(int sign);
#endif


/*!
	\brief Prints the usage screen if it is launched in console mode.
*/
void printusage()
{
	char *usagetext =
	"USAGE:\n"
	" "  PROGRAM_NAME " [-b <address>] [-p <port>] [-6] [-l <host_list>] [-a <host,port>]\n"
	"        [-n] [-v] [-d] [-s <file>] [-f <file>]\n"
	"  -b <address>: the address to bind to (either numeric or literal).\n"
    "                Default: it binds to all local IPv4 addresses\n"
	"  -p <port>: the port to bind to. Default: it binds to port " RPCAP_DEFAULT_NETPORT "\n"
	"  -4: use only IPv4 (default both IPv4 and IPv6 waiting sockets are used)\n"
	"  -l <host_list>: a file that keeps the list of the hosts which\n"
	"                  are allowed to connect to this server (if more than one,\n"
	"                  list them one per line). We suggest to use \n"
	"                  literal names (instead of numeric ones) in order to avoid\n"
	"                  problems with different address families\n"
	"  -n: permit NULL authentication (usually used with '-l')\n"
	"  -a <host, port>: run in active mode when connecting to 'host' on port 'port'\n"
	"  -v: run in active mode only (default: if '-a' is specified, it accepts passive\n"
	"      connections as well\n"
	"  -d: run in daemon mode (UNIX only) or as a service (Win32 only)\n"
	"      Warning (Win32): this switch is provided automatically when the service\n"
	"      is started from the control panel\n"
	"  -s <file>: save the current configuration to file\n"
 	"  -f <file>: load the current configuration from file; all the switches\n"
  	"             specified from the command line are ignored\n"
   "  -h: print this help screen\n\n";

	printf(usagetext);
}



//! Program main
int main(int argc, char *argv[], char *envp[])
{
char savefile[MAX_LINE + 1];		// name of the file on which we have to save the configuration
int isdaemon= 0;					// Not null if the user wants to run this program as a daemon
int retval;							// keeps the returning value from several functions
char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed


	savefile[0]= 0;
	loadfile[0]= 0;
	hostlist[0]= 0;

	// Initialize errbuf
	memset(errbuf, 0, sizeof(errbuf) );

	if (sock_init(errbuf) == -1)
	{
		SOCK_ASSERT(errbuf, 1);
		exit(-1);
	}

	strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
	strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);

	// Prepare to open a new server socket
	memset(&mainhints, 0, sizeof(struct addrinfo));

	mainhints.ai_family = PF_UNSPEC;
	mainhints.ai_flags = AI_PASSIVE;	// Ready to a bind() socket
	mainhints.ai_socktype = SOCK_STREAM;

	// Getting the proper command line options
	while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1)
	{
		switch (retval)
		{
			case 'b':
				strncpy(address, optarg, MAX_LINE);
				break;
			case 'p':
				strncpy(port, optarg, MAX_LINE);
				break;
			case '4':
				mainhints.ai_family = PF_INET;		// IPv4 server only
				break;
			case 'd':
				isdaemon= 1;
				break;
			case 'n':
				nullAuthAllowed= 1;
				break;
			case 'v':
				passivemode= 0;
				break;
			case 'l':
			{
				strncpy(hostlist, optarg, sizeof(hostlist) );
				break;
			}
			case 'a':
			{
			char *tmpaddress, *tmpport;
			int i= 0;

				tmpaddress= strtok(optarg, RPCAP_HOSTLIST_SEP);

				while ( (tmpaddress != NULL) && (i < MAX_ACTIVE_LIST) )
				{
					tmpport= strtok(NULL, RPCAP_HOSTLIST_SEP);

					snprintf(activelist[i].address, MAX_LINE, tmpaddress);
					
					if ( (tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0) ) // the user choose a custom port
						snprintf(activelist[i].port, MAX_LINE, RPCAP_DEFAULT_NETPORT_ACTIVE);
					else
						snprintf(activelist[i].port, MAX_LINE, tmpport);

					tmpaddress = strtok(NULL, RPCAP_HOSTLIST_SEP);

					i++;
				}
				
				if (i > MAX_ACTIVE_LIST)
					SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);

				// I don't initialize the remaining part of the structure, since
				// it is already zeroed (it is a global var)
				break;
			}
			case 'f':
				strncpy(loadfile, optarg, MAX_LINE);
				break;
			case 's':
				strncpy(savefile, optarg, MAX_LINE);
				break;
			case 'h':
				printusage();
				exit(0);
			default:
				break;
		}
	}

	if (savefile[0])
	{
		if (fileconf_save(savefile) )
			SOCK_ASSERT("Error when saving the configuration to file", 1);
	}

	// If the file does not exist, it keeps the settings provided by the command line
	if (loadfile[0])
		fileconf_read(0);

#ifdef linux
	// SIGTERM (i.e. kill -15) is not generated in WIN32, although it is included for ANSI compatibility
	signal(SIGTERM, main_cleanup);
	signal(SIGCHLD, main_cleanup_childs);
#endif

	// forking a daemon, if it is needed
	if (isdaemon)
	{
	#ifndef WIN32
	int pid;

		// Unix Network Programming, pg 336
		if ( (pid = fork() ) != 0)
			exit(0);		// Parent terminates

		// First child continues
		// Set daemon mode
		setsid();
		
		// generated under unix with 'kill -HUP'
		signal(SIGHUP, fileconf_read);

		if ( (pid = fork() ) != 0)
			exit(0);		// First child terminates

		// LINUX WARNING: the current linux implementation of pthreads requires a management thread
		// to handle some hidden stuff. So, as soon as you create the first thread, two threads are
		// created. Fom this point on, the number of threads active are always one more compared
		// to the number you're expecting

		// Second child continues
//		umask(0);
//		chdir("/");
	#else
		// We use the SIGABRT signal to kill the Win32 service
		signal(SIGABRT, main_cleanup);

		// If this call succeeds, it is blocking on Win32
		if ( svc_start() != 1)
			SOCK_ASSERT(1, "Unable to start the service");

		// When the previous call returns, the entire application has to be stopped.
		exit(0);
	#endif
	}
	else	// Console mode
	{
		// Enable the catching of Ctrl+C
		signal(SIGINT, main_cleanup);

		printf("Press CTRL + C to stop the server...\n");
	}

	// If we're a Win32 service, we have already called this function in the service_main
	main_startup();

	// The code should never arrive here (since the main_startup is blocking)
	//  however this avoids a compiler warning
	exit(0);
}



void main_startup(void)
{
char errbuf[PCAP_ERRBUF_SIZE + 1];	// keeps the error string, prior to be printed
struct addrinfo *addrinfo;				// keeps the addrinfo chain; required to open a new socket
int i;
#ifdef WIN32
	pthread_t threadId;					// Pthread variable that keeps the thread structures
#else
	pid_t pid;
#endif

	i= 0;
	addrinfo= NULL;
	memset(errbuf, 0, sizeof(errbuf) );

	// Starts all the active threads
	while ( (activelist[i].address[0] != 0) && (i < MAX_ACTIVE_LIST) )
	{
		activelist[i].ai_family= mainhints.ai_family;
		
#ifdef WIN32
		if ( pthread_create( &threadId, NULL, (void *) &main_active, (void *) &activelist[i]) )
		{
			SOCK_ASSERT("Error creating the active child thread", 1);
			continue;
		}
#else
		if ( (pid= fork() ) == 0)	// I am the child
		{
			main_active( (void *) &activelist[i]);
			exit(0);
		}
#endif
		i++;
	}

	/*
		The code that manages the active connections is not blocking; 
		vice versa, the code that manages the passive connection is blocking.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -