📄 rpcapd.c
字号:
/*
* 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, PCAP_ERRBUF_SIZE) == -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', needed to reload the configuration
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);
#ifndef WIN32
// generated under unix with 'kill -HUP', needed to reload the configuration
// We do not have this kind of signal in Win32
signal(SIGHUP, fileconf_read);
#endif
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
pthread_attr_t detachedAttribute; // PThread attribute needed to create the thread as detached
#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
/* GV we need this to create the thread as detached. */
/* GV otherwise, the thread handle is not destroyed */
pthread_attr_init(&detachedAttribute);
pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
if ( pthread_create( &threadId, &detachedAttribute, (void *) &main_active, (void *) &activelist[i]) )
{
SOCK_ASSERT("Error creating the active child thread", 1);
pthread_attr_destroy(&detachedAttribute);
continue;
}
pthread_attr_destroy(&detachedAttribute);
#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.
So, if the user do not want to run in passive mode, we have to block
the main thread here, otherwise the program ends and all threads
are stopped.
WARNING: this means that in case we have only active mode, the program does
not terminate even if all the child thread terminates. The user has always to
press Ctrl+C (or send a SIGTERM) to terminate the program.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -