1353141Sphilip/* 2353141Sphilip * Copyright (c) 2002 - 2003 3353141Sphilip * NetGroup, Politecnico di Torino (Italy) 4353141Sphilip * All rights reserved. 5353141Sphilip * 6353141Sphilip * Redistribution and use in source and binary forms, with or without 7353141Sphilip * modification, are permitted provided that the following conditions 8353141Sphilip * are met: 9353141Sphilip * 10353141Sphilip * 1. Redistributions of source code must retain the above copyright 11353141Sphilip * notice, this list of conditions and the following disclaimer. 12353141Sphilip * 2. Redistributions in binary form must reproduce the above copyright 13353141Sphilip * notice, this list of conditions and the following disclaimer in the 14353141Sphilip * documentation and/or other materials provided with the distribution. 15353141Sphilip * 3. Neither the name of the Politecnico di Torino nor the names of its 16353141Sphilip * contributors may be used to endorse or promote products derived from 17353141Sphilip * this software without specific prior written permission. 18353141Sphilip * 19353141Sphilip * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20353141Sphilip * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21353141Sphilip * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22353141Sphilip * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23353141Sphilip * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24353141Sphilip * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25353141Sphilip * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26353141Sphilip * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27353141Sphilip * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28353141Sphilip * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29353141Sphilip * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30353141Sphilip * 31353141Sphilip */ 32353141Sphilip 33353141Sphilip#ifdef HAVE_CONFIG_H 34353141Sphilip#include <config.h> 35353141Sphilip#endif 36353141Sphilip 37353141Sphilip#include "ftmacros.h" 38353141Sphilip 39353141Sphilip#include <errno.h> // for the errno variable 40353141Sphilip#include <string.h> // for strtok, etc 41353141Sphilip#include <stdlib.h> // for malloc(), free(), ... 42353141Sphilip#include <pcap.h> // for PCAP_ERRBUF_SIZE 43353141Sphilip#include <signal.h> // for signal() 44353141Sphilip 45353141Sphilip#include "fmtutils.h" 46353141Sphilip#include "sockutils.h" // for socket calls 47353141Sphilip#include "varattrs.h" // for _U_ 48353141Sphilip#include "portability.h" 49353141Sphilip#include "rpcapd.h" 50353141Sphilip#include "config_params.h" // configuration file parameters 51353141Sphilip#include "fileconf.h" // for the configuration file management 52353141Sphilip#include "rpcap-protocol.h" 53353141Sphilip#include "daemon.h" // the true main() method of this daemon 54353141Sphilip#include "log.h" 55353141Sphilip 56353141Sphilip#ifdef _WIN32 57353141Sphilip #include <process.h> // for thread stuff 58353141Sphilip #include "win32-svc.h" // for Win32 service stuff 59353141Sphilip #include "getopt.h" // for getopt()-for-Windows 60353141Sphilip#else 61353141Sphilip #include <fcntl.h> // for open() 62353141Sphilip #include <unistd.h> // for exit() 63353141Sphilip #include <sys/wait.h> // waitpid() 64353141Sphilip#endif 65353141Sphilip 66353141Sphilip// 67353141Sphilip// Element in list of sockets on which we're listening for connections. 68353141Sphilip// 69353141Sphilipstruct listen_sock { 70353141Sphilip struct listen_sock *next; 71353141Sphilip SOCKET sock; 72353141Sphilip}; 73353141Sphilip 74353141Sphilip// Global variables 75353141Sphilipchar hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server 76353141Sphilipstruct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) 77353141Sphilipint nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise 78353141Sphilipstatic struct listen_sock *listen_socks; //!< sockets on which we listen 79353141Sphilipchar loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration 80353141Sphilipstatic int passivemode = 1; //!< '1' if we want to run in passive mode as well 81353141Sphilipstatic struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket 82353141Sphilipstatic char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to 83353141Sphilipstatic char port[MAX_LINE + 1]; //!< keeps the network port to bind to 84353141Sphilip#ifdef _WIN32 85353141Sphilipstatic HANDLE state_change_event; //!< event to signal that a state change should take place 86353141Sphilip#endif 87353141Sphilipstatic volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down 88353141Sphilipstatic volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration 89353141Sphilip 90353141Sphilipextern char *optarg; // for getopt() 91353141Sphilip 92353141Sphilip// Function definition 93353141Sphilip#ifdef _WIN32 94353141Sphilipstatic unsigned __stdcall main_active(void *ptr); 95353141Sphilipstatic BOOL WINAPI main_ctrl_event(DWORD); 96353141Sphilip#else 97353141Sphilipstatic void *main_active(void *ptr); 98353141Sphilipstatic void main_terminate(int sign); 99353141Sphilipstatic void main_reread_config(int sign); 100353141Sphilip#endif 101353141Sphilipstatic void accept_connections(void); 102353141Sphilipstatic void accept_connection(SOCKET listen_sock); 103353141Sphilip#ifndef _WIN32 104353141Sphilipstatic void main_reap_children(int sign); 105353141Sphilip#endif 106353141Sphilip#ifdef _WIN32 107353141Sphilipstatic unsigned __stdcall main_passive_serviceloop_thread(void *ptr); 108353141Sphilip#endif 109353141Sphilip 110353141Sphilip#define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */ 111353141Sphilip 112353141Sphilip/*! 113353141Sphilip \brief Prints the usage screen if it is launched in console mode. 114353141Sphilip*/ 115353141Sphilipstatic void printusage(void) 116353141Sphilip{ 117353141Sphilip const char *usagetext = 118353141Sphilip "USAGE:" 119353141Sphilip " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n" 120353141Sphilip " [-n] [-v] [-d] " 121353141Sphilip#ifndef _WIN32 122353141Sphilip "[-i] " 123353141Sphilip#endif 124353141Sphilip "[-D] [-s <config_file>] [-f <config_file>]\n\n" 125353141Sphilip " -b <address> the address to bind to (either numeric or literal).\n" 126353141Sphilip " Default: binds to all local IPv4 and IPv6 addresses\n\n" 127353141Sphilip " -p <port> the port to bind to.\n" 128353141Sphilip " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n" 129353141Sphilip " -4 use only IPv4.\n" 130353141Sphilip " Default: use both IPv4 and IPv6 waiting sockets\n\n" 131353141Sphilip " -l <host_list> a file that contains a list of hosts that are allowed\n" 132353141Sphilip " to connect to this server (if more than one, list them one\n" 133353141Sphilip " per line).\n" 134353141Sphilip " We suggest to use literal names (instead of numeric ones)\n" 135353141Sphilip " in order to avoid problems with different address families.\n\n" 136353141Sphilip " -n permit NULL authentication (usually used with '-l')\n\n" 137353141Sphilip " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n" 138353141Sphilip " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n" 139353141Sphilip " -v run in active mode only (default: if '-a' is specified, it\n" 140353141Sphilip " accepts passive connections as well)\n\n" 141353141Sphilip " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n" 142353141Sphilip " Warning (Win32): this switch is provided automatically when\n" 143353141Sphilip " the service is started from the control panel\n\n" 144353141Sphilip#ifndef _WIN32 145353141Sphilip " -i run in inetd mode (UNIX only)\n\n" 146353141Sphilip#endif 147353141Sphilip " -D log debugging messages\n\n" 148353141Sphilip " -s <config_file> save the current configuration to file\n\n" 149353141Sphilip " -f <config_file> load the current configuration from file; all switches\n" 150353141Sphilip " specified from the command line are ignored\n\n" 151353141Sphilip " -h print this help screen\n\n"; 152353141Sphilip 153353141Sphilip (void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n" 154353141Sphilip "Compiled with %s\n\n", pcap_lib_version()); 155353141Sphilip printf("%s", usagetext); 156353141Sphilip} 157353141Sphilip 158353141Sphilip 159353141Sphilip 160353141Sphilip//! Program main 161353141Sphilipint main(int argc, char *argv[]) 162353141Sphilip{ 163353141Sphilip char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration 164353141Sphilip int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error 165353141Sphilip int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon 166353141Sphilip#ifndef _WIN32 167353141Sphilip int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like 168353141Sphilip#endif 169353141Sphilip int log_debug_messages = 0; // Non-zero if the user wants debug messages logged 170353141Sphilip int retval; // keeps the returning value from several functions 171353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 172353141Sphilip#ifndef _WIN32 173353141Sphilip struct sigaction action; 174353141Sphilip#endif 175353141Sphilip 176353141Sphilip savefile[0] = 0; 177353141Sphilip loadfile[0] = 0; 178353141Sphilip hostlist[0] = 0; 179353141Sphilip 180353141Sphilip // Initialize errbuf 181353141Sphilip memset(errbuf, 0, sizeof(errbuf)); 182353141Sphilip 183353141Sphilip strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE); 184353141Sphilip strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE); 185353141Sphilip 186353141Sphilip // Prepare to open a new server socket 187353141Sphilip memset(&mainhints, 0, sizeof(struct addrinfo)); 188353141Sphilip 189353141Sphilip mainhints.ai_family = PF_UNSPEC; 190353141Sphilip mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket 191353141Sphilip mainhints.ai_socktype = SOCK_STREAM; 192353141Sphilip 193353141Sphilip // Getting the proper command line options 194353141Sphilip while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1) 195353141Sphilip { 196353141Sphilip switch (retval) 197353141Sphilip { 198353141Sphilip case 'D': 199353141Sphilip log_debug_messages = 1; 200353141Sphilip rpcapd_log_set(log_to_systemlog, log_debug_messages); 201353141Sphilip break; 202353141Sphilip case 'b': 203353141Sphilip strncpy(address, optarg, MAX_LINE); 204353141Sphilip break; 205353141Sphilip case 'p': 206353141Sphilip strncpy(port, optarg, MAX_LINE); 207353141Sphilip break; 208353141Sphilip case '4': 209353141Sphilip mainhints.ai_family = PF_INET; // IPv4 server only 210353141Sphilip break; 211353141Sphilip case 'd': 212353141Sphilip isdaemon = 1; 213353141Sphilip log_to_systemlog = 1; 214353141Sphilip rpcapd_log_set(log_to_systemlog, log_debug_messages); 215353141Sphilip break; 216353141Sphilip case 'i': 217353141Sphilip#ifdef _WIN32 218353141Sphilip printusage(); 219353141Sphilip exit(1); 220353141Sphilip#else 221353141Sphilip isrunbyinetd = 1; 222353141Sphilip log_to_systemlog = 1; 223353141Sphilip rpcapd_log_set(log_to_systemlog, log_debug_messages); 224353141Sphilip#endif 225353141Sphilip break; 226353141Sphilip case 'n': 227353141Sphilip nullAuthAllowed = 1; 228353141Sphilip break; 229353141Sphilip case 'v': 230353141Sphilip passivemode = 0; 231353141Sphilip break; 232353141Sphilip case 'l': 233353141Sphilip { 234353141Sphilip strncpy(hostlist, optarg, sizeof(hostlist)); 235353141Sphilip break; 236353141Sphilip } 237353141Sphilip case 'a': 238353141Sphilip { 239353141Sphilip char *tmpaddress, *tmpport; 240353141Sphilip char *lasts; 241353141Sphilip int i = 0; 242353141Sphilip 243353141Sphilip tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts); 244353141Sphilip 245353141Sphilip while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST)) 246353141Sphilip { 247353141Sphilip tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); 248353141Sphilip 249353141Sphilip pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE); 250353141Sphilip 251353141Sphilip if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port 252353141Sphilip pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE); 253353141Sphilip else 254353141Sphilip pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE); 255353141Sphilip 256353141Sphilip tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); 257353141Sphilip 258353141Sphilip i++; 259353141Sphilip } 260353141Sphilip 261353141Sphilip if (i > MAX_ACTIVE_LIST) 262353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported."); 263353141Sphilip 264353141Sphilip // I don't initialize the remaining part of the structure, since 265353141Sphilip // it is already zeroed (it is a global var) 266353141Sphilip break; 267353141Sphilip } 268353141Sphilip case 'f': 269353141Sphilip pcap_strlcpy(loadfile, optarg, MAX_LINE); 270353141Sphilip break; 271353141Sphilip case 's': 272353141Sphilip pcap_strlcpy(savefile, optarg, MAX_LINE); 273353141Sphilip break; 274353141Sphilip case 'h': 275353141Sphilip printusage(); 276353141Sphilip exit(0); 277353141Sphilip /*NOTREACHED*/ 278353141Sphilip default: 279353141Sphilip exit(1); 280353141Sphilip /*NOTREACHED*/ 281353141Sphilip } 282353141Sphilip } 283353141Sphilip 284353141Sphilip#ifndef _WIN32 285353141Sphilip if (isdaemon && isrunbyinetd) 286353141Sphilip { 287353141Sphilip rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together"); 288353141Sphilip exit(1); 289353141Sphilip } 290353141Sphilip#endif 291353141Sphilip 292353141Sphilip if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) 293353141Sphilip { 294353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 295353141Sphilip exit(-1); 296353141Sphilip } 297353141Sphilip 298353141Sphilip if (savefile[0] && fileconf_save(savefile)) 299353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file"); 300353141Sphilip 301353141Sphilip // If the file does not exist, it keeps the settings provided by the command line 302353141Sphilip if (loadfile[0]) 303353141Sphilip fileconf_read(); 304353141Sphilip 305353141Sphilip#ifdef WIN32 306353141Sphilip // 307353141Sphilip // Create a handle to signal the main loop to tell it to do 308353141Sphilip // something. 309353141Sphilip // 310353141Sphilip state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL); 311353141Sphilip if (state_change_event == NULL) 312353141Sphilip { 313353141Sphilip sock_geterror("Can't create state change event", errbuf, 314353141Sphilip PCAP_ERRBUF_SIZE); 315353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 316353141Sphilip exit(2); 317353141Sphilip } 318353141Sphilip 319353141Sphilip // 320353141Sphilip // Catch control signals. 321353141Sphilip // 322353141Sphilip if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE)) 323353141Sphilip { 324353141Sphilip sock_geterror("Can't set control handler", errbuf, 325353141Sphilip PCAP_ERRBUF_SIZE); 326353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 327353141Sphilip exit(2); 328353141Sphilip } 329353141Sphilip#else 330353141Sphilip memset(&action, 0, sizeof (action)); 331353141Sphilip action.sa_handler = main_terminate; 332353141Sphilip action.sa_flags = 0; 333353141Sphilip sigemptyset(&action.sa_mask); 334353141Sphilip sigaction(SIGTERM, &action, NULL); 335353141Sphilip memset(&action, 0, sizeof (action)); 336353141Sphilip action.sa_handler = main_reap_children; 337353141Sphilip action.sa_flags = 0; 338353141Sphilip sigemptyset(&action.sa_mask); 339353141Sphilip sigaction(SIGCHLD, &action, NULL); 340353141Sphilip // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed 341353141Sphilip // connection, we don't want to get killed by a signal in that case 342353141Sphilip signal(SIGPIPE, SIG_IGN); 343353141Sphilip#endif 344353141Sphilip 345353141Sphilip#ifndef _WIN32 346353141Sphilip if (isrunbyinetd) 347353141Sphilip { 348353141Sphilip // 349353141Sphilip // -i was specified, indicating that this is being run 350353141Sphilip // by inetd or something that can run network daemons 351353141Sphilip // as if it were inetd (xinetd, launchd, systemd, etc.). 352353141Sphilip // 353353141Sphilip // We assume that the program that launched us just 354353141Sphilip // duplicated a single socket for the connection 355353141Sphilip // to our standard input, output, and error, so we 356353141Sphilip // can just use the standard input as our control 357353141Sphilip // socket. 358353141Sphilip // 359353141Sphilip int sockctrl; 360353141Sphilip int devnull_fd; 361353141Sphilip 362353141Sphilip // 363353141Sphilip // Duplicate the standard input as the control socket. 364353141Sphilip // 365353141Sphilip sockctrl = dup(0); 366353141Sphilip if (sockctrl == -1) 367353141Sphilip { 368353141Sphilip sock_geterror("Can't dup standard input", errbuf, 369353141Sphilip PCAP_ERRBUF_SIZE); 370353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 371353141Sphilip exit(2); 372353141Sphilip } 373353141Sphilip 374353141Sphilip // 375353141Sphilip // Try to set the standard input, output, and error 376353141Sphilip // to /dev/null. 377353141Sphilip // 378353141Sphilip devnull_fd = open("/dev/null", O_RDWR); 379353141Sphilip if (devnull_fd != -1) 380353141Sphilip { 381353141Sphilip // 382353141Sphilip // If this fails, just drive on. 383353141Sphilip // 384353141Sphilip (void)dup2(devnull_fd, 0); 385353141Sphilip (void)dup2(devnull_fd, 1); 386353141Sphilip (void)dup2(devnull_fd, 2); 387353141Sphilip close(devnull_fd); 388353141Sphilip } 389353141Sphilip 390353141Sphilip // 391353141Sphilip // Handle this client. 392353141Sphilip // This is passive mode, so we don't care whether we were 393353141Sphilip // told by the client to close. 394353141Sphilip // 395353141Sphilip char *hostlist_copy = strdup(hostlist); 396353141Sphilip if (hostlist_copy == NULL) 397353141Sphilip { 398353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); 399353141Sphilip exit(0); 400353141Sphilip } 401353141Sphilip (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, 402353141Sphilip nullAuthAllowed); 403353141Sphilip 404353141Sphilip // 405353141Sphilip // Nothing more to do. 406353141Sphilip // 407353141Sphilip exit(0); 408353141Sphilip } 409353141Sphilip#endif 410353141Sphilip 411353141Sphilip if (isdaemon) 412353141Sphilip { 413353141Sphilip // 414353141Sphilip // This is being run as a daemon. 415353141Sphilip // On UN*X, it might be manually run, or run from an 416353141Sphilip // rc file. 417353141Sphilip // 418353141Sphilip#ifndef _WIN32 419353141Sphilip int pid; 420353141Sphilip 421353141Sphilip // 422353141Sphilip // Daemonize ourselves. 423353141Sphilip // 424353141Sphilip // Unix Network Programming, pg 336 425353141Sphilip // 426353141Sphilip if ((pid = fork()) != 0) 427353141Sphilip exit(0); // Parent terminates 428353141Sphilip 429353141Sphilip // First child continues 430353141Sphilip // Set daemon mode 431353141Sphilip setsid(); 432353141Sphilip 433353141Sphilip // generated under unix with 'kill -HUP', needed to reload the configuration 434353141Sphilip memset(&action, 0, sizeof (action)); 435353141Sphilip action.sa_handler = main_reread_config; 436353141Sphilip action.sa_flags = 0; 437353141Sphilip sigemptyset(&action.sa_mask); 438353141Sphilip sigaction(SIGHUP, &action, NULL); 439353141Sphilip 440353141Sphilip if ((pid = fork()) != 0) 441353141Sphilip exit(0); // First child terminates 442353141Sphilip 443353141Sphilip // LINUX WARNING: the current linux implementation of pthreads requires a management thread 444353141Sphilip // to handle some hidden stuff. So, as soon as you create the first thread, two threads are 445353141Sphilip // created. Fom this point on, the number of threads active are always one more compared 446353141Sphilip // to the number you're expecting 447353141Sphilip 448353141Sphilip // Second child continues 449353141Sphilip// umask(0); 450353141Sphilip// chdir("/"); 451353141Sphilip#else 452353141Sphilip // 453353141Sphilip // This is being run as a service on Windows. 454353141Sphilip // 455353141Sphilip // If this call succeeds, it is blocking on Win32 456353141Sphilip // 457353141Sphilip if (svc_start() != 1) 458353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service"); 459353141Sphilip 460353141Sphilip // When the previous call returns, the entire application has to be stopped. 461353141Sphilip exit(0); 462353141Sphilip#endif 463353141Sphilip } 464353141Sphilip else // Console mode 465353141Sphilip { 466353141Sphilip#ifndef _WIN32 467353141Sphilip // Enable the catching of Ctrl+C 468353141Sphilip memset(&action, 0, sizeof (action)); 469353141Sphilip action.sa_handler = main_terminate; 470353141Sphilip action.sa_flags = 0; 471353141Sphilip sigemptyset(&action.sa_mask); 472353141Sphilip sigaction(SIGINT, &action, NULL); 473353141Sphilip 474353141Sphilip // generated under unix with 'kill -HUP', needed to reload the configuration 475353141Sphilip // We do not have this kind of signal in Win32 476353141Sphilip memset(&action, 0, sizeof (action)); 477353141Sphilip action.sa_handler = main_reread_config; 478353141Sphilip action.sa_flags = 0; 479353141Sphilip sigemptyset(&action.sa_mask); 480353141Sphilip sigaction(SIGHUP, &action, NULL); 481353141Sphilip#endif 482353141Sphilip 483353141Sphilip printf("Press CTRL + C to stop the server...\n"); 484353141Sphilip } 485353141Sphilip 486353141Sphilip // If we're a Win32 service, we have already called this function in the service_main 487353141Sphilip main_startup(); 488353141Sphilip 489353141Sphilip // The code should never arrive here (since the main_startup is blocking) 490353141Sphilip // however this avoids a compiler warning 491353141Sphilip exit(0); 492353141Sphilip} 493353141Sphilip 494353141Sphilipvoid main_startup(void) 495353141Sphilip{ 496353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 497353141Sphilip struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket 498353141Sphilip int i; 499353141Sphilip#ifdef _WIN32 500353141Sphilip HANDLE threadId; // handle for the subthread 501353141Sphilip#else 502353141Sphilip pid_t pid; 503353141Sphilip#endif 504353141Sphilip 505353141Sphilip i = 0; 506353141Sphilip addrinfo = NULL; 507353141Sphilip memset(errbuf, 0, sizeof(errbuf)); 508353141Sphilip 509353141Sphilip // Starts all the active threads 510353141Sphilip while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0)) 511353141Sphilip { 512353141Sphilip activelist[i].ai_family = mainhints.ai_family; 513353141Sphilip 514353141Sphilip#ifdef _WIN32 515353141Sphilip threadId = (HANDLE)_beginthreadex(NULL, 0, main_active, 516353141Sphilip (void *)&activelist[i], 0, NULL); 517353141Sphilip if (threadId == 0) 518353141Sphilip { 519353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads"); 520353141Sphilip continue; 521353141Sphilip } 522353141Sphilip CloseHandle(threadId); 523353141Sphilip#else 524353141Sphilip if ((pid = fork()) == 0) // I am the child 525353141Sphilip { 526353141Sphilip main_active((void *) &activelist[i]); 527353141Sphilip exit(0); 528353141Sphilip } 529353141Sphilip#endif 530353141Sphilip i++; 531353141Sphilip } 532353141Sphilip 533353141Sphilip /* 534353141Sphilip * The code that manages the active connections is not blocking; 535353141Sphilip * the code that manages the passive connection is blocking. 536353141Sphilip * So, if the user does not want to run in passive mode, we have 537353141Sphilip * to block the main thread here, otherwise the program ends and 538353141Sphilip * all threads are stopped. 539353141Sphilip * 540353141Sphilip * WARNING: this means that in case we have only active mode, 541353141Sphilip * the program does not terminate even if all the child thread 542353141Sphilip * terminates. The user has always to press Ctrl+C (or send a 543353141Sphilip * SIGTERM) to terminate the program. 544353141Sphilip */ 545353141Sphilip if (passivemode) 546353141Sphilip { 547353141Sphilip struct addrinfo *tempaddrinfo; 548353141Sphilip 549353141Sphilip // 550353141Sphilip // Get a list of sockets on which to listen. 551353141Sphilip // 552353141Sphilip if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 553353141Sphilip { 554353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); 555353141Sphilip return; 556353141Sphilip } 557353141Sphilip 558353141Sphilip for (tempaddrinfo = addrinfo; tempaddrinfo; 559353141Sphilip tempaddrinfo = tempaddrinfo->ai_next) 560353141Sphilip { 561353141Sphilip SOCKET sock; 562353141Sphilip struct listen_sock *sock_info; 563353141Sphilip 564353141Sphilip if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) 565353141Sphilip { 566353141Sphilip switch (tempaddrinfo->ai_family) 567353141Sphilip { 568353141Sphilip case AF_INET: 569353141Sphilip { 570353141Sphilip struct sockaddr_in *in; 571353141Sphilip char addrbuf[INET_ADDRSTRLEN]; 572353141Sphilip 573353141Sphilip in = (struct sockaddr_in *)tempaddrinfo->ai_addr; 574353141Sphilip rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", 575353141Sphilip inet_ntop(AF_INET, &in->sin_addr, 576353141Sphilip addrbuf, sizeof (addrbuf)), 577353141Sphilip ntohs(in->sin_port), 578353141Sphilip errbuf); 579353141Sphilip break; 580353141Sphilip } 581353141Sphilip 582353141Sphilip case AF_INET6: 583353141Sphilip { 584353141Sphilip struct sockaddr_in6 *in6; 585353141Sphilip char addrbuf[INET6_ADDRSTRLEN]; 586353141Sphilip 587353141Sphilip in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr; 588353141Sphilip rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", 589353141Sphilip inet_ntop(AF_INET6, &in6->sin6_addr, 590353141Sphilip addrbuf, sizeof (addrbuf)), 591353141Sphilip ntohs(in6->sin6_port), 592353141Sphilip errbuf); 593353141Sphilip break; 594353141Sphilip } 595353141Sphilip 596353141Sphilip default: 597353141Sphilip rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s", 598353141Sphilip tempaddrinfo->ai_family, 599353141Sphilip errbuf); 600353141Sphilip break; 601353141Sphilip } 602353141Sphilip continue; 603353141Sphilip } 604353141Sphilip 605353141Sphilip sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock)); 606353141Sphilip if (sock_info == NULL) 607353141Sphilip { 608353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket"); 609353141Sphilip exit(2); 610353141Sphilip } 611353141Sphilip sock_info->sock = sock; 612353141Sphilip sock_info->next = listen_socks; 613353141Sphilip listen_socks = sock_info; 614353141Sphilip } 615353141Sphilip 616353141Sphilip freeaddrinfo(addrinfo); 617353141Sphilip 618353141Sphilip if (listen_socks == NULL) 619353141Sphilip { 620353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address"); 621353141Sphilip exit(2); 622353141Sphilip } 623353141Sphilip 624353141Sphilip // 625353141Sphilip // Now listen on all of them, waiting for connections. 626353141Sphilip // 627353141Sphilip accept_connections(); 628353141Sphilip } 629353141Sphilip 630353141Sphilip // 631353141Sphilip // We're done; exit. 632353141Sphilip // 633353141Sphilip rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n"); 634353141Sphilip 635353141Sphilip#ifndef _WIN32 636353141Sphilip // 637353141Sphilip // Sends a KILL signal to all the processes in this process's 638353141Sphilip // process group; i.e., it kills all the child processes 639353141Sphilip // we've created. 640353141Sphilip // 641353141Sphilip // XXX - that also includes us, so we will be killed as well; 642353141Sphilip // that may cause a message to be printed or logged. 643353141Sphilip // 644353141Sphilip kill(0, SIGKILL); 645353141Sphilip#endif 646353141Sphilip 647353141Sphilip // 648353141Sphilip // Just leave. We shouldn't need to clean up sockets or 649353141Sphilip // anything else, and if we try to do so, we'll could end 650353141Sphilip // up closing sockets, or shutting Winsock down, out from 651353141Sphilip // under service loops, causing all sorts of noisy error 652353141Sphilip // messages. 653353141Sphilip // 654353141Sphilip // We shouldn't need to worry about cleaning up any resources 655353141Sphilip // such as handles, sockets, threads, etc. - exit() should 656353141Sphilip // terminate the process, causing all those resources to be 657353141Sphilip // cleaned up (including the threads; Microsoft claims in the 658353141Sphilip // ExitProcess() documentation that, if ExitProcess() is called, 659353141Sphilip // "If a thread is waiting on a kernel object, it will not be 660353141Sphilip // terminated until the wait has completed.", but claims in the 661353141Sphilip // _beginthread()/_beginthreadex() documentation that "All threads 662353141Sphilip // are terminated if any thread calls abort, exit, _exit, or 663353141Sphilip // ExitProcess." - the latter appears to be the case, even for 664353141Sphilip // threads waiting on the event for a pcap_t). 665353141Sphilip // 666353141Sphilip exit(0); 667353141Sphilip} 668353141Sphilip 669353141Sphilip#ifdef _WIN32 670353141Sphilipstatic void 671353141Sphilipsend_state_change_event(void) 672353141Sphilip{ 673353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 674353141Sphilip 675353141Sphilip if (!SetEvent(state_change_event)) 676353141Sphilip { 677353141Sphilip sock_geterror("SetEvent on shutdown event failed", errbuf, 678353141Sphilip PCAP_ERRBUF_SIZE); 679353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 680353141Sphilip } 681353141Sphilip} 682353141Sphilip 683353141Sphilipvoid 684353141Sphilipsend_shutdown_notification(void) 685353141Sphilip{ 686353141Sphilip // 687353141Sphilip // Indicate that the server should shut down. 688353141Sphilip // 689353141Sphilip shutdown_server = 1; 690353141Sphilip 691353141Sphilip // 692353141Sphilip // Send a state change event, to wake up WSAWaitForMultipleEvents(). 693353141Sphilip // 694353141Sphilip send_state_change_event(); 695353141Sphilip} 696353141Sphilip 697353141Sphilipvoid 698353141Sphilipsend_reread_configuration_notification(void) 699353141Sphilip{ 700353141Sphilip // 701353141Sphilip // Indicate that the server should re-read its configuration file. 702353141Sphilip // 703353141Sphilip reread_config = 1; 704353141Sphilip 705353141Sphilip // 706353141Sphilip // Send a state change event, to wake up WSAWaitForMultipleEvents(). 707353141Sphilip // 708353141Sphilip send_state_change_event(); 709353141Sphilip} 710353141Sphilip 711353141Sphilipstatic BOOL WINAPI main_ctrl_event(DWORD ctrltype) 712353141Sphilip{ 713353141Sphilip // 714353141Sphilip // ctrltype is one of: 715353141Sphilip // 716353141Sphilip // CTRL_C_EVENT - we got a ^C; this is like SIGINT 717353141Sphilip // CTRL_BREAK_EVENT - we got Ctrl+Break 718353141Sphilip // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP 719353141Sphilip // CTRL_LOGOFF_EVENT - a user is logging off; this is received 720353141Sphilip // only by services 721353141Sphilip // CTRL_SHUTDOWN_EVENT - the systemis shutting down; this is 722353141Sphilip // received only by services 723353141Sphilip // 724353141Sphilip // For now, we treat all but CTRL_LOGOFF_EVENT as indications 725353141Sphilip // that we should shut down. 726353141Sphilip // 727353141Sphilip switch (ctrltype) 728353141Sphilip { 729353141Sphilip case CTRL_C_EVENT: 730353141Sphilip case CTRL_BREAK_EVENT: 731353141Sphilip case CTRL_CLOSE_EVENT: 732353141Sphilip case CTRL_SHUTDOWN_EVENT: 733353141Sphilip // 734353141Sphilip // Set a shutdown notification. 735353141Sphilip // 736353141Sphilip send_shutdown_notification(); 737353141Sphilip break; 738353141Sphilip 739353141Sphilip default: 740353141Sphilip break; 741353141Sphilip } 742353141Sphilip 743353141Sphilip // 744353141Sphilip // We handled this. 745353141Sphilip // 746353141Sphilip return TRUE; 747353141Sphilip} 748353141Sphilip#else 749353141Sphilipstatic void main_terminate(int sign _U_) 750353141Sphilip{ 751353141Sphilip // 752353141Sphilip // Note that the server should shut down. 753353141Sphilip // select() should get an EINTR error when we return, 754353141Sphilip // so it will wake up and know it needs to check the flag. 755353141Sphilip // 756353141Sphilip shutdown_server = 1; 757353141Sphilip} 758353141Sphilip 759353141Sphilipstatic void main_reread_config(int sign _U_) 760353141Sphilip{ 761353141Sphilip // 762353141Sphilip // Note that the server should re-read its configuration file. 763353141Sphilip // select() should get an EINTR error when we return, 764353141Sphilip // so it will wake up and know it needs to check the flag. 765353141Sphilip // 766353141Sphilip reread_config = 1; 767353141Sphilip} 768353141Sphilip 769353141Sphilipstatic void main_reap_children(int sign _U_) 770353141Sphilip{ 771353141Sphilip pid_t pid; 772353141Sphilip int exitstat; 773353141Sphilip 774353141Sphilip // Reap all child processes that have exited. 775353141Sphilip // For reference, Stevens, pg 128 776353141Sphilip 777353141Sphilip while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0) 778353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "Child terminated"); 779353141Sphilip 780353141Sphilip return; 781353141Sphilip} 782353141Sphilip#endif 783353141Sphilip 784353141Sphilip// 785353141Sphilip// Loop waiting for incoming connections and accepting them. 786353141Sphilip// 787353141Sphilipstatic void 788353141Sphilipaccept_connections(void) 789353141Sphilip{ 790353141Sphilip#ifdef _WIN32 791353141Sphilip struct listen_sock *sock_info; 792353141Sphilip DWORD num_events; 793353141Sphilip WSAEVENT *events; 794353141Sphilip int i; 795353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 796353141Sphilip 797353141Sphilip // 798353141Sphilip // How big does the set of events need to be? 799353141Sphilip // One for the shutdown event, plus one for every socket on which 800353141Sphilip // we'll be listening. 801353141Sphilip // 802353141Sphilip num_events = 1; // shutdown event 803353141Sphilip for (sock_info = listen_socks; sock_info; 804353141Sphilip sock_info = sock_info->next) 805353141Sphilip { 806353141Sphilip if (num_events == WSA_MAXIMUM_WAIT_EVENTS) 807353141Sphilip { 808353141Sphilip // 809353141Sphilip // WSAWaitForMultipleEvents() doesn't support 810353141Sphilip // more than WSA_MAXIMUM_WAIT_EVENTS events 811353141Sphilip // on which to wait. 812353141Sphilip // 813353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen"); 814353141Sphilip exit(2); 815353141Sphilip } 816353141Sphilip num_events++; 817353141Sphilip } 818353141Sphilip 819353141Sphilip // 820353141Sphilip // Allocate the array of events. 821353141Sphilip // 822353141Sphilip events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT)); 823353141Sphilip if (events == NULL) 824353141Sphilip { 825353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen"); 826353141Sphilip exit(2); 827353141Sphilip } 828353141Sphilip 829353141Sphilip // 830353141Sphilip // Fill it in. 831353141Sphilip // 832353141Sphilip events[0] = state_change_event; // state change event first 833353141Sphilip for (sock_info = listen_socks, i = 1; sock_info; 834353141Sphilip sock_info = sock_info->next, i++) 835353141Sphilip { 836353141Sphilip WSAEVENT event; 837353141Sphilip 838353141Sphilip // 839353141Sphilip // Create an event that is signaled if there's a connection 840353141Sphilip // to accept on the socket in question. 841353141Sphilip // 842353141Sphilip event = WSACreateEvent(); 843353141Sphilip if (event == WSA_INVALID_EVENT) 844353141Sphilip { 845353141Sphilip sock_geterror("Can't create socket event", errbuf, 846353141Sphilip PCAP_ERRBUF_SIZE); 847353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 848353141Sphilip exit(2); 849353141Sphilip } 850353141Sphilip if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR) 851353141Sphilip { 852353141Sphilip sock_geterror("Can't setup socket event", errbuf, 853353141Sphilip PCAP_ERRBUF_SIZE); 854353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 855353141Sphilip exit(2); 856353141Sphilip } 857353141Sphilip events[i] = event; 858353141Sphilip } 859353141Sphilip 860353141Sphilip for (;;) 861353141Sphilip { 862353141Sphilip // 863353141Sphilip // Wait for incoming connections. 864353141Sphilip // 865353141Sphilip DWORD ret; 866353141Sphilip 867353141Sphilip ret = WSAWaitForMultipleEvents(num_events, events, FALSE, 868353141Sphilip WSA_INFINITE, FALSE); 869353141Sphilip if (ret == WSA_WAIT_FAILED) 870353141Sphilip { 871353141Sphilip sock_geterror("WSAWaitForMultipleEvents failed", errbuf, 872353141Sphilip PCAP_ERRBUF_SIZE); 873353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 874353141Sphilip exit(2); 875353141Sphilip } 876353141Sphilip 877353141Sphilip if (ret == WSA_WAIT_EVENT_0) 878353141Sphilip { 879353141Sphilip // 880353141Sphilip // The state change event was set. 881353141Sphilip // 882353141Sphilip if (shutdown_server) 883353141Sphilip { 884353141Sphilip // 885353141Sphilip // Time to quit. Exit the loop. 886353141Sphilip // 887353141Sphilip break; 888353141Sphilip } 889353141Sphilip if (reread_config) 890353141Sphilip { 891353141Sphilip // 892353141Sphilip // We should re-read the configuration 893353141Sphilip // file. 894353141Sphilip // 895353141Sphilip reread_config = 0; // clear the indicator 896353141Sphilip fileconf_read(); 897353141Sphilip } 898353141Sphilip } 899353141Sphilip 900353141Sphilip // 901353141Sphilip // Check each socket. 902353141Sphilip // 903353141Sphilip for (sock_info = listen_socks, i = 1; sock_info; 904353141Sphilip sock_info = sock_info->next, i++) 905353141Sphilip { 906353141Sphilip WSANETWORKEVENTS network_events; 907353141Sphilip 908353141Sphilip if (WSAEnumNetworkEvents(sock_info->sock, 909353141Sphilip events[i], &network_events) == SOCKET_ERROR) 910353141Sphilip { 911353141Sphilip sock_geterror("WSAEnumNetworkEvents failed", 912353141Sphilip errbuf, PCAP_ERRBUF_SIZE); 913353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 914353141Sphilip exit(2); 915353141Sphilip } 916353141Sphilip if (network_events.lNetworkEvents & FD_ACCEPT) 917353141Sphilip { 918353141Sphilip // 919353141Sphilip // Did an error occur? 920353141Sphilip // 921353141Sphilip if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0) 922353141Sphilip { 923353141Sphilip // 924353141Sphilip // Yes - report it and keep going. 925353141Sphilip // 926353141Sphilip sock_fmterror("Socket error", 927353141Sphilip network_events.iErrorCode[FD_ACCEPT_BIT], 928353141Sphilip errbuf, 929353141Sphilip PCAP_ERRBUF_SIZE); 930353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 931353141Sphilip continue; 932353141Sphilip } 933353141Sphilip 934353141Sphilip // 935353141Sphilip // Accept the connection. 936353141Sphilip // 937353141Sphilip accept_connection(sock_info->sock); 938353141Sphilip } 939353141Sphilip } 940353141Sphilip } 941353141Sphilip#else 942353141Sphilip struct listen_sock *sock_info; 943353141Sphilip int num_sock_fds; 944353141Sphilip 945353141Sphilip // 946353141Sphilip // How big does the bitset of sockets on which to select() have 947353141Sphilip // to be? 948353141Sphilip // 949353141Sphilip num_sock_fds = 0; 950353141Sphilip for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) 951353141Sphilip { 952353141Sphilip if (sock_info->sock + 1 > num_sock_fds) 953353141Sphilip { 954353141Sphilip if ((unsigned int)(sock_info->sock + 1) > 955353141Sphilip (unsigned int)FD_SETSIZE) 956353141Sphilip { 957353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set"); 958353141Sphilip exit(2); 959353141Sphilip } 960353141Sphilip num_sock_fds = sock_info->sock + 1; 961353141Sphilip } 962353141Sphilip } 963353141Sphilip 964353141Sphilip for (;;) 965353141Sphilip { 966353141Sphilip fd_set sock_fds; 967353141Sphilip int ret; 968353141Sphilip 969353141Sphilip // 970353141Sphilip // Set up an fd_set for all the sockets on which we're 971353141Sphilip // listening. 972353141Sphilip // 973353141Sphilip // This set is modified by select(), so we have to 974353141Sphilip // construct it anew each time. 975353141Sphilip // 976353141Sphilip FD_ZERO(&sock_fds); 977353141Sphilip for (sock_info = listen_socks; sock_info; 978353141Sphilip sock_info = sock_info->next) 979353141Sphilip { 980353141Sphilip FD_SET(sock_info->sock, &sock_fds); 981353141Sphilip } 982353141Sphilip 983353141Sphilip // 984353141Sphilip // Wait for incoming connections. 985353141Sphilip // 986353141Sphilip ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL); 987353141Sphilip if (ret == -1) 988353141Sphilip { 989353141Sphilip if (errno == EINTR) 990353141Sphilip { 991353141Sphilip // 992353141Sphilip // If this is a "terminate the 993353141Sphilip // server" signal, exit the loop, 994353141Sphilip // otherwise just keep trying. 995353141Sphilip // 996353141Sphilip if (shutdown_server) 997353141Sphilip { 998353141Sphilip // 999353141Sphilip // Time to quit. Exit the loop. 1000353141Sphilip // 1001353141Sphilip break; 1002353141Sphilip } 1003353141Sphilip if (reread_config) 1004353141Sphilip { 1005353141Sphilip // 1006353141Sphilip // We should re-read the configuration 1007353141Sphilip // file. 1008353141Sphilip // 1009353141Sphilip reread_config = 0; // clear the indicator 1010353141Sphilip fileconf_read(); 1011353141Sphilip } 1012353141Sphilip 1013353141Sphilip // 1014353141Sphilip // Go back and wait again. 1015353141Sphilip // 1016353141Sphilip continue; 1017353141Sphilip } 1018353141Sphilip else 1019353141Sphilip { 1020353141Sphilip rpcapd_log(LOGPRIO_ERROR, "select failed: %s", 1021353141Sphilip strerror(errno)); 1022353141Sphilip exit(2); 1023353141Sphilip } 1024353141Sphilip } 1025353141Sphilip 1026353141Sphilip // 1027353141Sphilip // Check each socket. 1028353141Sphilip // 1029353141Sphilip for (sock_info = listen_socks; sock_info; 1030353141Sphilip sock_info = sock_info->next) 1031353141Sphilip { 1032353141Sphilip if (FD_ISSET(sock_info->sock, &sock_fds)) 1033353141Sphilip { 1034353141Sphilip // 1035353141Sphilip // Accept the connection. 1036353141Sphilip // 1037353141Sphilip accept_connection(sock_info->sock); 1038353141Sphilip } 1039353141Sphilip } 1040353141Sphilip } 1041353141Sphilip#endif 1042353141Sphilip 1043353141Sphilip // 1044353141Sphilip // Close all the listen sockets. 1045353141Sphilip // 1046353141Sphilip for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) 1047353141Sphilip { 1048353141Sphilip closesocket(sock_info->sock); 1049353141Sphilip } 1050353141Sphilip sock_cleanup(); 1051353141Sphilip} 1052353141Sphilip 1053353141Sphilip#ifdef _WIN32 1054353141Sphilip// 1055353141Sphilip// A structure to hold the parameters to the daemon service loop 1056353141Sphilip// thread on Windows. 1057353141Sphilip// 1058353141Sphilip// (On UN*X, there is no need for this explicit copy since the 1059353141Sphilip// fork "inherits" the parent stack.) 1060353141Sphilip// 1061353141Sphilipstruct params_copy { 1062353141Sphilip SOCKET sockctrl; 1063353141Sphilip char *hostlist; 1064353141Sphilip}; 1065353141Sphilip#endif 1066353141Sphilip 1067353141Sphilip// 1068353141Sphilip// Accept a connection and start a worker thread, on Windows, or a 1069353141Sphilip// worker process, on UN*X, to handle the connection. 1070353141Sphilip// 1071353141Sphilipstatic void 1072353141Sphilipaccept_connection(SOCKET listen_sock) 1073353141Sphilip{ 1074353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 1075353141Sphilip SOCKET sockctrl; // keeps the socket ID for this control connection 1076353141Sphilip struct sockaddr_storage from; // generic sockaddr_storage variable 1077353141Sphilip socklen_t fromlen; // keeps the length of the sockaddr_storage variable 1078353141Sphilip 1079353141Sphilip#ifdef _WIN32 1080353141Sphilip HANDLE threadId; // handle for the subthread 1081353141Sphilip u_long off = 0; 1082353141Sphilip struct params_copy *params_copy = NULL; 1083353141Sphilip#else 1084353141Sphilip pid_t pid; 1085353141Sphilip#endif 1086353141Sphilip 1087353141Sphilip // Initialize errbuf 1088353141Sphilip memset(errbuf, 0, sizeof(errbuf)); 1089353141Sphilip 1090353141Sphilip for (;;) 1091353141Sphilip { 1092353141Sphilip // Accept the connection 1093353141Sphilip fromlen = sizeof(struct sockaddr_storage); 1094353141Sphilip 1095353141Sphilip sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen); 1096353141Sphilip 1097353141Sphilip if (sockctrl != INVALID_SOCKET) 1098353141Sphilip { 1099353141Sphilip // Success. 1100353141Sphilip break; 1101353141Sphilip } 1102353141Sphilip 1103353141Sphilip // The accept() call can return this error when a signal is catched 1104353141Sphilip // In this case, we have simply to ignore this error code 1105353141Sphilip // Stevens, pg 124 1106353141Sphilip#ifdef _WIN32 1107353141Sphilip if (WSAGetLastError() == WSAEINTR) 1108353141Sphilip#else 1109353141Sphilip if (errno == EINTR) 1110353141Sphilip#endif 1111353141Sphilip continue; 1112353141Sphilip 1113353141Sphilip // Don't check for errors here, since the error can be due to the fact that the thread 1114353141Sphilip // has been killed 1115353141Sphilip sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE); 1116353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s", 1117353141Sphilip errbuf); 1118353141Sphilip return; 1119353141Sphilip } 1120353141Sphilip 1121353141Sphilip#ifdef _WIN32 1122353141Sphilip // 1123353141Sphilip // Put the socket back into blocking mode; doing WSAEventSelect() 1124353141Sphilip // on the listen socket makes that socket non-blocking, and it 1125353141Sphilip // appears that sockets returned from an accept() on that socket 1126353141Sphilip // are also non-blocking. 1127353141Sphilip // 1128353141Sphilip // First, we have to un-WSAEventSelect() this socket, and then 1129353141Sphilip // we can turn non-blocking mode off. 1130353141Sphilip // 1131353141Sphilip // If this fails, we aren't guaranteed that, for example, any 1132353141Sphilip // of the error message will be sent - if it can't be put in 1133353141Sphilip // the socket queue, the send will just fail. 1134353141Sphilip // 1135353141Sphilip // So we just log the message and close the connection. 1136353141Sphilip // 1137353141Sphilip if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR) 1138353141Sphilip { 1139353141Sphilip sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE); 1140353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 1141353141Sphilip sock_close(sockctrl, NULL, 0); 1142353141Sphilip return; 1143353141Sphilip } 1144353141Sphilip if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR) 1145353141Sphilip { 1146353141Sphilip sock_geterror("ioctlsocket(FIONBIO)", errbuf, PCAP_ERRBUF_SIZE); 1147353141Sphilip rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); 1148353141Sphilip sock_close(sockctrl, NULL, 0); 1149353141Sphilip return; 1150353141Sphilip } 1151353141Sphilip 1152353141Sphilip // 1153353141Sphilip // Make a copy of the host list to pass to the new thread, so that 1154353141Sphilip // if we update it in the main thread, it won't catch us in the 1155353141Sphilip // middle of updating it. 1156353141Sphilip // 1157353141Sphilip // daemon_serviceloop() will free it once it's done with it. 1158353141Sphilip // 1159353141Sphilip char *hostlist_copy = strdup(hostlist); 1160353141Sphilip if (hostlist_copy == NULL) 1161353141Sphilip { 1162353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); 1163353141Sphilip sock_close(sockctrl, NULL, 0); 1164353141Sphilip return; 1165353141Sphilip } 1166353141Sphilip 1167353141Sphilip // 1168353141Sphilip // Allocate a location to hold the values of sockctrl. 1169353141Sphilip // It will be freed in the newly-created thread once it's 1170353141Sphilip // finished with it. 1171353141Sphilip // 1172353141Sphilip params_copy = malloc(sizeof(*params_copy)); 1173353141Sphilip if (params_copy == NULL) 1174353141Sphilip { 1175353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure"); 1176353141Sphilip free(hostlist_copy); 1177353141Sphilip sock_close(sockctrl, NULL, 0); 1178353141Sphilip return; 1179353141Sphilip } 1180353141Sphilip params_copy->sockctrl = sockctrl; 1181353141Sphilip params_copy->hostlist = hostlist_copy; 1182353141Sphilip 1183353141Sphilip threadId = (HANDLE)_beginthreadex(NULL, 0, 1184353141Sphilip main_passive_serviceloop_thread, (void *) params_copy, 0, NULL); 1185353141Sphilip if (threadId == 0) 1186353141Sphilip { 1187353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread"); 1188353141Sphilip free(params_copy); 1189353141Sphilip free(hostlist_copy); 1190353141Sphilip sock_close(sockctrl, NULL, 0); 1191353141Sphilip return; 1192353141Sphilip } 1193353141Sphilip CloseHandle(threadId); 1194353141Sphilip#else /* _WIN32 */ 1195353141Sphilip pid = fork(); 1196353141Sphilip if (pid == -1) 1197353141Sphilip { 1198353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s", 1199353141Sphilip strerror(errno)); 1200353141Sphilip sock_close(sockctrl, NULL, 0); 1201353141Sphilip return; 1202353141Sphilip } 1203353141Sphilip if (pid == 0) 1204353141Sphilip { 1205353141Sphilip // 1206353141Sphilip // Child process. 1207353141Sphilip // 1208353141Sphilip // Close the socket on which we're listening (must 1209353141Sphilip // be open only in the parent). 1210353141Sphilip // 1211353141Sphilip closesocket(listen_sock); 1212353141Sphilip 1213353141Sphilip#if 0 1214353141Sphilip // 1215353141Sphilip // Modify thread params so that it can be killed at any time 1216353141Sphilip // XXX - is this necessary? This is the main and, currently, 1217353141Sphilip // only thread in the child process, and nobody tries to 1218353141Sphilip // cancel us, although *we* may cancel the thread that's 1219353141Sphilip // handling the capture loop. 1220353141Sphilip // 1221353141Sphilip if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) 1222353141Sphilip goto end; 1223353141Sphilip if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) 1224353141Sphilip goto end; 1225353141Sphilip#endif 1226353141Sphilip 1227353141Sphilip // 1228353141Sphilip // Run the service loop. 1229353141Sphilip // This is passive mode, so we don't care whether we were 1230353141Sphilip // told by the client to close. 1231353141Sphilip // 1232353141Sphilip char *hostlist_copy = strdup(hostlist); 1233353141Sphilip if (hostlist_copy == NULL) 1234353141Sphilip { 1235353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); 1236353141Sphilip exit(0); 1237353141Sphilip } 1238353141Sphilip (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, 1239353141Sphilip nullAuthAllowed); 1240353141Sphilip 1241353141Sphilip exit(0); 1242353141Sphilip } 1243353141Sphilip 1244353141Sphilip // I am the parent 1245353141Sphilip // Close the socket for this session (must be open only in the child) 1246353141Sphilip closesocket(sockctrl); 1247353141Sphilip#endif /* _WIN32 */ 1248353141Sphilip} 1249353141Sphilip 1250353141Sphilip/*! 1251353141Sphilip \brief 'true' main of the program in case the active mode is turned on. 1252353141Sphilip 1253353141Sphilip This function loops forever trying to connect to the remote host, until the 1254353141Sphilip daemon is turned down. 1255353141Sphilip 1256353141Sphilip \param ptr: it keeps the 'activepars' parameters. It is a 'void *' 1257353141Sphilip just because the thread APIs want this format. 1258353141Sphilip*/ 1259353141Sphilip#ifdef _WIN32 1260353141Sphilipstatic unsigned __stdcall 1261353141Sphilip#else 1262353141Sphilipstatic void * 1263353141Sphilip#endif 1264353141Sphilipmain_active(void *ptr) 1265353141Sphilip{ 1266353141Sphilip char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 1267353141Sphilip SOCKET sockctrl; // keeps the socket ID for this control connection 1268353141Sphilip struct addrinfo hints; // temporary struct to keep settings needed to open the new socket 1269353141Sphilip struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket 1270353141Sphilip struct active_pars *activepars; 1271353141Sphilip 1272353141Sphilip activepars = (struct active_pars *) ptr; 1273353141Sphilip 1274353141Sphilip // Prepare to open a new server socket 1275353141Sphilip memset(&hints, 0, sizeof(struct addrinfo)); 1276353141Sphilip // WARNING Currently it supports only ONE socket family among IPv4 and IPv6 1277353141Sphilip hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server 1278353141Sphilip hints.ai_socktype = SOCK_STREAM; 1279353141Sphilip hints.ai_family = activepars->ai_family; 1280353141Sphilip 1281353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s", 1282353141Sphilip activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": 1283353141Sphilip (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); 1284353141Sphilip 1285353141Sphilip // Initialize errbuf 1286353141Sphilip memset(errbuf, 0, sizeof(errbuf)); 1287353141Sphilip 1288353141Sphilip // Do the work 1289353141Sphilip if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 1290353141Sphilip { 1291353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); 1292353141Sphilip return 0; 1293353141Sphilip } 1294353141Sphilip 1295353141Sphilip for (;;) 1296353141Sphilip { 1297353141Sphilip int activeclose; 1298353141Sphilip 1299353141Sphilip if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) 1300353141Sphilip { 1301353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); 1302353141Sphilip 1303353141Sphilip pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s", 1304353141Sphilip activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": 1305353141Sphilip (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); 1306353141Sphilip 1307353141Sphilip rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); 1308353141Sphilip 1309353141Sphilip sleep_secs(RPCAP_ACTIVE_WAIT); 1310353141Sphilip 1311353141Sphilip continue; 1312353141Sphilip } 1313353141Sphilip 1314353141Sphilip char *hostlist_copy = strdup(hostlist); 1315353141Sphilip if (hostlist_copy == NULL) 1316353141Sphilip { 1317353141Sphilip rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); 1318353141Sphilip activeclose = 0; 1319353141Sphilip sock_close(sockctrl, NULL, 0); 1320353141Sphilip } 1321353141Sphilip else 1322353141Sphilip { 1323353141Sphilip // 1324353141Sphilip // daemon_serviceloop() will free the copy. 1325353141Sphilip // 1326353141Sphilip activeclose = daemon_serviceloop(sockctrl, 1, 1327353141Sphilip hostlist_copy, nullAuthAllowed); 1328353141Sphilip } 1329353141Sphilip 1330353141Sphilip // If the connection is closed by the user explicitely, don't try to connect to it again 1331353141Sphilip // just exit the program 1332353141Sphilip if (activeclose == 1) 1333353141Sphilip break; 1334353141Sphilip } 1335353141Sphilip 1336353141Sphilip freeaddrinfo(addrinfo); 1337353141Sphilip return 0; 1338353141Sphilip} 1339353141Sphilip 1340353141Sphilip#ifdef _WIN32 1341353141Sphilip// 1342353141Sphilip// Main routine of a passive-mode service thread. 1343353141Sphilip// 1344353141Sphilipunsigned __stdcall main_passive_serviceloop_thread(void *ptr) 1345353141Sphilip{ 1346353141Sphilip struct params_copy params = *(struct params_copy *)ptr; 1347353141Sphilip free(ptr); 1348353141Sphilip 1349353141Sphilip // 1350353141Sphilip // Handle this client. 1351353141Sphilip // This is passive mode, so we don't care whether we were 1352353141Sphilip // told by the client to close. 1353353141Sphilip // 1354353141Sphilip (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist, 1355353141Sphilip nullAuthAllowed); 1356353141Sphilip 1357353141Sphilip return 0; 1358353141Sphilip} 1359353141Sphilip#endif 1360