10036d835Schristos /*
20036d835Schristos * Copyright (c) 2002 - 2003
30036d835Schristos * NetGroup, Politecnico di Torino (Italy)
40036d835Schristos * All rights reserved.
50036d835Schristos *
60036d835Schristos * Redistribution and use in source and binary forms, with or without
70036d835Schristos * modification, are permitted provided that the following conditions
80036d835Schristos * are met:
90036d835Schristos *
100036d835Schristos * 1. Redistributions of source code must retain the above copyright
110036d835Schristos * notice, this list of conditions and the following disclaimer.
120036d835Schristos * 2. Redistributions in binary form must reproduce the above copyright
130036d835Schristos * notice, this list of conditions and the following disclaimer in the
140036d835Schristos * documentation and/or other materials provided with the distribution.
150036d835Schristos * 3. Neither the name of the Politecnico di Torino nor the names of its
160036d835Schristos * contributors may be used to endorse or promote products derived from
170036d835Schristos * this software without specific prior written permission.
180036d835Schristos *
190036d835Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200036d835Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
210036d835Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
220036d835Schristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
230036d835Schristos * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
240036d835Schristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
250036d835Schristos * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
260036d835Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
270036d835Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
280036d835Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
290036d835Schristos * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300036d835Schristos *
310036d835Schristos */
320036d835Schristos
330036d835Schristos #ifdef HAVE_CONFIG_H
340036d835Schristos #include <config.h>
350036d835Schristos #endif
360036d835Schristos
370036d835Schristos #include "ftmacros.h"
380036d835Schristos
390036d835Schristos #include <errno.h> // for the errno variable
400036d835Schristos #include <string.h> // for strtok, etc
410036d835Schristos #include <stdlib.h> // for malloc(), free(), ...
420036d835Schristos #include <pcap.h> // for PCAP_ERRBUF_SIZE
430036d835Schristos #include <signal.h> // for signal()
440036d835Schristos
450036d835Schristos #include "fmtutils.h"
460036d835Schristos #include "sockutils.h" // for socket calls
470036d835Schristos #include "varattrs.h" // for _U_
480036d835Schristos #include "portability.h"
490036d835Schristos #include "rpcapd.h"
500036d835Schristos #include "config_params.h" // configuration file parameters
510036d835Schristos #include "fileconf.h" // for the configuration file management
520036d835Schristos #include "rpcap-protocol.h"
530036d835Schristos #include "daemon.h" // the true main() method of this daemon
540036d835Schristos #include "log.h"
550036d835Schristos
560036d835Schristos #ifdef _WIN32
570036d835Schristos #include <process.h> // for thread stuff
580036d835Schristos #include "win32-svc.h" // for Win32 service stuff
590036d835Schristos #include "getopt.h" // for getopt()-for-Windows
600036d835Schristos #else
610036d835Schristos #include <fcntl.h> // for open()
620036d835Schristos #include <unistd.h> // for exit()
630036d835Schristos #include <sys/wait.h> // waitpid()
640036d835Schristos #endif
650036d835Schristos
660036d835Schristos //
670036d835Schristos // Element in list of sockets on which we're listening for connections.
680036d835Schristos //
690036d835Schristos struct listen_sock {
700036d835Schristos struct listen_sock *next;
710036d835Schristos SOCKET sock;
720036d835Schristos };
730036d835Schristos
740036d835Schristos // Global variables
750036d835Schristos char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
760036d835Schristos struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
770036d835Schristos int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
780036d835Schristos static struct listen_sock *listen_socks; //!< sockets on which we listen
790036d835Schristos char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration
800036d835Schristos static int passivemode = 1; //!< '1' if we want to run in passive mode as well
810036d835Schristos static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket
820036d835Schristos static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to
830036d835Schristos static char port[MAX_LINE + 1]; //!< keeps the network port to bind to
840036d835Schristos #ifdef _WIN32
850036d835Schristos static HANDLE state_change_event; //!< event to signal that a state change should take place
860036d835Schristos #endif
870036d835Schristos static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
880036d835Schristos static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
890036d835Schristos
900036d835Schristos extern char *optarg; // for getopt()
910036d835Schristos
920036d835Schristos // Function definition
930036d835Schristos #ifdef _WIN32
940036d835Schristos static unsigned __stdcall main_active(void *ptr);
950036d835Schristos static BOOL WINAPI main_ctrl_event(DWORD);
960036d835Schristos #else
970036d835Schristos static void *main_active(void *ptr);
980036d835Schristos static void main_terminate(int sign);
990036d835Schristos static void main_reread_config(int sign);
1000036d835Schristos #endif
1010036d835Schristos static void accept_connections(void);
1020036d835Schristos static void accept_connection(SOCKET listen_sock);
1030036d835Schristos #ifndef _WIN32
1040036d835Schristos static void main_reap_children(int sign);
1050036d835Schristos #endif
1060036d835Schristos #ifdef _WIN32
1070036d835Schristos static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
1080036d835Schristos #endif
1090036d835Schristos
1100036d835Schristos #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
1110036d835Schristos
1120036d835Schristos /*!
1130036d835Schristos \brief Prints the usage screen if it is launched in console mode.
1140036d835Schristos */
printusage(void)1150036d835Schristos static void printusage(void)
1160036d835Schristos {
1170036d835Schristos const char *usagetext =
1180036d835Schristos "USAGE:"
1190036d835Schristos " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
1200036d835Schristos " [-n] [-v] [-d] "
1210036d835Schristos #ifndef _WIN32
1220036d835Schristos "[-i] "
1230036d835Schristos #endif
124*9a3414cbSchristos "[-D] [-s <config_file>] [-f <config_file>]\n\n"
1250036d835Schristos " -b <address> the address to bind to (either numeric or literal).\n"
1260036d835Schristos " Default: binds to all local IPv4 and IPv6 addresses\n\n"
1270036d835Schristos " -p <port> the port to bind to.\n"
1280036d835Schristos " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
1290036d835Schristos " -4 use only IPv4.\n"
1300036d835Schristos " Default: use both IPv4 and IPv6 waiting sockets\n\n"
1310036d835Schristos " -l <host_list> a file that contains a list of hosts that are allowed\n"
1320036d835Schristos " to connect to this server (if more than one, list them one\n"
1330036d835Schristos " per line).\n"
1340036d835Schristos " We suggest to use literal names (instead of numeric ones)\n"
1350036d835Schristos " in order to avoid problems with different address families.\n\n"
1360036d835Schristos " -n permit NULL authentication (usually used with '-l')\n\n"
1370036d835Schristos " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
1380036d835Schristos " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
1390036d835Schristos " -v run in active mode only (default: if '-a' is specified, it\n"
1400036d835Schristos " accepts passive connections as well)\n\n"
1410036d835Schristos " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
1420036d835Schristos " Warning (Win32): this switch is provided automatically when\n"
1430036d835Schristos " the service is started from the control panel\n\n"
1440036d835Schristos #ifndef _WIN32
1450036d835Schristos " -i run in inetd mode (UNIX only)\n\n"
1460036d835Schristos #endif
147*9a3414cbSchristos " -D log debugging messages\n\n"
1480036d835Schristos " -s <config_file> save the current configuration to file\n\n"
1490036d835Schristos " -f <config_file> load the current configuration from file; all switches\n"
1500036d835Schristos " specified from the command line are ignored\n\n"
1510036d835Schristos " -h print this help screen\n\n";
1520036d835Schristos
1530036d835Schristos (void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
1540036d835Schristos "Compiled with %s\n\n", pcap_lib_version());
1550036d835Schristos printf("%s", usagetext);
1560036d835Schristos }
1570036d835Schristos
1580036d835Schristos
1590036d835Schristos
1600036d835Schristos //! Program main
main(int argc,char * argv[])1610036d835Schristos int main(int argc, char *argv[])
1620036d835Schristos {
1630036d835Schristos char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration
164*9a3414cbSchristos int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error
1650036d835Schristos int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon
1660036d835Schristos #ifndef _WIN32
1670036d835Schristos int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like
1680036d835Schristos #endif
169*9a3414cbSchristos int log_debug_messages = 0; // Non-zero if the user wants debug messages logged
1700036d835Schristos int retval; // keeps the returning value from several functions
1710036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1720036d835Schristos #ifndef _WIN32
1730036d835Schristos struct sigaction action;
1740036d835Schristos #endif
1750036d835Schristos
1760036d835Schristos savefile[0] = 0;
1770036d835Schristos loadfile[0] = 0;
1780036d835Schristos hostlist[0] = 0;
1790036d835Schristos
1800036d835Schristos // Initialize errbuf
1810036d835Schristos memset(errbuf, 0, sizeof(errbuf));
1820036d835Schristos
1830036d835Schristos strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
1840036d835Schristos strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
1850036d835Schristos
1860036d835Schristos // Prepare to open a new server socket
1870036d835Schristos memset(&mainhints, 0, sizeof(struct addrinfo));
1880036d835Schristos
1890036d835Schristos mainhints.ai_family = PF_UNSPEC;
1900036d835Schristos mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
1910036d835Schristos mainhints.ai_socktype = SOCK_STREAM;
1920036d835Schristos
1930036d835Schristos // Getting the proper command line options
194*9a3414cbSchristos while ((retval = getopt(argc, argv, "b:dDhip:4l:na:s:f:v")) != -1)
1950036d835Schristos {
1960036d835Schristos switch (retval)
1970036d835Schristos {
198*9a3414cbSchristos case 'D':
199*9a3414cbSchristos log_debug_messages = 1;
200*9a3414cbSchristos rpcapd_log_set(log_to_systemlog, log_debug_messages);
201*9a3414cbSchristos break;
2020036d835Schristos case 'b':
2030036d835Schristos strncpy(address, optarg, MAX_LINE);
2040036d835Schristos break;
2050036d835Schristos case 'p':
2060036d835Schristos strncpy(port, optarg, MAX_LINE);
2070036d835Schristos break;
2080036d835Schristos case '4':
2090036d835Schristos mainhints.ai_family = PF_INET; // IPv4 server only
2100036d835Schristos break;
2110036d835Schristos case 'd':
2120036d835Schristos isdaemon = 1;
213*9a3414cbSchristos log_to_systemlog = 1;
214*9a3414cbSchristos rpcapd_log_set(log_to_systemlog, log_debug_messages);
2150036d835Schristos break;
2160036d835Schristos case 'i':
2170036d835Schristos #ifdef _WIN32
2180036d835Schristos printusage();
2190036d835Schristos exit(1);
2200036d835Schristos #else
2210036d835Schristos isrunbyinetd = 1;
222*9a3414cbSchristos log_to_systemlog = 1;
223*9a3414cbSchristos rpcapd_log_set(log_to_systemlog, log_debug_messages);
2240036d835Schristos #endif
2250036d835Schristos break;
2260036d835Schristos case 'n':
2270036d835Schristos nullAuthAllowed = 1;
2280036d835Schristos break;
2290036d835Schristos case 'v':
2300036d835Schristos passivemode = 0;
2310036d835Schristos break;
2320036d835Schristos case 'l':
2330036d835Schristos {
2340036d835Schristos strncpy(hostlist, optarg, sizeof(hostlist));
2350036d835Schristos break;
2360036d835Schristos }
2370036d835Schristos case 'a':
2380036d835Schristos {
2390036d835Schristos char *tmpaddress, *tmpport;
2400036d835Schristos char *lasts;
2410036d835Schristos int i = 0;
2420036d835Schristos
2430036d835Schristos tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
2440036d835Schristos
2450036d835Schristos while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
2460036d835Schristos {
2470036d835Schristos tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
2480036d835Schristos
249*9a3414cbSchristos pcap_strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
2500036d835Schristos
2510036d835Schristos if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
252*9a3414cbSchristos pcap_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
2530036d835Schristos else
254*9a3414cbSchristos pcap_strlcpy(activelist[i].port, tmpport, MAX_LINE);
2550036d835Schristos
2560036d835Schristos tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
2570036d835Schristos
2580036d835Schristos i++;
2590036d835Schristos }
2600036d835Schristos
2610036d835Schristos if (i > MAX_ACTIVE_LIST)
262*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
2630036d835Schristos
2640036d835Schristos // I don't initialize the remaining part of the structure, since
2650036d835Schristos // it is already zeroed (it is a global var)
2660036d835Schristos break;
2670036d835Schristos }
2680036d835Schristos case 'f':
269*9a3414cbSchristos pcap_strlcpy(loadfile, optarg, MAX_LINE);
2700036d835Schristos break;
2710036d835Schristos case 's':
272*9a3414cbSchristos pcap_strlcpy(savefile, optarg, MAX_LINE);
2730036d835Schristos break;
2740036d835Schristos case 'h':
2750036d835Schristos printusage();
2760036d835Schristos exit(0);
277*9a3414cbSchristos /*NOTREACHED*/
2780036d835Schristos default:
2790036d835Schristos exit(1);
280*9a3414cbSchristos /*NOTREACHED*/
2810036d835Schristos }
2820036d835Schristos }
2830036d835Schristos
2840036d835Schristos #ifndef _WIN32
2850036d835Schristos if (isdaemon && isrunbyinetd)
2860036d835Schristos {
287*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
2880036d835Schristos exit(1);
2890036d835Schristos }
2900036d835Schristos #endif
2910036d835Schristos
292*9a3414cbSchristos if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
293*9a3414cbSchristos {
294*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
295*9a3414cbSchristos exit(-1);
296*9a3414cbSchristos }
297*9a3414cbSchristos
2980036d835Schristos if (savefile[0] && fileconf_save(savefile))
299*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
3000036d835Schristos
3010036d835Schristos // If the file does not exist, it keeps the settings provided by the command line
3020036d835Schristos if (loadfile[0])
3030036d835Schristos fileconf_read();
3040036d835Schristos
3050036d835Schristos #ifdef WIN32
3060036d835Schristos //
3070036d835Schristos // Create a handle to signal the main loop to tell it to do
3080036d835Schristos // something.
3090036d835Schristos //
3100036d835Schristos state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
3110036d835Schristos if (state_change_event == NULL)
3120036d835Schristos {
313*9a3414cbSchristos sock_geterror("Can't create state change event", errbuf,
314*9a3414cbSchristos PCAP_ERRBUF_SIZE);
315*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3160036d835Schristos exit(2);
3170036d835Schristos }
3180036d835Schristos
3190036d835Schristos //
3200036d835Schristos // Catch control signals.
3210036d835Schristos //
3220036d835Schristos if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
3230036d835Schristos {
324*9a3414cbSchristos sock_geterror("Can't set control handler", errbuf,
325*9a3414cbSchristos PCAP_ERRBUF_SIZE);
326*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3270036d835Schristos exit(2);
3280036d835Schristos }
3290036d835Schristos #else
3300036d835Schristos memset(&action, 0, sizeof (action));
3310036d835Schristos action.sa_handler = main_terminate;
3320036d835Schristos action.sa_flags = 0;
3330036d835Schristos sigemptyset(&action.sa_mask);
3340036d835Schristos sigaction(SIGTERM, &action, NULL);
3350036d835Schristos memset(&action, 0, sizeof (action));
3360036d835Schristos action.sa_handler = main_reap_children;
3370036d835Schristos action.sa_flags = 0;
3380036d835Schristos sigemptyset(&action.sa_mask);
3390036d835Schristos sigaction(SIGCHLD, &action, NULL);
3400036d835Schristos // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
3410036d835Schristos // connection, we don't want to get killed by a signal in that case
3420036d835Schristos signal(SIGPIPE, SIG_IGN);
3430036d835Schristos #endif
3440036d835Schristos
3450036d835Schristos #ifndef _WIN32
3460036d835Schristos if (isrunbyinetd)
3470036d835Schristos {
3480036d835Schristos //
3490036d835Schristos // -i was specified, indicating that this is being run
3500036d835Schristos // by inetd or something that can run network daemons
3510036d835Schristos // as if it were inetd (xinetd, launchd, systemd, etc.).
3520036d835Schristos //
353*9a3414cbSchristos // We assume that the program that launched us just
354*9a3414cbSchristos // duplicated a single socket for the connection
355*9a3414cbSchristos // to our standard input, output, and error, so we
356*9a3414cbSchristos // can just use the standard input as our control
357*9a3414cbSchristos // socket.
3580036d835Schristos //
359*9a3414cbSchristos int sockctrl;
3600036d835Schristos int devnull_fd;
3610036d835Schristos
3620036d835Schristos //
363*9a3414cbSchristos // Duplicate the standard input as the control socket.
3640036d835Schristos //
365*9a3414cbSchristos sockctrl = dup(0);
366*9a3414cbSchristos if (sockctrl == -1)
3670036d835Schristos {
368*9a3414cbSchristos sock_geterror("Can't dup standard input", errbuf,
369*9a3414cbSchristos PCAP_ERRBUF_SIZE);
370*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3710036d835Schristos exit(2);
3720036d835Schristos }
3730036d835Schristos
3740036d835Schristos //
375*9a3414cbSchristos // Try to set the standard input, output, and error
376*9a3414cbSchristos // to /dev/null.
3770036d835Schristos //
3780036d835Schristos devnull_fd = open("/dev/null", O_RDWR);
3790036d835Schristos if (devnull_fd != -1)
3800036d835Schristos {
3810036d835Schristos //
3820036d835Schristos // If this fails, just drive on.
3830036d835Schristos //
3840036d835Schristos (void)dup2(devnull_fd, 0);
3850036d835Schristos (void)dup2(devnull_fd, 1);
386*9a3414cbSchristos (void)dup2(devnull_fd, 2);
3870036d835Schristos close(devnull_fd);
3880036d835Schristos }
3890036d835Schristos
3900036d835Schristos //
3910036d835Schristos // Handle this client.
3920036d835Schristos // This is passive mode, so we don't care whether we were
3930036d835Schristos // told by the client to close.
3940036d835Schristos //
395*9a3414cbSchristos char *hostlist_copy = strdup(hostlist);
396*9a3414cbSchristos if (hostlist_copy == NULL)
397*9a3414cbSchristos {
398*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
399*9a3414cbSchristos exit(0);
400*9a3414cbSchristos }
401*9a3414cbSchristos (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
4020036d835Schristos nullAuthAllowed);
4030036d835Schristos
4040036d835Schristos //
4050036d835Schristos // Nothing more to do.
4060036d835Schristos //
4070036d835Schristos exit(0);
4080036d835Schristos }
4090036d835Schristos #endif
4100036d835Schristos
4110036d835Schristos if (isdaemon)
4120036d835Schristos {
4130036d835Schristos //
4140036d835Schristos // This is being run as a daemon.
4150036d835Schristos // On UN*X, it might be manually run, or run from an
4160036d835Schristos // rc file.
4170036d835Schristos //
4180036d835Schristos #ifndef _WIN32
4190036d835Schristos int pid;
4200036d835Schristos
4210036d835Schristos //
4220036d835Schristos // Daemonize ourselves.
4230036d835Schristos //
4240036d835Schristos // Unix Network Programming, pg 336
4250036d835Schristos //
4260036d835Schristos if ((pid = fork()) != 0)
4270036d835Schristos exit(0); // Parent terminates
4280036d835Schristos
4290036d835Schristos // First child continues
4300036d835Schristos // Set daemon mode
4310036d835Schristos setsid();
4320036d835Schristos
4330036d835Schristos // generated under unix with 'kill -HUP', needed to reload the configuration
4340036d835Schristos memset(&action, 0, sizeof (action));
4350036d835Schristos action.sa_handler = main_reread_config;
4360036d835Schristos action.sa_flags = 0;
4370036d835Schristos sigemptyset(&action.sa_mask);
4380036d835Schristos sigaction(SIGHUP, &action, NULL);
4390036d835Schristos
4400036d835Schristos if ((pid = fork()) != 0)
4410036d835Schristos exit(0); // First child terminates
4420036d835Schristos
4430036d835Schristos // LINUX WARNING: the current linux implementation of pthreads requires a management thread
4440036d835Schristos // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
4450036d835Schristos // created. Fom this point on, the number of threads active are always one more compared
4460036d835Schristos // to the number you're expecting
4470036d835Schristos
4480036d835Schristos // Second child continues
4490036d835Schristos // umask(0);
4500036d835Schristos // chdir("/");
4510036d835Schristos #else
4520036d835Schristos //
4530036d835Schristos // This is being run as a service on Windows.
4540036d835Schristos //
4550036d835Schristos // If this call succeeds, it is blocking on Win32
4560036d835Schristos //
4570036d835Schristos if (svc_start() != 1)
458*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
4590036d835Schristos
4600036d835Schristos // When the previous call returns, the entire application has to be stopped.
4610036d835Schristos exit(0);
4620036d835Schristos #endif
4630036d835Schristos }
4640036d835Schristos else // Console mode
4650036d835Schristos {
4660036d835Schristos #ifndef _WIN32
4670036d835Schristos // Enable the catching of Ctrl+C
4680036d835Schristos memset(&action, 0, sizeof (action));
4690036d835Schristos action.sa_handler = main_terminate;
4700036d835Schristos action.sa_flags = 0;
4710036d835Schristos sigemptyset(&action.sa_mask);
4720036d835Schristos sigaction(SIGINT, &action, NULL);
4730036d835Schristos
4740036d835Schristos // generated under unix with 'kill -HUP', needed to reload the configuration
4750036d835Schristos // We do not have this kind of signal in Win32
4760036d835Schristos memset(&action, 0, sizeof (action));
4770036d835Schristos action.sa_handler = main_reread_config;
4780036d835Schristos action.sa_flags = 0;
4790036d835Schristos sigemptyset(&action.sa_mask);
4800036d835Schristos sigaction(SIGHUP, &action, NULL);
4810036d835Schristos #endif
4820036d835Schristos
4830036d835Schristos printf("Press CTRL + C to stop the server...\n");
4840036d835Schristos }
4850036d835Schristos
4860036d835Schristos // If we're a Win32 service, we have already called this function in the service_main
4870036d835Schristos main_startup();
4880036d835Schristos
4890036d835Schristos // The code should never arrive here (since the main_startup is blocking)
4900036d835Schristos // however this avoids a compiler warning
4910036d835Schristos exit(0);
4920036d835Schristos }
4930036d835Schristos
main_startup(void)4940036d835Schristos void main_startup(void)
4950036d835Schristos {
4960036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
4970036d835Schristos struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
4980036d835Schristos int i;
4990036d835Schristos #ifdef _WIN32
5000036d835Schristos HANDLE threadId; // handle for the subthread
5010036d835Schristos #else
5020036d835Schristos pid_t pid;
5030036d835Schristos #endif
5040036d835Schristos
5050036d835Schristos i = 0;
5060036d835Schristos addrinfo = NULL;
5070036d835Schristos memset(errbuf, 0, sizeof(errbuf));
5080036d835Schristos
5090036d835Schristos // Starts all the active threads
5100036d835Schristos while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
5110036d835Schristos {
5120036d835Schristos activelist[i].ai_family = mainhints.ai_family;
5130036d835Schristos
5140036d835Schristos #ifdef _WIN32
5150036d835Schristos threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
5160036d835Schristos (void *)&activelist[i], 0, NULL);
5170036d835Schristos if (threadId == 0)
5180036d835Schristos {
519*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
5200036d835Schristos continue;
5210036d835Schristos }
5220036d835Schristos CloseHandle(threadId);
5230036d835Schristos #else
5240036d835Schristos if ((pid = fork()) == 0) // I am the child
5250036d835Schristos {
5260036d835Schristos main_active((void *) &activelist[i]);
5270036d835Schristos exit(0);
5280036d835Schristos }
5290036d835Schristos #endif
5300036d835Schristos i++;
5310036d835Schristos }
5320036d835Schristos
5330036d835Schristos /*
5340036d835Schristos * The code that manages the active connections is not blocking;
5350036d835Schristos * the code that manages the passive connection is blocking.
5360036d835Schristos * So, if the user does not want to run in passive mode, we have
5370036d835Schristos * to block the main thread here, otherwise the program ends and
5380036d835Schristos * all threads are stopped.
5390036d835Schristos *
5400036d835Schristos * WARNING: this means that in case we have only active mode,
5410036d835Schristos * the program does not terminate even if all the child thread
5420036d835Schristos * terminates. The user has always to press Ctrl+C (or send a
5430036d835Schristos * SIGTERM) to terminate the program.
5440036d835Schristos */
5450036d835Schristos if (passivemode)
5460036d835Schristos {
5470036d835Schristos struct addrinfo *tempaddrinfo;
5480036d835Schristos
5490036d835Schristos //
5500036d835Schristos // Get a list of sockets on which to listen.
5510036d835Schristos //
5520036d835Schristos if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
5530036d835Schristos {
554*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
5550036d835Schristos return;
5560036d835Schristos }
5570036d835Schristos
5580036d835Schristos for (tempaddrinfo = addrinfo; tempaddrinfo;
5590036d835Schristos tempaddrinfo = tempaddrinfo->ai_next)
5600036d835Schristos {
5610036d835Schristos SOCKET sock;
5620036d835Schristos struct listen_sock *sock_info;
5630036d835Schristos
5640036d835Schristos if ((sock = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
5650036d835Schristos {
5660036d835Schristos switch (tempaddrinfo->ai_family)
5670036d835Schristos {
5680036d835Schristos case AF_INET:
5690036d835Schristos {
5700036d835Schristos struct sockaddr_in *in;
5710036d835Schristos char addrbuf[INET_ADDRSTRLEN];
5720036d835Schristos
5730036d835Schristos in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
5740036d835Schristos rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
5750036d835Schristos inet_ntop(AF_INET, &in->sin_addr,
5760036d835Schristos addrbuf, sizeof (addrbuf)),
5770036d835Schristos ntohs(in->sin_port),
5780036d835Schristos errbuf);
5790036d835Schristos break;
5800036d835Schristos }
5810036d835Schristos
5820036d835Schristos case AF_INET6:
5830036d835Schristos {
5840036d835Schristos struct sockaddr_in6 *in6;
5850036d835Schristos char addrbuf[INET6_ADDRSTRLEN];
5860036d835Schristos
5870036d835Schristos in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
5880036d835Schristos rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
5890036d835Schristos inet_ntop(AF_INET6, &in6->sin6_addr,
5900036d835Schristos addrbuf, sizeof (addrbuf)),
5910036d835Schristos ntohs(in6->sin6_port),
5920036d835Schristos errbuf);
5930036d835Schristos break;
5940036d835Schristos }
5950036d835Schristos
5960036d835Schristos default:
5970036d835Schristos rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
5980036d835Schristos tempaddrinfo->ai_family,
5990036d835Schristos errbuf);
6000036d835Schristos break;
6010036d835Schristos }
6020036d835Schristos continue;
6030036d835Schristos }
6040036d835Schristos
6050036d835Schristos sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
6060036d835Schristos if (sock_info == NULL)
6070036d835Schristos {
6080036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
6090036d835Schristos exit(2);
6100036d835Schristos }
6110036d835Schristos sock_info->sock = sock;
6120036d835Schristos sock_info->next = listen_socks;
6130036d835Schristos listen_socks = sock_info;
6140036d835Schristos }
6150036d835Schristos
6160036d835Schristos freeaddrinfo(addrinfo);
6170036d835Schristos
6180036d835Schristos if (listen_socks == NULL)
6190036d835Schristos {
6200036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
6210036d835Schristos exit(2);
6220036d835Schristos }
6230036d835Schristos
6240036d835Schristos //
6250036d835Schristos // Now listen on all of them, waiting for connections.
6260036d835Schristos //
6270036d835Schristos accept_connections();
6280036d835Schristos }
6290036d835Schristos
6300036d835Schristos //
6310036d835Schristos // We're done; exit.
6320036d835Schristos //
633*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
6340036d835Schristos
6350036d835Schristos #ifndef _WIN32
6360036d835Schristos //
6370036d835Schristos // Sends a KILL signal to all the processes in this process's
6380036d835Schristos // process group; i.e., it kills all the child processes
6390036d835Schristos // we've created.
6400036d835Schristos //
6410036d835Schristos // XXX - that also includes us, so we will be killed as well;
6420036d835Schristos // that may cause a message to be printed or logged.
6430036d835Schristos //
6440036d835Schristos kill(0, SIGKILL);
6450036d835Schristos #endif
6460036d835Schristos
6470036d835Schristos //
6480036d835Schristos // Just leave. We shouldn't need to clean up sockets or
6490036d835Schristos // anything else, and if we try to do so, we'll could end
6500036d835Schristos // up closing sockets, or shutting Winsock down, out from
6510036d835Schristos // under service loops, causing all sorts of noisy error
6520036d835Schristos // messages.
6530036d835Schristos //
6540036d835Schristos // We shouldn't need to worry about cleaning up any resources
6550036d835Schristos // such as handles, sockets, threads, etc. - exit() should
6560036d835Schristos // terminate the process, causing all those resources to be
6570036d835Schristos // cleaned up (including the threads; Microsoft claims in the
6580036d835Schristos // ExitProcess() documentation that, if ExitProcess() is called,
6590036d835Schristos // "If a thread is waiting on a kernel object, it will not be
6600036d835Schristos // terminated until the wait has completed.", but claims in the
6610036d835Schristos // _beginthread()/_beginthreadex() documentation that "All threads
6620036d835Schristos // are terminated if any thread calls abort, exit, _exit, or
6630036d835Schristos // ExitProcess." - the latter appears to be the case, even for
6640036d835Schristos // threads waiting on the event for a pcap_t).
6650036d835Schristos //
6660036d835Schristos exit(0);
6670036d835Schristos }
6680036d835Schristos
6690036d835Schristos #ifdef _WIN32
6700036d835Schristos static void
send_state_change_event(void)6710036d835Schristos send_state_change_event(void)
6720036d835Schristos {
6730036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
6740036d835Schristos
6750036d835Schristos if (!SetEvent(state_change_event))
6760036d835Schristos {
677*9a3414cbSchristos sock_geterror("SetEvent on shutdown event failed", errbuf,
678*9a3414cbSchristos PCAP_ERRBUF_SIZE);
679*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
6800036d835Schristos }
6810036d835Schristos }
6820036d835Schristos
6830036d835Schristos void
send_shutdown_notification(void)6840036d835Schristos send_shutdown_notification(void)
6850036d835Schristos {
6860036d835Schristos //
6870036d835Schristos // Indicate that the server should shut down.
6880036d835Schristos //
6890036d835Schristos shutdown_server = 1;
6900036d835Schristos
6910036d835Schristos //
6920036d835Schristos // Send a state change event, to wake up WSAWaitForMultipleEvents().
6930036d835Schristos //
6940036d835Schristos send_state_change_event();
6950036d835Schristos }
6960036d835Schristos
6970036d835Schristos void
send_reread_configuration_notification(void)6980036d835Schristos send_reread_configuration_notification(void)
6990036d835Schristos {
7000036d835Schristos //
7010036d835Schristos // Indicate that the server should re-read its configuration file.
7020036d835Schristos //
7030036d835Schristos reread_config = 1;
7040036d835Schristos
7050036d835Schristos //
7060036d835Schristos // Send a state change event, to wake up WSAWaitForMultipleEvents().
7070036d835Schristos //
7080036d835Schristos send_state_change_event();
7090036d835Schristos }
7100036d835Schristos
main_ctrl_event(DWORD ctrltype)7110036d835Schristos static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
7120036d835Schristos {
7130036d835Schristos //
7140036d835Schristos // ctrltype is one of:
7150036d835Schristos //
7160036d835Schristos // CTRL_C_EVENT - we got a ^C; this is like SIGINT
7170036d835Schristos // CTRL_BREAK_EVENT - we got Ctrl+Break
7180036d835Schristos // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
7190036d835Schristos // CTRL_LOGOFF_EVENT - a user is logging off; this is received
7200036d835Schristos // only by services
7210036d835Schristos // CTRL_SHUTDOWN_EVENT - the systemis shutting down; this is
7220036d835Schristos // received only by services
7230036d835Schristos //
7240036d835Schristos // For now, we treat all but CTRL_LOGOFF_EVENT as indications
7250036d835Schristos // that we should shut down.
7260036d835Schristos //
7270036d835Schristos switch (ctrltype)
7280036d835Schristos {
7290036d835Schristos case CTRL_C_EVENT:
7300036d835Schristos case CTRL_BREAK_EVENT:
7310036d835Schristos case CTRL_CLOSE_EVENT:
7320036d835Schristos case CTRL_SHUTDOWN_EVENT:
7330036d835Schristos //
7340036d835Schristos // Set a shutdown notification.
7350036d835Schristos //
7360036d835Schristos send_shutdown_notification();
7370036d835Schristos break;
7380036d835Schristos
7390036d835Schristos default:
7400036d835Schristos break;
7410036d835Schristos }
7420036d835Schristos
7430036d835Schristos //
7440036d835Schristos // We handled this.
7450036d835Schristos //
7460036d835Schristos return TRUE;
7470036d835Schristos }
7480036d835Schristos #else
main_terminate(int sign _U_)7490036d835Schristos static void main_terminate(int sign _U_)
7500036d835Schristos {
7510036d835Schristos //
7520036d835Schristos // Note that the server should shut down.
7530036d835Schristos // select() should get an EINTR error when we return,
7540036d835Schristos // so it will wake up and know it needs to check the flag.
7550036d835Schristos //
7560036d835Schristos shutdown_server = 1;
7570036d835Schristos }
7580036d835Schristos
main_reread_config(int sign _U_)7590036d835Schristos static void main_reread_config(int sign _U_)
7600036d835Schristos {
7610036d835Schristos //
7620036d835Schristos // Note that the server should re-read its configuration file.
7630036d835Schristos // select() should get an EINTR error when we return,
7640036d835Schristos // so it will wake up and know it needs to check the flag.
7650036d835Schristos //
7660036d835Schristos reread_config = 1;
7670036d835Schristos }
7680036d835Schristos
main_reap_children(int sign _U_)7690036d835Schristos static void main_reap_children(int sign _U_)
7700036d835Schristos {
7710036d835Schristos pid_t pid;
7720036d835Schristos int exitstat;
7730036d835Schristos
7740036d835Schristos // Reap all child processes that have exited.
7750036d835Schristos // For reference, Stevens, pg 128
7760036d835Schristos
7770036d835Schristos while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
778*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
7790036d835Schristos
7800036d835Schristos return;
7810036d835Schristos }
7820036d835Schristos #endif
7830036d835Schristos
7840036d835Schristos //
7850036d835Schristos // Loop waiting for incoming connections and accepting them.
7860036d835Schristos //
7870036d835Schristos static void
accept_connections(void)7880036d835Schristos accept_connections(void)
7890036d835Schristos {
7900036d835Schristos #ifdef _WIN32
7910036d835Schristos struct listen_sock *sock_info;
7920036d835Schristos DWORD num_events;
7930036d835Schristos WSAEVENT *events;
7940036d835Schristos int i;
7950036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
7960036d835Schristos
7970036d835Schristos //
7980036d835Schristos // How big does the set of events need to be?
7990036d835Schristos // One for the shutdown event, plus one for every socket on which
8000036d835Schristos // we'll be listening.
8010036d835Schristos //
8020036d835Schristos num_events = 1; // shutdown event
8030036d835Schristos for (sock_info = listen_socks; sock_info;
8040036d835Schristos sock_info = sock_info->next)
8050036d835Schristos {
8060036d835Schristos if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
8070036d835Schristos {
8080036d835Schristos //
8090036d835Schristos // WSAWaitForMultipleEvents() doesn't support
8100036d835Schristos // more than WSA_MAXIMUM_WAIT_EVENTS events
8110036d835Schristos // on which to wait.
8120036d835Schristos //
8130036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
8140036d835Schristos exit(2);
8150036d835Schristos }
8160036d835Schristos num_events++;
8170036d835Schristos }
8180036d835Schristos
8190036d835Schristos //
8200036d835Schristos // Allocate the array of events.
8210036d835Schristos //
8220036d835Schristos events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
8230036d835Schristos if (events == NULL)
8240036d835Schristos {
8250036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
8260036d835Schristos exit(2);
8270036d835Schristos }
8280036d835Schristos
8290036d835Schristos //
8300036d835Schristos // Fill it in.
8310036d835Schristos //
8320036d835Schristos events[0] = state_change_event; // state change event first
8330036d835Schristos for (sock_info = listen_socks, i = 1; sock_info;
8340036d835Schristos sock_info = sock_info->next, i++)
8350036d835Schristos {
8360036d835Schristos WSAEVENT event;
8370036d835Schristos
8380036d835Schristos //
8390036d835Schristos // Create an event that is signaled if there's a connection
8400036d835Schristos // to accept on the socket in question.
8410036d835Schristos //
8420036d835Schristos event = WSACreateEvent();
8430036d835Schristos if (event == WSA_INVALID_EVENT)
8440036d835Schristos {
845*9a3414cbSchristos sock_geterror("Can't create socket event", errbuf,
846*9a3414cbSchristos PCAP_ERRBUF_SIZE);
847*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8480036d835Schristos exit(2);
8490036d835Schristos }
8500036d835Schristos if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
8510036d835Schristos {
852*9a3414cbSchristos sock_geterror("Can't setup socket event", errbuf,
853*9a3414cbSchristos PCAP_ERRBUF_SIZE);
854*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8550036d835Schristos exit(2);
8560036d835Schristos }
8570036d835Schristos events[i] = event;
8580036d835Schristos }
8590036d835Schristos
8600036d835Schristos for (;;)
8610036d835Schristos {
8620036d835Schristos //
8630036d835Schristos // Wait for incoming connections.
8640036d835Schristos //
8650036d835Schristos DWORD ret;
8660036d835Schristos
8670036d835Schristos ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
8680036d835Schristos WSA_INFINITE, FALSE);
8690036d835Schristos if (ret == WSA_WAIT_FAILED)
8700036d835Schristos {
871*9a3414cbSchristos sock_geterror("WSAWaitForMultipleEvents failed", errbuf,
872*9a3414cbSchristos PCAP_ERRBUF_SIZE);
873*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
8740036d835Schristos exit(2);
8750036d835Schristos }
8760036d835Schristos
8770036d835Schristos if (ret == WSA_WAIT_EVENT_0)
8780036d835Schristos {
8790036d835Schristos //
8800036d835Schristos // The state change event was set.
8810036d835Schristos //
8820036d835Schristos if (shutdown_server)
8830036d835Schristos {
8840036d835Schristos //
8850036d835Schristos // Time to quit. Exit the loop.
8860036d835Schristos //
8870036d835Schristos break;
8880036d835Schristos }
8890036d835Schristos if (reread_config)
8900036d835Schristos {
8910036d835Schristos //
8920036d835Schristos // We should re-read the configuration
8930036d835Schristos // file.
8940036d835Schristos //
8950036d835Schristos reread_config = 0; // clear the indicator
8960036d835Schristos fileconf_read();
8970036d835Schristos }
8980036d835Schristos }
8990036d835Schristos
9000036d835Schristos //
9010036d835Schristos // Check each socket.
9020036d835Schristos //
9030036d835Schristos for (sock_info = listen_socks, i = 1; sock_info;
9040036d835Schristos sock_info = sock_info->next, i++)
9050036d835Schristos {
9060036d835Schristos WSANETWORKEVENTS network_events;
9070036d835Schristos
9080036d835Schristos if (WSAEnumNetworkEvents(sock_info->sock,
9090036d835Schristos events[i], &network_events) == SOCKET_ERROR)
9100036d835Schristos {
911*9a3414cbSchristos sock_geterror("WSAEnumNetworkEvents failed",
912*9a3414cbSchristos errbuf, PCAP_ERRBUF_SIZE);
913*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
9140036d835Schristos exit(2);
9150036d835Schristos }
9160036d835Schristos if (network_events.lNetworkEvents & FD_ACCEPT)
9170036d835Schristos {
9180036d835Schristos //
9190036d835Schristos // Did an error occur?
9200036d835Schristos //
9210036d835Schristos if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
9220036d835Schristos {
9230036d835Schristos //
9240036d835Schristos // Yes - report it and keep going.
9250036d835Schristos //
926*9a3414cbSchristos sock_fmterror("Socket error",
9270036d835Schristos network_events.iErrorCode[FD_ACCEPT_BIT],
9280036d835Schristos errbuf,
9290036d835Schristos PCAP_ERRBUF_SIZE);
930*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
9310036d835Schristos continue;
9320036d835Schristos }
9330036d835Schristos
9340036d835Schristos //
9350036d835Schristos // Accept the connection.
9360036d835Schristos //
9370036d835Schristos accept_connection(sock_info->sock);
9380036d835Schristos }
9390036d835Schristos }
9400036d835Schristos }
9410036d835Schristos #else
9420036d835Schristos struct listen_sock *sock_info;
9430036d835Schristos int num_sock_fds;
9440036d835Schristos
9450036d835Schristos //
9460036d835Schristos // How big does the bitset of sockets on which to select() have
9470036d835Schristos // to be?
9480036d835Schristos //
9490036d835Schristos num_sock_fds = 0;
9500036d835Schristos for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
9510036d835Schristos {
9520036d835Schristos if (sock_info->sock + 1 > num_sock_fds)
9530036d835Schristos {
9540036d835Schristos if ((unsigned int)(sock_info->sock + 1) >
9550036d835Schristos (unsigned int)FD_SETSIZE)
9560036d835Schristos {
9570036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
9580036d835Schristos exit(2);
9590036d835Schristos }
9600036d835Schristos num_sock_fds = sock_info->sock + 1;
9610036d835Schristos }
9620036d835Schristos }
9630036d835Schristos
9640036d835Schristos for (;;)
9650036d835Schristos {
9660036d835Schristos fd_set sock_fds;
9670036d835Schristos int ret;
9680036d835Schristos
9690036d835Schristos //
9700036d835Schristos // Set up an fd_set for all the sockets on which we're
9710036d835Schristos // listening.
9720036d835Schristos //
9730036d835Schristos // This set is modified by select(), so we have to
9740036d835Schristos // construct it anew each time.
9750036d835Schristos //
9760036d835Schristos FD_ZERO(&sock_fds);
9770036d835Schristos for (sock_info = listen_socks; sock_info;
9780036d835Schristos sock_info = sock_info->next)
9790036d835Schristos {
9800036d835Schristos FD_SET(sock_info->sock, &sock_fds);
9810036d835Schristos }
9820036d835Schristos
9830036d835Schristos //
9840036d835Schristos // Wait for incoming connections.
9850036d835Schristos //
9860036d835Schristos ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
9870036d835Schristos if (ret == -1)
9880036d835Schristos {
9890036d835Schristos if (errno == EINTR)
9900036d835Schristos {
9910036d835Schristos //
9920036d835Schristos // If this is a "terminate the
9930036d835Schristos // server" signal, exit the loop,
9940036d835Schristos // otherwise just keep trying.
9950036d835Schristos //
9960036d835Schristos if (shutdown_server)
9970036d835Schristos {
9980036d835Schristos //
9990036d835Schristos // Time to quit. Exit the loop.
10000036d835Schristos //
10010036d835Schristos break;
10020036d835Schristos }
10030036d835Schristos if (reread_config)
10040036d835Schristos {
10050036d835Schristos //
10060036d835Schristos // We should re-read the configuration
10070036d835Schristos // file.
10080036d835Schristos //
10090036d835Schristos reread_config = 0; // clear the indicator
10100036d835Schristos fileconf_read();
10110036d835Schristos }
10120036d835Schristos
10130036d835Schristos //
10140036d835Schristos // Go back and wait again.
10150036d835Schristos //
10160036d835Schristos continue;
10170036d835Schristos }
10180036d835Schristos else
10190036d835Schristos {
10200036d835Schristos rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
10210036d835Schristos strerror(errno));
10220036d835Schristos exit(2);
10230036d835Schristos }
10240036d835Schristos }
10250036d835Schristos
10260036d835Schristos //
10270036d835Schristos // Check each socket.
10280036d835Schristos //
10290036d835Schristos for (sock_info = listen_socks; sock_info;
10300036d835Schristos sock_info = sock_info->next)
10310036d835Schristos {
10320036d835Schristos if (FD_ISSET(sock_info->sock, &sock_fds))
10330036d835Schristos {
10340036d835Schristos //
10350036d835Schristos // Accept the connection.
10360036d835Schristos //
10370036d835Schristos accept_connection(sock_info->sock);
10380036d835Schristos }
10390036d835Schristos }
10400036d835Schristos }
10410036d835Schristos #endif
10420036d835Schristos
10430036d835Schristos //
10440036d835Schristos // Close all the listen sockets.
10450036d835Schristos //
10460036d835Schristos for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
10470036d835Schristos {
10480036d835Schristos closesocket(sock_info->sock);
10490036d835Schristos }
10500036d835Schristos sock_cleanup();
10510036d835Schristos }
10520036d835Schristos
1053*9a3414cbSchristos #ifdef _WIN32
1054*9a3414cbSchristos //
1055*9a3414cbSchristos // A structure to hold the parameters to the daemon service loop
1056*9a3414cbSchristos // thread on Windows.
1057*9a3414cbSchristos //
1058*9a3414cbSchristos // (On UN*X, there is no need for this explicit copy since the
1059*9a3414cbSchristos // fork "inherits" the parent stack.)
1060*9a3414cbSchristos //
1061*9a3414cbSchristos struct params_copy {
1062*9a3414cbSchristos SOCKET sockctrl;
1063*9a3414cbSchristos char *hostlist;
1064*9a3414cbSchristos };
1065*9a3414cbSchristos #endif
1066*9a3414cbSchristos
10670036d835Schristos //
10680036d835Schristos // Accept a connection and start a worker thread, on Windows, or a
10690036d835Schristos // worker process, on UN*X, to handle the connection.
10700036d835Schristos //
10710036d835Schristos static void
accept_connection(SOCKET listen_sock)10720036d835Schristos accept_connection(SOCKET listen_sock)
10730036d835Schristos {
10740036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
10750036d835Schristos SOCKET sockctrl; // keeps the socket ID for this control connection
10760036d835Schristos struct sockaddr_storage from; // generic sockaddr_storage variable
10770036d835Schristos socklen_t fromlen; // keeps the length of the sockaddr_storage variable
10780036d835Schristos
10790036d835Schristos #ifdef _WIN32
10800036d835Schristos HANDLE threadId; // handle for the subthread
10810036d835Schristos u_long off = 0;
1082*9a3414cbSchristos struct params_copy *params_copy = NULL;
10830036d835Schristos #else
10840036d835Schristos pid_t pid;
10850036d835Schristos #endif
10860036d835Schristos
10870036d835Schristos // Initialize errbuf
10880036d835Schristos memset(errbuf, 0, sizeof(errbuf));
10890036d835Schristos
10900036d835Schristos for (;;)
10910036d835Schristos {
10920036d835Schristos // Accept the connection
10930036d835Schristos fromlen = sizeof(struct sockaddr_storage);
10940036d835Schristos
10950036d835Schristos sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
10960036d835Schristos
10970036d835Schristos if (sockctrl != INVALID_SOCKET)
10980036d835Schristos {
10990036d835Schristos // Success.
11000036d835Schristos break;
11010036d835Schristos }
11020036d835Schristos
11030036d835Schristos // The accept() call can return this error when a signal is catched
11040036d835Schristos // In this case, we have simply to ignore this error code
11050036d835Schristos // Stevens, pg 124
11060036d835Schristos #ifdef _WIN32
11070036d835Schristos if (WSAGetLastError() == WSAEINTR)
11080036d835Schristos #else
11090036d835Schristos if (errno == EINTR)
11100036d835Schristos #endif
11110036d835Schristos continue;
11120036d835Schristos
11130036d835Schristos // Don't check for errors here, since the error can be due to the fact that the thread
11140036d835Schristos // has been killed
1115*9a3414cbSchristos sock_geterror("accept()", errbuf, PCAP_ERRBUF_SIZE);
11160036d835Schristos rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
11170036d835Schristos errbuf);
11180036d835Schristos return;
11190036d835Schristos }
11200036d835Schristos
11210036d835Schristos #ifdef _WIN32
11220036d835Schristos //
11230036d835Schristos // Put the socket back into blocking mode; doing WSAEventSelect()
11240036d835Schristos // on the listen socket makes that socket non-blocking, and it
11250036d835Schristos // appears that sockets returned from an accept() on that socket
11260036d835Schristos // are also non-blocking.
11270036d835Schristos //
11280036d835Schristos // First, we have to un-WSAEventSelect() this socket, and then
11290036d835Schristos // we can turn non-blocking mode off.
11300036d835Schristos //
1131*9a3414cbSchristos // If this fails, we aren't guaranteed that, for example, any
1132*9a3414cbSchristos // of the error message will be sent - if it can't be put in
1133*9a3414cbSchristos // the socket queue, the send will just fail.
1134*9a3414cbSchristos //
1135*9a3414cbSchristos // So we just log the message and close the connection.
1136*9a3414cbSchristos //
11370036d835Schristos if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
11380036d835Schristos {
1139*9a3414cbSchristos sock_geterror("WSAEventSelect()", errbuf, PCAP_ERRBUF_SIZE);
1140*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
11410036d835Schristos sock_close(sockctrl, NULL, 0);
11420036d835Schristos return;
11430036d835Schristos }
11440036d835Schristos if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
11450036d835Schristos {
1146*9a3414cbSchristos sock_geterror("ioctlsocket(FIONBIO)", errbuf, PCAP_ERRBUF_SIZE);
1147*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
11480036d835Schristos sock_close(sockctrl, NULL, 0);
11490036d835Schristos return;
11500036d835Schristos }
11510036d835Schristos
11520036d835Schristos //
1153*9a3414cbSchristos // Make a copy of the host list to pass to the new thread, so that
1154*9a3414cbSchristos // if we update it in the main thread, it won't catch us in the
1155*9a3414cbSchristos // middle of updating it.
1156*9a3414cbSchristos //
1157*9a3414cbSchristos // daemon_serviceloop() will free it once it's done with it.
1158*9a3414cbSchristos //
1159*9a3414cbSchristos char *hostlist_copy = strdup(hostlist);
1160*9a3414cbSchristos if (hostlist_copy == NULL)
1161*9a3414cbSchristos {
1162*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1163*9a3414cbSchristos sock_close(sockctrl, NULL, 0);
1164*9a3414cbSchristos return;
1165*9a3414cbSchristos }
1166*9a3414cbSchristos
1167*9a3414cbSchristos //
1168*9a3414cbSchristos // Allocate a location to hold the values of sockctrl.
11690036d835Schristos // It will be freed in the newly-created thread once it's
11700036d835Schristos // finished with it.
11710036d835Schristos //
1172*9a3414cbSchristos params_copy = malloc(sizeof(*params_copy));
1173*9a3414cbSchristos if (params_copy == NULL)
11740036d835Schristos {
1175*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
1176*9a3414cbSchristos free(hostlist_copy);
11770036d835Schristos sock_close(sockctrl, NULL, 0);
11780036d835Schristos return;
11790036d835Schristos }
1180*9a3414cbSchristos params_copy->sockctrl = sockctrl;
1181*9a3414cbSchristos params_copy->hostlist = hostlist_copy;
11820036d835Schristos
11830036d835Schristos threadId = (HANDLE)_beginthreadex(NULL, 0,
1184*9a3414cbSchristos main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
11850036d835Schristos if (threadId == 0)
11860036d835Schristos {
1187*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
1188*9a3414cbSchristos free(params_copy);
1189*9a3414cbSchristos free(hostlist_copy);
11900036d835Schristos sock_close(sockctrl, NULL, 0);
11910036d835Schristos return;
11920036d835Schristos }
11930036d835Schristos CloseHandle(threadId);
1194*9a3414cbSchristos #else /* _WIN32 */
11950036d835Schristos pid = fork();
11960036d835Schristos if (pid == -1)
11970036d835Schristos {
1198*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
1199*9a3414cbSchristos strerror(errno));
12000036d835Schristos sock_close(sockctrl, NULL, 0);
12010036d835Schristos return;
12020036d835Schristos }
12030036d835Schristos if (pid == 0)
12040036d835Schristos {
12050036d835Schristos //
12060036d835Schristos // Child process.
12070036d835Schristos //
12080036d835Schristos // Close the socket on which we're listening (must
12090036d835Schristos // be open only in the parent).
12100036d835Schristos //
12110036d835Schristos closesocket(listen_sock);
12120036d835Schristos
12130036d835Schristos #if 0
12140036d835Schristos //
12150036d835Schristos // Modify thread params so that it can be killed at any time
12160036d835Schristos // XXX - is this necessary? This is the main and, currently,
12170036d835Schristos // only thread in the child process, and nobody tries to
12180036d835Schristos // cancel us, although *we* may cancel the thread that's
12190036d835Schristos // handling the capture loop.
12200036d835Schristos //
12210036d835Schristos if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
12220036d835Schristos goto end;
12230036d835Schristos if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
12240036d835Schristos goto end;
12250036d835Schristos #endif
12260036d835Schristos
12270036d835Schristos //
12280036d835Schristos // Run the service loop.
12290036d835Schristos // This is passive mode, so we don't care whether we were
12300036d835Schristos // told by the client to close.
12310036d835Schristos //
1232*9a3414cbSchristos char *hostlist_copy = strdup(hostlist);
1233*9a3414cbSchristos if (hostlist_copy == NULL)
1234*9a3414cbSchristos {
1235*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1236*9a3414cbSchristos exit(0);
1237*9a3414cbSchristos }
1238*9a3414cbSchristos (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
12390036d835Schristos nullAuthAllowed);
12400036d835Schristos
12410036d835Schristos exit(0);
12420036d835Schristos }
12430036d835Schristos
12440036d835Schristos // I am the parent
12450036d835Schristos // Close the socket for this session (must be open only in the child)
12460036d835Schristos closesocket(sockctrl);
1247*9a3414cbSchristos #endif /* _WIN32 */
12480036d835Schristos }
12490036d835Schristos
12500036d835Schristos /*!
12510036d835Schristos \brief 'true' main of the program in case the active mode is turned on.
12520036d835Schristos
12530036d835Schristos This function loops forever trying to connect to the remote host, until the
12540036d835Schristos daemon is turned down.
12550036d835Schristos
12560036d835Schristos \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
12570036d835Schristos just because the thread APIs want this format.
12580036d835Schristos */
12590036d835Schristos #ifdef _WIN32
12600036d835Schristos static unsigned __stdcall
12610036d835Schristos #else
12620036d835Schristos static void *
12630036d835Schristos #endif
main_active(void * ptr)12640036d835Schristos main_active(void *ptr)
12650036d835Schristos {
12660036d835Schristos char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
12670036d835Schristos SOCKET sockctrl; // keeps the socket ID for this control connection
12680036d835Schristos struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
12690036d835Schristos struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
12700036d835Schristos struct active_pars *activepars;
12710036d835Schristos
12720036d835Schristos activepars = (struct active_pars *) ptr;
12730036d835Schristos
12740036d835Schristos // Prepare to open a new server socket
12750036d835Schristos memset(&hints, 0, sizeof(struct addrinfo));
12760036d835Schristos // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
12770036d835Schristos hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
12780036d835Schristos hints.ai_socktype = SOCK_STREAM;
12790036d835Schristos hints.ai_family = activepars->ai_family;
12800036d835Schristos
1281*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
12820036d835Schristos activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
12830036d835Schristos (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
12840036d835Schristos
12850036d835Schristos // Initialize errbuf
12860036d835Schristos memset(errbuf, 0, sizeof(errbuf));
12870036d835Schristos
12880036d835Schristos // Do the work
12890036d835Schristos if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
12900036d835Schristos {
1291*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
12920036d835Schristos return 0;
12930036d835Schristos }
12940036d835Schristos
12950036d835Schristos for (;;)
12960036d835Schristos {
12970036d835Schristos int activeclose;
12980036d835Schristos
12990036d835Schristos if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
13000036d835Schristos {
1301*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
13020036d835Schristos
13030036d835Schristos pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
13040036d835Schristos activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
13050036d835Schristos (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
13060036d835Schristos
1307*9a3414cbSchristos rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
13080036d835Schristos
13090036d835Schristos sleep_secs(RPCAP_ACTIVE_WAIT);
13100036d835Schristos
13110036d835Schristos continue;
13120036d835Schristos }
13130036d835Schristos
1314*9a3414cbSchristos char *hostlist_copy = strdup(hostlist);
1315*9a3414cbSchristos if (hostlist_copy == NULL)
1316*9a3414cbSchristos {
1317*9a3414cbSchristos rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1318*9a3414cbSchristos activeclose = 0;
13190036d835Schristos sock_close(sockctrl, NULL, 0);
1320*9a3414cbSchristos }
1321*9a3414cbSchristos else
1322*9a3414cbSchristos {
1323*9a3414cbSchristos //
1324*9a3414cbSchristos // daemon_serviceloop() will free the copy.
1325*9a3414cbSchristos //
1326*9a3414cbSchristos activeclose = daemon_serviceloop(sockctrl, 1,
1327*9a3414cbSchristos hostlist_copy, nullAuthAllowed);
1328*9a3414cbSchristos }
13290036d835Schristos
13300036d835Schristos // If the connection is closed by the user explicitely, don't try to connect to it again
13310036d835Schristos // just exit the program
13320036d835Schristos if (activeclose == 1)
13330036d835Schristos break;
13340036d835Schristos }
13350036d835Schristos
13360036d835Schristos freeaddrinfo(addrinfo);
13370036d835Schristos return 0;
13380036d835Schristos }
13390036d835Schristos
13400036d835Schristos #ifdef _WIN32
13410036d835Schristos //
13420036d835Schristos // Main routine of a passive-mode service thread.
13430036d835Schristos //
main_passive_serviceloop_thread(void * ptr)13440036d835Schristos unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
13450036d835Schristos {
1346*9a3414cbSchristos struct params_copy params = *(struct params_copy *)ptr;
13470036d835Schristos free(ptr);
13480036d835Schristos
13490036d835Schristos //
13500036d835Schristos // Handle this client.
13510036d835Schristos // This is passive mode, so we don't care whether we were
13520036d835Schristos // told by the client to close.
13530036d835Schristos //
1354*9a3414cbSchristos (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
1355*9a3414cbSchristos nullAuthAllowed);
13560036d835Schristos
13570036d835Schristos return 0;
13580036d835Schristos }
13590036d835Schristos #endif
1360