157e22627SCy Schubert /*
257e22627SCy Schubert * Copyright (c) 2002 - 2003
357e22627SCy Schubert * NetGroup, Politecnico di Torino (Italy)
457e22627SCy Schubert * All rights reserved.
557e22627SCy Schubert *
657e22627SCy Schubert * Redistribution and use in source and binary forms, with or without
757e22627SCy Schubert * modification, are permitted provided that the following conditions
857e22627SCy Schubert * are met:
957e22627SCy Schubert *
1057e22627SCy Schubert * 1. Redistributions of source code must retain the above copyright
1157e22627SCy Schubert * notice, this list of conditions and the following disclaimer.
1257e22627SCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
1357e22627SCy Schubert * notice, this list of conditions and the following disclaimer in the
1457e22627SCy Schubert * documentation and/or other materials provided with the distribution.
1557e22627SCy Schubert * 3. Neither the name of the Politecnico di Torino nor the names of its
1657e22627SCy Schubert * contributors may be used to endorse or promote products derived from
1757e22627SCy Schubert * this software without specific prior written permission.
1857e22627SCy Schubert *
1957e22627SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2057e22627SCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2157e22627SCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2257e22627SCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2357e22627SCy Schubert * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2457e22627SCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2557e22627SCy Schubert * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2657e22627SCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2757e22627SCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2857e22627SCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2957e22627SCy Schubert * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3057e22627SCy Schubert *
3157e22627SCy Schubert */
3257e22627SCy Schubert
3357e22627SCy Schubert #include <config.h>
3457e22627SCy Schubert
3557e22627SCy Schubert #include "ftmacros.h"
366f9cba8fSJoseph Mingrone #include "diag-control.h"
3757e22627SCy Schubert
3857e22627SCy Schubert #include <errno.h> // for the errno variable
3957e22627SCy Schubert #include <string.h> // for strtok, etc
4057e22627SCy Schubert #include <stdlib.h> // for malloc(), free(), ...
416f9cba8fSJoseph Mingrone #include <stdio.h> // for fprintf(), stderr, FILE etc
4257e22627SCy Schubert #include <pcap.h> // for PCAP_ERRBUF_SIZE
4357e22627SCy Schubert #include <signal.h> // for signal()
4457e22627SCy Schubert
4557e22627SCy Schubert #include "fmtutils.h"
4657e22627SCy Schubert #include "sockutils.h" // for socket calls
4757e22627SCy Schubert #include "varattrs.h" // for _U_
4857e22627SCy Schubert #include "portability.h"
4957e22627SCy Schubert #include "rpcapd.h"
5057e22627SCy Schubert #include "config_params.h" // configuration file parameters
5157e22627SCy Schubert #include "fileconf.h" // for the configuration file management
5257e22627SCy Schubert #include "rpcap-protocol.h"
5357e22627SCy Schubert #include "daemon.h" // the true main() method of this daemon
5457e22627SCy Schubert #include "log.h"
5557e22627SCy Schubert
566f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
576f9cba8fSJoseph Mingrone #include "sslutils.h"
586f9cba8fSJoseph Mingrone #endif
596f9cba8fSJoseph Mingrone
6057e22627SCy Schubert #ifdef _WIN32
6157e22627SCy Schubert #include <process.h> // for thread stuff
6257e22627SCy Schubert #include "win32-svc.h" // for Win32 service stuff
6357e22627SCy Schubert #include "getopt.h" // for getopt()-for-Windows
6457e22627SCy Schubert #else
6557e22627SCy Schubert #include <fcntl.h> // for open()
6657e22627SCy Schubert #include <unistd.h> // for exit()
6757e22627SCy Schubert #include <sys/wait.h> // waitpid()
6857e22627SCy Schubert #endif
6957e22627SCy Schubert
7057e22627SCy Schubert //
7157e22627SCy Schubert // Element in list of sockets on which we're listening for connections.
7257e22627SCy Schubert //
7357e22627SCy Schubert struct listen_sock {
7457e22627SCy Schubert struct listen_sock *next;
75*afdbf109SJoseph Mingrone PCAP_SOCKET sock;
7657e22627SCy Schubert };
7757e22627SCy Schubert
7857e22627SCy Schubert // Global variables
7957e22627SCy Schubert char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
8057e22627SCy Schubert struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
8157e22627SCy Schubert int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
8257e22627SCy Schubert static struct listen_sock *listen_socks; //!< sockets on which we listen
8357e22627SCy Schubert char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration
8457e22627SCy Schubert static int passivemode = 1; //!< '1' if we want to run in passive mode as well
8557e22627SCy Schubert static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket
8657e22627SCy Schubert static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to
8757e22627SCy Schubert static char port[MAX_LINE + 1]; //!< keeps the network port to bind to
8857e22627SCy Schubert #ifdef _WIN32
8957e22627SCy Schubert static HANDLE state_change_event; //!< event to signal that a state change should take place
9057e22627SCy Schubert #endif
9157e22627SCy Schubert static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
9257e22627SCy Schubert static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
93*afdbf109SJoseph Mingrone static int uses_ssl; //!< '1' to use TLS over TCP
9457e22627SCy Schubert
9557e22627SCy Schubert extern char *optarg; // for getopt()
9657e22627SCy Schubert
9757e22627SCy Schubert // Function definition
9857e22627SCy Schubert #ifdef _WIN32
9957e22627SCy Schubert static unsigned __stdcall main_active(void *ptr);
10057e22627SCy Schubert static BOOL WINAPI main_ctrl_event(DWORD);
10157e22627SCy Schubert #else
10257e22627SCy Schubert static void *main_active(void *ptr);
10357e22627SCy Schubert static void main_terminate(int sign);
10457e22627SCy Schubert static void main_reread_config(int sign);
10557e22627SCy Schubert #endif
10657e22627SCy Schubert static void accept_connections(void);
107*afdbf109SJoseph Mingrone static void accept_connection(PCAP_SOCKET listen_sock);
10857e22627SCy Schubert #ifndef _WIN32
10957e22627SCy Schubert static void main_reap_children(int sign);
11057e22627SCy Schubert #endif
11157e22627SCy Schubert #ifdef _WIN32
11257e22627SCy Schubert static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
11357e22627SCy Schubert #endif
11457e22627SCy Schubert
11557e22627SCy Schubert #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
11657e22627SCy Schubert
11757e22627SCy Schubert /*!
11857e22627SCy Schubert \brief Prints the usage screen if it is launched in console mode.
11957e22627SCy Schubert */
printusage(FILE * f)1206f9cba8fSJoseph Mingrone static void printusage(FILE * f)
12157e22627SCy Schubert {
12257e22627SCy Schubert const char *usagetext =
12357e22627SCy Schubert "USAGE:"
12457e22627SCy Schubert " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
12557e22627SCy Schubert " [-n] [-v] [-d] "
12657e22627SCy Schubert #ifndef _WIN32
12757e22627SCy Schubert "[-i] "
12857e22627SCy Schubert #endif
12957e22627SCy Schubert "[-D] [-s <config_file>] [-f <config_file>]\n\n"
13057e22627SCy Schubert " -b <address> the address to bind to (either numeric or literal).\n"
13157e22627SCy Schubert " Default: binds to all local IPv4 and IPv6 addresses\n\n"
13257e22627SCy Schubert " -p <port> the port to bind to.\n"
13357e22627SCy Schubert " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
13457e22627SCy Schubert " -4 use only IPv4.\n"
13557e22627SCy Schubert " Default: use both IPv4 and IPv6 waiting sockets\n\n"
13657e22627SCy Schubert " -l <host_list> a file that contains a list of hosts that are allowed\n"
13757e22627SCy Schubert " to connect to this server (if more than one, list them one\n"
13857e22627SCy Schubert " per line).\n"
13957e22627SCy Schubert " We suggest to use literal names (instead of numeric ones)\n"
14057e22627SCy Schubert " in order to avoid problems with different address families.\n\n"
14157e22627SCy Schubert " -n permit NULL authentication (usually used with '-l')\n\n"
14257e22627SCy Schubert " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
14357e22627SCy Schubert " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
14457e22627SCy Schubert " -v run in active mode only (default: if '-a' is specified, it\n"
14557e22627SCy Schubert " accepts passive connections as well)\n\n"
14657e22627SCy Schubert " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
14757e22627SCy Schubert " Warning (Win32): this switch is provided automatically when\n"
14857e22627SCy Schubert " the service is started from the control panel\n\n"
14957e22627SCy Schubert #ifndef _WIN32
15057e22627SCy Schubert " -i run in inetd mode (UNIX only)\n\n"
15157e22627SCy Schubert #endif
15257e22627SCy Schubert " -D log debugging messages\n\n"
1536f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
1546f9cba8fSJoseph Mingrone " -S encrypt all communication with SSL (implements rpcaps://)\n"
1556f9cba8fSJoseph Mingrone " -C enable compression\n"
1566f9cba8fSJoseph Mingrone " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n"
1576f9cba8fSJoseph Mingrone " -X <pem_file> uses the certificate from this file (default: cert.pem)\n"
1586f9cba8fSJoseph Mingrone #endif
15957e22627SCy Schubert " -s <config_file> save the current configuration to file\n\n"
16057e22627SCy Schubert " -f <config_file> load the current configuration from file; all switches\n"
16157e22627SCy Schubert " specified from the command line are ignored\n\n"
16257e22627SCy Schubert " -h print this help screen\n\n";
16357e22627SCy Schubert
1646f9cba8fSJoseph Mingrone (void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
1656f9cba8fSJoseph Mingrone "Compiled with %s\n", pcap_lib_version());
1666f9cba8fSJoseph Mingrone #if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
1676f9cba8fSJoseph Mingrone (void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
1686f9cba8fSJoseph Mingrone #endif
1696f9cba8fSJoseph Mingrone (void)fprintf(f, "\n%s", usagetext);
17057e22627SCy Schubert }
17157e22627SCy Schubert
17257e22627SCy Schubert
17357e22627SCy Schubert
17457e22627SCy Schubert //! Program main
main(int argc,char * argv[])17557e22627SCy Schubert int main(int argc, char *argv[])
17657e22627SCy Schubert {
17757e22627SCy Schubert char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration
17857e22627SCy Schubert int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error
17957e22627SCy Schubert int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon
18057e22627SCy Schubert #ifndef _WIN32
18157e22627SCy Schubert int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like
18257e22627SCy Schubert #endif
18357e22627SCy Schubert int log_debug_messages = 0; // Non-zero if the user wants debug messages logged
18457e22627SCy Schubert int retval; // keeps the returning value from several functions
18557e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
18657e22627SCy Schubert #ifndef _WIN32
18757e22627SCy Schubert struct sigaction action;
18857e22627SCy Schubert #endif
1896f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
1906f9cba8fSJoseph Mingrone int enable_compression = 0;
1916f9cba8fSJoseph Mingrone #endif
19257e22627SCy Schubert
19357e22627SCy Schubert savefile[0] = 0;
19457e22627SCy Schubert loadfile[0] = 0;
19557e22627SCy Schubert hostlist[0] = 0;
19657e22627SCy Schubert
19757e22627SCy Schubert // Initialize errbuf
19857e22627SCy Schubert memset(errbuf, 0, sizeof(errbuf));
19957e22627SCy Schubert
200*afdbf109SJoseph Mingrone pcapint_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
201*afdbf109SJoseph Mingrone pcapint_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
20257e22627SCy Schubert
20357e22627SCy Schubert // Prepare to open a new server socket
20457e22627SCy Schubert memset(&mainhints, 0, sizeof(struct addrinfo));
20557e22627SCy Schubert
20657e22627SCy Schubert mainhints.ai_family = PF_UNSPEC;
20757e22627SCy Schubert mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
20857e22627SCy Schubert mainhints.ai_socktype = SOCK_STREAM;
20957e22627SCy Schubert
21057e22627SCy Schubert // Getting the proper command line options
2116f9cba8fSJoseph Mingrone # ifdef HAVE_OPENSSL
2126f9cba8fSJoseph Mingrone # define SSL_CLOPTS "SK:X:C"
2136f9cba8fSJoseph Mingrone # else
2146f9cba8fSJoseph Mingrone # define SSL_CLOPTS ""
2156f9cba8fSJoseph Mingrone # endif
2166f9cba8fSJoseph Mingrone
2176f9cba8fSJoseph Mingrone # define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
2186f9cba8fSJoseph Mingrone
2196f9cba8fSJoseph Mingrone while ((retval = getopt(argc, argv, CLOPTS)) != -1)
22057e22627SCy Schubert {
22157e22627SCy Schubert switch (retval)
22257e22627SCy Schubert {
22357e22627SCy Schubert case 'D':
22457e22627SCy Schubert log_debug_messages = 1;
22557e22627SCy Schubert rpcapd_log_set(log_to_systemlog, log_debug_messages);
22657e22627SCy Schubert break;
22757e22627SCy Schubert case 'b':
228*afdbf109SJoseph Mingrone pcapint_strlcpy(address, optarg, sizeof (address));
22957e22627SCy Schubert break;
23057e22627SCy Schubert case 'p':
231*afdbf109SJoseph Mingrone pcapint_strlcpy(port, optarg, sizeof (port));
23257e22627SCy Schubert break;
23357e22627SCy Schubert case '4':
23457e22627SCy Schubert mainhints.ai_family = PF_INET; // IPv4 server only
23557e22627SCy Schubert break;
23657e22627SCy Schubert case 'd':
23757e22627SCy Schubert isdaemon = 1;
23857e22627SCy Schubert log_to_systemlog = 1;
23957e22627SCy Schubert rpcapd_log_set(log_to_systemlog, log_debug_messages);
24057e22627SCy Schubert break;
24157e22627SCy Schubert case 'i':
24257e22627SCy Schubert #ifdef _WIN32
2436f9cba8fSJoseph Mingrone printusage(stderr);
24457e22627SCy Schubert exit(1);
24557e22627SCy Schubert #else
24657e22627SCy Schubert isrunbyinetd = 1;
24757e22627SCy Schubert log_to_systemlog = 1;
24857e22627SCy Schubert rpcapd_log_set(log_to_systemlog, log_debug_messages);
24957e22627SCy Schubert #endif
25057e22627SCy Schubert break;
25157e22627SCy Schubert case 'n':
25257e22627SCy Schubert nullAuthAllowed = 1;
25357e22627SCy Schubert break;
25457e22627SCy Schubert case 'v':
25557e22627SCy Schubert passivemode = 0;
25657e22627SCy Schubert break;
25757e22627SCy Schubert case 'l':
25857e22627SCy Schubert {
259*afdbf109SJoseph Mingrone pcapint_strlcpy(hostlist, optarg, sizeof(hostlist));
26057e22627SCy Schubert break;
26157e22627SCy Schubert }
26257e22627SCy Schubert case 'a':
26357e22627SCy Schubert {
26457e22627SCy Schubert char *tmpaddress, *tmpport;
26557e22627SCy Schubert char *lasts;
26657e22627SCy Schubert int i = 0;
26757e22627SCy Schubert
268*afdbf109SJoseph Mingrone tmpaddress = pcapint_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
26957e22627SCy Schubert
27057e22627SCy Schubert while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
27157e22627SCy Schubert {
272*afdbf109SJoseph Mingrone tmpport = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
27357e22627SCy Schubert
274*afdbf109SJoseph Mingrone pcapint_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
27557e22627SCy Schubert
27657e22627SCy Schubert if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
277*afdbf109SJoseph Mingrone pcapint_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
27857e22627SCy Schubert else
279*afdbf109SJoseph Mingrone pcapint_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
28057e22627SCy Schubert
281*afdbf109SJoseph Mingrone tmpaddress = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
28257e22627SCy Schubert
28357e22627SCy Schubert i++;
28457e22627SCy Schubert }
28557e22627SCy Schubert
28657e22627SCy Schubert if (i > MAX_ACTIVE_LIST)
28757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
28857e22627SCy Schubert
28957e22627SCy Schubert // I don't initialize the remaining part of the structure, since
29057e22627SCy Schubert // it is already zeroed (it is a global var)
29157e22627SCy Schubert break;
29257e22627SCy Schubert }
29357e22627SCy Schubert case 'f':
294*afdbf109SJoseph Mingrone pcapint_strlcpy(loadfile, optarg, sizeof (loadfile));
29557e22627SCy Schubert break;
29657e22627SCy Schubert case 's':
297*afdbf109SJoseph Mingrone pcapint_strlcpy(savefile, optarg, sizeof (savefile));
29857e22627SCy Schubert break;
2996f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL
3006f9cba8fSJoseph Mingrone case 'S':
3016f9cba8fSJoseph Mingrone uses_ssl = 1;
3026f9cba8fSJoseph Mingrone break;
3036f9cba8fSJoseph Mingrone case 'C':
3046f9cba8fSJoseph Mingrone enable_compression = 1;
3056f9cba8fSJoseph Mingrone break;
3066f9cba8fSJoseph Mingrone case 'K':
3076f9cba8fSJoseph Mingrone ssl_set_keyfile(optarg);
3086f9cba8fSJoseph Mingrone break;
3096f9cba8fSJoseph Mingrone case 'X':
3106f9cba8fSJoseph Mingrone ssl_set_certfile(optarg);
3116f9cba8fSJoseph Mingrone break;
3126f9cba8fSJoseph Mingrone #endif
31357e22627SCy Schubert case 'h':
3146f9cba8fSJoseph Mingrone printusage(stdout);
31557e22627SCy Schubert exit(0);
31657e22627SCy Schubert /*NOTREACHED*/
31757e22627SCy Schubert default:
31857e22627SCy Schubert exit(1);
31957e22627SCy Schubert /*NOTREACHED*/
32057e22627SCy Schubert }
32157e22627SCy Schubert }
32257e22627SCy Schubert
32357e22627SCy Schubert #ifndef _WIN32
32457e22627SCy Schubert if (isdaemon && isrunbyinetd)
32557e22627SCy Schubert {
32657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
32757e22627SCy Schubert exit(1);
32857e22627SCy Schubert }
32957e22627SCy Schubert #endif
33057e22627SCy Schubert
3316f9cba8fSJoseph Mingrone //
3326f9cba8fSJoseph Mingrone // We want UTF-8 error messages.
3336f9cba8fSJoseph Mingrone //
3346f9cba8fSJoseph Mingrone if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
3356f9cba8fSJoseph Mingrone {
3366f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
3376f9cba8fSJoseph Mingrone exit(-1);
3386f9cba8fSJoseph Mingrone }
339*afdbf109SJoseph Mingrone pcapint_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
3406f9cba8fSJoseph Mingrone
34157e22627SCy Schubert if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
34257e22627SCy Schubert {
34357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
34457e22627SCy Schubert exit(-1);
34557e22627SCy Schubert }
34657e22627SCy Schubert
34757e22627SCy Schubert if (savefile[0] && fileconf_save(savefile))
34857e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
34957e22627SCy Schubert
35057e22627SCy Schubert // If the file does not exist, it keeps the settings provided by the command line
35157e22627SCy Schubert if (loadfile[0])
35257e22627SCy Schubert fileconf_read();
35357e22627SCy Schubert
3546f9cba8fSJoseph Mingrone #ifdef _WIN32
35557e22627SCy Schubert //
35657e22627SCy Schubert // Create a handle to signal the main loop to tell it to do
35757e22627SCy Schubert // something.
35857e22627SCy Schubert //
35957e22627SCy Schubert state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
36057e22627SCy Schubert if (state_change_event == NULL)
36157e22627SCy Schubert {
3626f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
3636f9cba8fSJoseph Mingrone "Can't create state change event");
36457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
36557e22627SCy Schubert exit(2);
36657e22627SCy Schubert }
36757e22627SCy Schubert
36857e22627SCy Schubert //
36957e22627SCy Schubert // Catch control signals.
37057e22627SCy Schubert //
37157e22627SCy Schubert if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
37257e22627SCy Schubert {
3736f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
3746f9cba8fSJoseph Mingrone "Can't set control handler");
37557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
37657e22627SCy Schubert exit(2);
37757e22627SCy Schubert }
37857e22627SCy Schubert #else
37957e22627SCy Schubert memset(&action, 0, sizeof (action));
38057e22627SCy Schubert action.sa_handler = main_terminate;
38157e22627SCy Schubert action.sa_flags = 0;
38257e22627SCy Schubert sigemptyset(&action.sa_mask);
38357e22627SCy Schubert sigaction(SIGTERM, &action, NULL);
38457e22627SCy Schubert memset(&action, 0, sizeof (action));
38557e22627SCy Schubert action.sa_handler = main_reap_children;
38657e22627SCy Schubert action.sa_flags = 0;
38757e22627SCy Schubert sigemptyset(&action.sa_mask);
38857e22627SCy Schubert sigaction(SIGCHLD, &action, NULL);
38957e22627SCy Schubert // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
39057e22627SCy Schubert // connection, we don't want to get killed by a signal in that case
391*afdbf109SJoseph Mingrone #ifdef __illumos__
392*afdbf109SJoseph Mingrone DIAG_OFF_STRICT_PROTOTYPES
393*afdbf109SJoseph Mingrone #endif /* __illumos__ */
39457e22627SCy Schubert signal(SIGPIPE, SIG_IGN);
395*afdbf109SJoseph Mingrone #ifdef __illumos__
396*afdbf109SJoseph Mingrone DIAG_ON_STRICT_PROTOTYPES
397*afdbf109SJoseph Mingrone #endif /* __illumos__ */
39857e22627SCy Schubert #endif
39957e22627SCy Schubert
4006f9cba8fSJoseph Mingrone # ifdef HAVE_OPENSSL
4016f9cba8fSJoseph Mingrone if (uses_ssl) {
4026f9cba8fSJoseph Mingrone if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
4036f9cba8fSJoseph Mingrone {
4046f9cba8fSJoseph Mingrone rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
4056f9cba8fSJoseph Mingrone errbuf);
4066f9cba8fSJoseph Mingrone exit(2);
4076f9cba8fSJoseph Mingrone }
4086f9cba8fSJoseph Mingrone }
4096f9cba8fSJoseph Mingrone # endif
4106f9cba8fSJoseph Mingrone
41157e22627SCy Schubert #ifndef _WIN32
41257e22627SCy Schubert if (isrunbyinetd)
41357e22627SCy Schubert {
41457e22627SCy Schubert //
41557e22627SCy Schubert // -i was specified, indicating that this is being run
41657e22627SCy Schubert // by inetd or something that can run network daemons
41757e22627SCy Schubert // as if it were inetd (xinetd, launchd, systemd, etc.).
41857e22627SCy Schubert //
41957e22627SCy Schubert // We assume that the program that launched us just
42057e22627SCy Schubert // duplicated a single socket for the connection
42157e22627SCy Schubert // to our standard input, output, and error, so we
42257e22627SCy Schubert // can just use the standard input as our control
42357e22627SCy Schubert // socket.
42457e22627SCy Schubert //
42557e22627SCy Schubert int sockctrl;
42657e22627SCy Schubert int devnull_fd;
42757e22627SCy Schubert
42857e22627SCy Schubert //
42957e22627SCy Schubert // Duplicate the standard input as the control socket.
43057e22627SCy Schubert //
43157e22627SCy Schubert sockctrl = dup(0);
43257e22627SCy Schubert if (sockctrl == -1)
43357e22627SCy Schubert {
4346f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
4356f9cba8fSJoseph Mingrone "Can't dup standard input");
43657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
43757e22627SCy Schubert exit(2);
43857e22627SCy Schubert }
43957e22627SCy Schubert
44057e22627SCy Schubert //
44157e22627SCy Schubert // Try to set the standard input, output, and error
44257e22627SCy Schubert // to /dev/null.
44357e22627SCy Schubert //
44457e22627SCy Schubert devnull_fd = open("/dev/null", O_RDWR);
44557e22627SCy Schubert if (devnull_fd != -1)
44657e22627SCy Schubert {
44757e22627SCy Schubert //
44857e22627SCy Schubert // If this fails, just drive on.
44957e22627SCy Schubert //
45057e22627SCy Schubert (void)dup2(devnull_fd, 0);
45157e22627SCy Schubert (void)dup2(devnull_fd, 1);
45257e22627SCy Schubert (void)dup2(devnull_fd, 2);
45357e22627SCy Schubert close(devnull_fd);
45457e22627SCy Schubert }
45557e22627SCy Schubert
45657e22627SCy Schubert //
45757e22627SCy Schubert // Handle this client.
45857e22627SCy Schubert // This is passive mode, so we don't care whether we were
45957e22627SCy Schubert // told by the client to close.
46057e22627SCy Schubert //
46157e22627SCy Schubert char *hostlist_copy = strdup(hostlist);
46257e22627SCy Schubert if (hostlist_copy == NULL)
46357e22627SCy Schubert {
46457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
46557e22627SCy Schubert exit(0);
46657e22627SCy Schubert }
46757e22627SCy Schubert (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
4686f9cba8fSJoseph Mingrone nullAuthAllowed, uses_ssl);
46957e22627SCy Schubert
47057e22627SCy Schubert //
47157e22627SCy Schubert // Nothing more to do.
47257e22627SCy Schubert //
47357e22627SCy Schubert exit(0);
47457e22627SCy Schubert }
47557e22627SCy Schubert #endif
47657e22627SCy Schubert
47757e22627SCy Schubert if (isdaemon)
47857e22627SCy Schubert {
47957e22627SCy Schubert //
48057e22627SCy Schubert // This is being run as a daemon.
48157e22627SCy Schubert // On UN*X, it might be manually run, or run from an
48257e22627SCy Schubert // rc file.
48357e22627SCy Schubert //
48457e22627SCy Schubert #ifndef _WIN32
48557e22627SCy Schubert int pid;
48657e22627SCy Schubert
48757e22627SCy Schubert //
48857e22627SCy Schubert // Daemonize ourselves.
48957e22627SCy Schubert //
49057e22627SCy Schubert // Unix Network Programming, pg 336
49157e22627SCy Schubert //
49257e22627SCy Schubert if ((pid = fork()) != 0)
49357e22627SCy Schubert exit(0); // Parent terminates
49457e22627SCy Schubert
49557e22627SCy Schubert // First child continues
49657e22627SCy Schubert // Set daemon mode
49757e22627SCy Schubert setsid();
49857e22627SCy Schubert
49957e22627SCy Schubert // generated under unix with 'kill -HUP', needed to reload the configuration
50057e22627SCy Schubert memset(&action, 0, sizeof (action));
50157e22627SCy Schubert action.sa_handler = main_reread_config;
50257e22627SCy Schubert action.sa_flags = 0;
50357e22627SCy Schubert sigemptyset(&action.sa_mask);
50457e22627SCy Schubert sigaction(SIGHUP, &action, NULL);
50557e22627SCy Schubert
50657e22627SCy Schubert if ((pid = fork()) != 0)
50757e22627SCy Schubert exit(0); // First child terminates
50857e22627SCy Schubert
50957e22627SCy Schubert // LINUX WARNING: the current linux implementation of pthreads requires a management thread
51057e22627SCy Schubert // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
5116f9cba8fSJoseph Mingrone // created. From this point on, the number of threads active are always one more compared
51257e22627SCy Schubert // to the number you're expecting
51357e22627SCy Schubert
51457e22627SCy Schubert // Second child continues
51557e22627SCy Schubert // umask(0);
51657e22627SCy Schubert // chdir("/");
51757e22627SCy Schubert #else
51857e22627SCy Schubert //
51957e22627SCy Schubert // This is being run as a service on Windows.
52057e22627SCy Schubert //
52157e22627SCy Schubert // If this call succeeds, it is blocking on Win32
52257e22627SCy Schubert //
5236f9cba8fSJoseph Mingrone if (!svc_start())
52457e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
52557e22627SCy Schubert
52657e22627SCy Schubert // When the previous call returns, the entire application has to be stopped.
52757e22627SCy Schubert exit(0);
52857e22627SCy Schubert #endif
52957e22627SCy Schubert }
53057e22627SCy Schubert else // Console mode
53157e22627SCy Schubert {
53257e22627SCy Schubert #ifndef _WIN32
53357e22627SCy Schubert // Enable the catching of Ctrl+C
53457e22627SCy Schubert memset(&action, 0, sizeof (action));
53557e22627SCy Schubert action.sa_handler = main_terminate;
53657e22627SCy Schubert action.sa_flags = 0;
53757e22627SCy Schubert sigemptyset(&action.sa_mask);
53857e22627SCy Schubert sigaction(SIGINT, &action, NULL);
53957e22627SCy Schubert
54057e22627SCy Schubert // generated under unix with 'kill -HUP', needed to reload the configuration
54157e22627SCy Schubert // We do not have this kind of signal in Win32
54257e22627SCy Schubert memset(&action, 0, sizeof (action));
54357e22627SCy Schubert action.sa_handler = main_reread_config;
54457e22627SCy Schubert action.sa_flags = 0;
54557e22627SCy Schubert sigemptyset(&action.sa_mask);
54657e22627SCy Schubert sigaction(SIGHUP, &action, NULL);
54757e22627SCy Schubert #endif
54857e22627SCy Schubert
54957e22627SCy Schubert printf("Press CTRL + C to stop the server...\n");
55057e22627SCy Schubert }
55157e22627SCy Schubert
55257e22627SCy Schubert // If we're a Win32 service, we have already called this function in the service_main
55357e22627SCy Schubert main_startup();
55457e22627SCy Schubert
55557e22627SCy Schubert // The code should never arrive here (since the main_startup is blocking)
55657e22627SCy Schubert // however this avoids a compiler warning
55757e22627SCy Schubert exit(0);
55857e22627SCy Schubert }
55957e22627SCy Schubert
main_startup(void)56057e22627SCy Schubert void main_startup(void)
56157e22627SCy Schubert {
56257e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
56357e22627SCy Schubert struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
56457e22627SCy Schubert int i;
56557e22627SCy Schubert #ifdef _WIN32
56657e22627SCy Schubert HANDLE threadId; // handle for the subthread
56757e22627SCy Schubert #else
56857e22627SCy Schubert pid_t pid;
56957e22627SCy Schubert #endif
57057e22627SCy Schubert
57157e22627SCy Schubert i = 0;
57257e22627SCy Schubert addrinfo = NULL;
57357e22627SCy Schubert memset(errbuf, 0, sizeof(errbuf));
57457e22627SCy Schubert
57557e22627SCy Schubert // Starts all the active threads
57657e22627SCy Schubert while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
57757e22627SCy Schubert {
57857e22627SCy Schubert activelist[i].ai_family = mainhints.ai_family;
57957e22627SCy Schubert
58057e22627SCy Schubert #ifdef _WIN32
58157e22627SCy Schubert threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
58257e22627SCy Schubert (void *)&activelist[i], 0, NULL);
58357e22627SCy Schubert if (threadId == 0)
58457e22627SCy Schubert {
58557e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
58657e22627SCy Schubert continue;
58757e22627SCy Schubert }
58857e22627SCy Schubert CloseHandle(threadId);
58957e22627SCy Schubert #else
59057e22627SCy Schubert if ((pid = fork()) == 0) // I am the child
59157e22627SCy Schubert {
59257e22627SCy Schubert main_active((void *) &activelist[i]);
59357e22627SCy Schubert exit(0);
59457e22627SCy Schubert }
59557e22627SCy Schubert #endif
59657e22627SCy Schubert i++;
59757e22627SCy Schubert }
59857e22627SCy Schubert
59957e22627SCy Schubert /*
60057e22627SCy Schubert * The code that manages the active connections is not blocking;
60157e22627SCy Schubert * the code that manages the passive connection is blocking.
60257e22627SCy Schubert * So, if the user does not want to run in passive mode, we have
60357e22627SCy Schubert * to block the main thread here, otherwise the program ends and
60457e22627SCy Schubert * all threads are stopped.
60557e22627SCy Schubert *
60657e22627SCy Schubert * WARNING: this means that in case we have only active mode,
60757e22627SCy Schubert * the program does not terminate even if all the child thread
60857e22627SCy Schubert * terminates. The user has always to press Ctrl+C (or send a
60957e22627SCy Schubert * SIGTERM) to terminate the program.
61057e22627SCy Schubert */
61157e22627SCy Schubert if (passivemode)
61257e22627SCy Schubert {
61357e22627SCy Schubert struct addrinfo *tempaddrinfo;
61457e22627SCy Schubert
61557e22627SCy Schubert //
61657e22627SCy Schubert // Get a list of sockets on which to listen.
61757e22627SCy Schubert //
618*afdbf109SJoseph Mingrone addrinfo = sock_initaddress((address[0]) ? address : NULL,
619*afdbf109SJoseph Mingrone port, &mainhints, errbuf, PCAP_ERRBUF_SIZE);
620*afdbf109SJoseph Mingrone if (addrinfo == NULL)
62157e22627SCy Schubert {
62257e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
62357e22627SCy Schubert return;
62457e22627SCy Schubert }
62557e22627SCy Schubert
62657e22627SCy Schubert for (tempaddrinfo = addrinfo; tempaddrinfo;
62757e22627SCy Schubert tempaddrinfo = tempaddrinfo->ai_next)
62857e22627SCy Schubert {
629*afdbf109SJoseph Mingrone PCAP_SOCKET sock;
63057e22627SCy Schubert struct listen_sock *sock_info;
63157e22627SCy Schubert
6326f9cba8fSJoseph Mingrone if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
63357e22627SCy Schubert {
63457e22627SCy Schubert switch (tempaddrinfo->ai_family)
63557e22627SCy Schubert {
63657e22627SCy Schubert case AF_INET:
63757e22627SCy Schubert {
63857e22627SCy Schubert struct sockaddr_in *in;
63957e22627SCy Schubert char addrbuf[INET_ADDRSTRLEN];
64057e22627SCy Schubert
64157e22627SCy Schubert in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
64257e22627SCy Schubert rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
64357e22627SCy Schubert inet_ntop(AF_INET, &in->sin_addr,
64457e22627SCy Schubert addrbuf, sizeof (addrbuf)),
64557e22627SCy Schubert ntohs(in->sin_port),
64657e22627SCy Schubert errbuf);
64757e22627SCy Schubert break;
64857e22627SCy Schubert }
64957e22627SCy Schubert
65057e22627SCy Schubert case AF_INET6:
65157e22627SCy Schubert {
65257e22627SCy Schubert struct sockaddr_in6 *in6;
65357e22627SCy Schubert char addrbuf[INET6_ADDRSTRLEN];
65457e22627SCy Schubert
65557e22627SCy Schubert in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
65657e22627SCy Schubert rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
65757e22627SCy Schubert inet_ntop(AF_INET6, &in6->sin6_addr,
65857e22627SCy Schubert addrbuf, sizeof (addrbuf)),
65957e22627SCy Schubert ntohs(in6->sin6_port),
66057e22627SCy Schubert errbuf);
66157e22627SCy Schubert break;
66257e22627SCy Schubert }
66357e22627SCy Schubert
66457e22627SCy Schubert default:
66557e22627SCy Schubert rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
66657e22627SCy Schubert tempaddrinfo->ai_family,
66757e22627SCy Schubert errbuf);
66857e22627SCy Schubert break;
66957e22627SCy Schubert }
67057e22627SCy Schubert continue;
67157e22627SCy Schubert }
67257e22627SCy Schubert
67357e22627SCy Schubert sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
67457e22627SCy Schubert if (sock_info == NULL)
67557e22627SCy Schubert {
67657e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
67757e22627SCy Schubert exit(2);
67857e22627SCy Schubert }
67957e22627SCy Schubert sock_info->sock = sock;
68057e22627SCy Schubert sock_info->next = listen_socks;
68157e22627SCy Schubert listen_socks = sock_info;
68257e22627SCy Schubert }
68357e22627SCy Schubert
68457e22627SCy Schubert freeaddrinfo(addrinfo);
68557e22627SCy Schubert
68657e22627SCy Schubert if (listen_socks == NULL)
68757e22627SCy Schubert {
68857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
68957e22627SCy Schubert exit(2);
69057e22627SCy Schubert }
69157e22627SCy Schubert
69257e22627SCy Schubert //
69357e22627SCy Schubert // Now listen on all of them, waiting for connections.
69457e22627SCy Schubert //
69557e22627SCy Schubert accept_connections();
69657e22627SCy Schubert }
69757e22627SCy Schubert
69857e22627SCy Schubert //
69957e22627SCy Schubert // We're done; exit.
70057e22627SCy Schubert //
70157e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
70257e22627SCy Schubert
70357e22627SCy Schubert #ifndef _WIN32
70457e22627SCy Schubert //
70557e22627SCy Schubert // Sends a KILL signal to all the processes in this process's
70657e22627SCy Schubert // process group; i.e., it kills all the child processes
70757e22627SCy Schubert // we've created.
70857e22627SCy Schubert //
70957e22627SCy Schubert // XXX - that also includes us, so we will be killed as well;
71057e22627SCy Schubert // that may cause a message to be printed or logged.
71157e22627SCy Schubert //
71257e22627SCy Schubert kill(0, SIGKILL);
71357e22627SCy Schubert #endif
71457e22627SCy Schubert
71557e22627SCy Schubert //
71657e22627SCy Schubert // Just leave. We shouldn't need to clean up sockets or
71757e22627SCy Schubert // anything else, and if we try to do so, we'll could end
71857e22627SCy Schubert // up closing sockets, or shutting Winsock down, out from
71957e22627SCy Schubert // under service loops, causing all sorts of noisy error
72057e22627SCy Schubert // messages.
72157e22627SCy Schubert //
72257e22627SCy Schubert // We shouldn't need to worry about cleaning up any resources
72357e22627SCy Schubert // such as handles, sockets, threads, etc. - exit() should
72457e22627SCy Schubert // terminate the process, causing all those resources to be
72557e22627SCy Schubert // cleaned up (including the threads; Microsoft claims in the
72657e22627SCy Schubert // ExitProcess() documentation that, if ExitProcess() is called,
72757e22627SCy Schubert // "If a thread is waiting on a kernel object, it will not be
72857e22627SCy Schubert // terminated until the wait has completed.", but claims in the
72957e22627SCy Schubert // _beginthread()/_beginthreadex() documentation that "All threads
73057e22627SCy Schubert // are terminated if any thread calls abort, exit, _exit, or
73157e22627SCy Schubert // ExitProcess." - the latter appears to be the case, even for
73257e22627SCy Schubert // threads waiting on the event for a pcap_t).
73357e22627SCy Schubert //
73457e22627SCy Schubert exit(0);
73557e22627SCy Schubert }
73657e22627SCy Schubert
73757e22627SCy Schubert #ifdef _WIN32
73857e22627SCy Schubert static void
send_state_change_event(void)73957e22627SCy Schubert send_state_change_event(void)
74057e22627SCy Schubert {
74157e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
74257e22627SCy Schubert
74357e22627SCy Schubert if (!SetEvent(state_change_event))
74457e22627SCy Schubert {
7456f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
7466f9cba8fSJoseph Mingrone "SetEvent on shutdown event failed");
74757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
74857e22627SCy Schubert }
74957e22627SCy Schubert }
75057e22627SCy Schubert
75157e22627SCy Schubert void
send_shutdown_notification(void)75257e22627SCy Schubert send_shutdown_notification(void)
75357e22627SCy Schubert {
75457e22627SCy Schubert //
75557e22627SCy Schubert // Indicate that the server should shut down.
75657e22627SCy Schubert //
75757e22627SCy Schubert shutdown_server = 1;
75857e22627SCy Schubert
75957e22627SCy Schubert //
76057e22627SCy Schubert // Send a state change event, to wake up WSAWaitForMultipleEvents().
76157e22627SCy Schubert //
76257e22627SCy Schubert send_state_change_event();
76357e22627SCy Schubert }
76457e22627SCy Schubert
76557e22627SCy Schubert void
send_reread_configuration_notification(void)76657e22627SCy Schubert send_reread_configuration_notification(void)
76757e22627SCy Schubert {
76857e22627SCy Schubert //
76957e22627SCy Schubert // Indicate that the server should re-read its configuration file.
77057e22627SCy Schubert //
77157e22627SCy Schubert reread_config = 1;
77257e22627SCy Schubert
77357e22627SCy Schubert //
77457e22627SCy Schubert // Send a state change event, to wake up WSAWaitForMultipleEvents().
77557e22627SCy Schubert //
77657e22627SCy Schubert send_state_change_event();
77757e22627SCy Schubert }
77857e22627SCy Schubert
main_ctrl_event(DWORD ctrltype)77957e22627SCy Schubert static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
78057e22627SCy Schubert {
78157e22627SCy Schubert //
78257e22627SCy Schubert // ctrltype is one of:
78357e22627SCy Schubert //
78457e22627SCy Schubert // CTRL_C_EVENT - we got a ^C; this is like SIGINT
78557e22627SCy Schubert // CTRL_BREAK_EVENT - we got Ctrl+Break
78657e22627SCy Schubert // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
78757e22627SCy Schubert // CTRL_LOGOFF_EVENT - a user is logging off; this is received
78857e22627SCy Schubert // only by services
78957e22627SCy Schubert // CTRL_SHUTDOWN_EVENT - the system is shutting down; this is
79057e22627SCy Schubert // received only by services
79157e22627SCy Schubert //
79257e22627SCy Schubert // For now, we treat all but CTRL_LOGOFF_EVENT as indications
79357e22627SCy Schubert // that we should shut down.
79457e22627SCy Schubert //
79557e22627SCy Schubert switch (ctrltype)
79657e22627SCy Schubert {
79757e22627SCy Schubert case CTRL_C_EVENT:
79857e22627SCy Schubert case CTRL_BREAK_EVENT:
79957e22627SCy Schubert case CTRL_CLOSE_EVENT:
80057e22627SCy Schubert case CTRL_SHUTDOWN_EVENT:
80157e22627SCy Schubert //
80257e22627SCy Schubert // Set a shutdown notification.
80357e22627SCy Schubert //
80457e22627SCy Schubert send_shutdown_notification();
80557e22627SCy Schubert break;
80657e22627SCy Schubert
80757e22627SCy Schubert default:
80857e22627SCy Schubert break;
80957e22627SCy Schubert }
81057e22627SCy Schubert
81157e22627SCy Schubert //
81257e22627SCy Schubert // We handled this.
81357e22627SCy Schubert //
81457e22627SCy Schubert return TRUE;
81557e22627SCy Schubert }
81657e22627SCy Schubert #else
main_terminate(int sign _U_)81757e22627SCy Schubert static void main_terminate(int sign _U_)
81857e22627SCy Schubert {
81957e22627SCy Schubert //
82057e22627SCy Schubert // Note that the server should shut down.
82157e22627SCy Schubert // select() should get an EINTR error when we return,
82257e22627SCy Schubert // so it will wake up and know it needs to check the flag.
82357e22627SCy Schubert //
82457e22627SCy Schubert shutdown_server = 1;
82557e22627SCy Schubert }
82657e22627SCy Schubert
main_reread_config(int sign _U_)82757e22627SCy Schubert static void main_reread_config(int sign _U_)
82857e22627SCy Schubert {
82957e22627SCy Schubert //
83057e22627SCy Schubert // Note that the server should re-read its configuration file.
83157e22627SCy Schubert // select() should get an EINTR error when we return,
83257e22627SCy Schubert // so it will wake up and know it needs to check the flag.
83357e22627SCy Schubert //
83457e22627SCy Schubert reread_config = 1;
83557e22627SCy Schubert }
83657e22627SCy Schubert
main_reap_children(int sign _U_)83757e22627SCy Schubert static void main_reap_children(int sign _U_)
83857e22627SCy Schubert {
83957e22627SCy Schubert pid_t pid;
84057e22627SCy Schubert int exitstat;
84157e22627SCy Schubert
84257e22627SCy Schubert // Reap all child processes that have exited.
84357e22627SCy Schubert // For reference, Stevens, pg 128
84457e22627SCy Schubert
84557e22627SCy Schubert while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
84657e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
84757e22627SCy Schubert
84857e22627SCy Schubert return;
84957e22627SCy Schubert }
85057e22627SCy Schubert #endif
85157e22627SCy Schubert
85257e22627SCy Schubert //
85357e22627SCy Schubert // Loop waiting for incoming connections and accepting them.
85457e22627SCy Schubert //
85557e22627SCy Schubert static void
accept_connections(void)85657e22627SCy Schubert accept_connections(void)
85757e22627SCy Schubert {
85857e22627SCy Schubert #ifdef _WIN32
85957e22627SCy Schubert struct listen_sock *sock_info;
86057e22627SCy Schubert DWORD num_events;
86157e22627SCy Schubert WSAEVENT *events;
86257e22627SCy Schubert int i;
86357e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
86457e22627SCy Schubert
86557e22627SCy Schubert //
86657e22627SCy Schubert // How big does the set of events need to be?
86757e22627SCy Schubert // One for the shutdown event, plus one for every socket on which
86857e22627SCy Schubert // we'll be listening.
86957e22627SCy Schubert //
87057e22627SCy Schubert num_events = 1; // shutdown event
87157e22627SCy Schubert for (sock_info = listen_socks; sock_info;
87257e22627SCy Schubert sock_info = sock_info->next)
87357e22627SCy Schubert {
87457e22627SCy Schubert if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
87557e22627SCy Schubert {
87657e22627SCy Schubert //
87757e22627SCy Schubert // WSAWaitForMultipleEvents() doesn't support
87857e22627SCy Schubert // more than WSA_MAXIMUM_WAIT_EVENTS events
87957e22627SCy Schubert // on which to wait.
88057e22627SCy Schubert //
88157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
88257e22627SCy Schubert exit(2);
88357e22627SCy Schubert }
88457e22627SCy Schubert num_events++;
88557e22627SCy Schubert }
88657e22627SCy Schubert
88757e22627SCy Schubert //
88857e22627SCy Schubert // Allocate the array of events.
88957e22627SCy Schubert //
89057e22627SCy Schubert events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
89157e22627SCy Schubert if (events == NULL)
89257e22627SCy Schubert {
89357e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
89457e22627SCy Schubert exit(2);
89557e22627SCy Schubert }
89657e22627SCy Schubert
89757e22627SCy Schubert //
89857e22627SCy Schubert // Fill it in.
89957e22627SCy Schubert //
90057e22627SCy Schubert events[0] = state_change_event; // state change event first
90157e22627SCy Schubert for (sock_info = listen_socks, i = 1; sock_info;
90257e22627SCy Schubert sock_info = sock_info->next, i++)
90357e22627SCy Schubert {
90457e22627SCy Schubert WSAEVENT event;
90557e22627SCy Schubert
90657e22627SCy Schubert //
90757e22627SCy Schubert // Create an event that is signaled if there's a connection
90857e22627SCy Schubert // to accept on the socket in question.
90957e22627SCy Schubert //
91057e22627SCy Schubert event = WSACreateEvent();
91157e22627SCy Schubert if (event == WSA_INVALID_EVENT)
91257e22627SCy Schubert {
9136f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9146f9cba8fSJoseph Mingrone "Can't create socket event");
91557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
91657e22627SCy Schubert exit(2);
91757e22627SCy Schubert }
91857e22627SCy Schubert if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
91957e22627SCy Schubert {
9206f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9216f9cba8fSJoseph Mingrone "Can't setup socket event");
92257e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
92357e22627SCy Schubert exit(2);
92457e22627SCy Schubert }
92557e22627SCy Schubert events[i] = event;
92657e22627SCy Schubert }
92757e22627SCy Schubert
92857e22627SCy Schubert for (;;)
92957e22627SCy Schubert {
93057e22627SCy Schubert //
93157e22627SCy Schubert // Wait for incoming connections.
93257e22627SCy Schubert //
93357e22627SCy Schubert DWORD ret;
93457e22627SCy Schubert
93557e22627SCy Schubert ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
93657e22627SCy Schubert WSA_INFINITE, FALSE);
93757e22627SCy Schubert if (ret == WSA_WAIT_FAILED)
93857e22627SCy Schubert {
9396f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9406f9cba8fSJoseph Mingrone "WSAWaitForMultipleEvents failed");
94157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
94257e22627SCy Schubert exit(2);
94357e22627SCy Schubert }
94457e22627SCy Schubert
94557e22627SCy Schubert if (ret == WSA_WAIT_EVENT_0)
94657e22627SCy Schubert {
94757e22627SCy Schubert //
94857e22627SCy Schubert // The state change event was set.
94957e22627SCy Schubert //
95057e22627SCy Schubert if (shutdown_server)
95157e22627SCy Schubert {
95257e22627SCy Schubert //
95357e22627SCy Schubert // Time to quit. Exit the loop.
95457e22627SCy Schubert //
95557e22627SCy Schubert break;
95657e22627SCy Schubert }
95757e22627SCy Schubert if (reread_config)
95857e22627SCy Schubert {
95957e22627SCy Schubert //
96057e22627SCy Schubert // We should re-read the configuration
96157e22627SCy Schubert // file.
96257e22627SCy Schubert //
96357e22627SCy Schubert reread_config = 0; // clear the indicator
96457e22627SCy Schubert fileconf_read();
96557e22627SCy Schubert }
96657e22627SCy Schubert }
96757e22627SCy Schubert
96857e22627SCy Schubert //
96957e22627SCy Schubert // Check each socket.
97057e22627SCy Schubert //
97157e22627SCy Schubert for (sock_info = listen_socks, i = 1; sock_info;
97257e22627SCy Schubert sock_info = sock_info->next, i++)
97357e22627SCy Schubert {
97457e22627SCy Schubert WSANETWORKEVENTS network_events;
97557e22627SCy Schubert
97657e22627SCy Schubert if (WSAEnumNetworkEvents(sock_info->sock,
97757e22627SCy Schubert events[i], &network_events) == SOCKET_ERROR)
97857e22627SCy Schubert {
9796f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
9806f9cba8fSJoseph Mingrone "WSAEnumNetworkEvents failed");
98157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
98257e22627SCy Schubert exit(2);
98357e22627SCy Schubert }
98457e22627SCy Schubert if (network_events.lNetworkEvents & FD_ACCEPT)
98557e22627SCy Schubert {
98657e22627SCy Schubert //
98757e22627SCy Schubert // Did an error occur?
98857e22627SCy Schubert //
98957e22627SCy Schubert if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
99057e22627SCy Schubert {
99157e22627SCy Schubert //
99257e22627SCy Schubert // Yes - report it and keep going.
99357e22627SCy Schubert //
9946f9cba8fSJoseph Mingrone sock_fmterrmsg(errbuf,
9956f9cba8fSJoseph Mingrone PCAP_ERRBUF_SIZE,
99657e22627SCy Schubert network_events.iErrorCode[FD_ACCEPT_BIT],
9976f9cba8fSJoseph Mingrone "Socket error");
99857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
99957e22627SCy Schubert continue;
100057e22627SCy Schubert }
100157e22627SCy Schubert
100257e22627SCy Schubert //
100357e22627SCy Schubert // Accept the connection.
100457e22627SCy Schubert //
100557e22627SCy Schubert accept_connection(sock_info->sock);
100657e22627SCy Schubert }
100757e22627SCy Schubert }
100857e22627SCy Schubert }
100957e22627SCy Schubert #else
101057e22627SCy Schubert struct listen_sock *sock_info;
101157e22627SCy Schubert int num_sock_fds;
101257e22627SCy Schubert
101357e22627SCy Schubert //
101457e22627SCy Schubert // How big does the bitset of sockets on which to select() have
101557e22627SCy Schubert // to be?
101657e22627SCy Schubert //
101757e22627SCy Schubert num_sock_fds = 0;
101857e22627SCy Schubert for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
101957e22627SCy Schubert {
102057e22627SCy Schubert if (sock_info->sock + 1 > num_sock_fds)
102157e22627SCy Schubert {
102257e22627SCy Schubert if ((unsigned int)(sock_info->sock + 1) >
102357e22627SCy Schubert (unsigned int)FD_SETSIZE)
102457e22627SCy Schubert {
102557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
102657e22627SCy Schubert exit(2);
102757e22627SCy Schubert }
102857e22627SCy Schubert num_sock_fds = sock_info->sock + 1;
102957e22627SCy Schubert }
103057e22627SCy Schubert }
103157e22627SCy Schubert
103257e22627SCy Schubert for (;;)
103357e22627SCy Schubert {
103457e22627SCy Schubert fd_set sock_fds;
103557e22627SCy Schubert int ret;
103657e22627SCy Schubert
103757e22627SCy Schubert //
103857e22627SCy Schubert // Set up an fd_set for all the sockets on which we're
103957e22627SCy Schubert // listening.
104057e22627SCy Schubert //
104157e22627SCy Schubert // This set is modified by select(), so we have to
104257e22627SCy Schubert // construct it anew each time.
104357e22627SCy Schubert //
104457e22627SCy Schubert FD_ZERO(&sock_fds);
104557e22627SCy Schubert for (sock_info = listen_socks; sock_info;
104657e22627SCy Schubert sock_info = sock_info->next)
104757e22627SCy Schubert {
104857e22627SCy Schubert FD_SET(sock_info->sock, &sock_fds);
104957e22627SCy Schubert }
105057e22627SCy Schubert
105157e22627SCy Schubert //
105257e22627SCy Schubert // Wait for incoming connections.
105357e22627SCy Schubert //
105457e22627SCy Schubert ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
105557e22627SCy Schubert if (ret == -1)
105657e22627SCy Schubert {
105757e22627SCy Schubert if (errno == EINTR)
105857e22627SCy Schubert {
105957e22627SCy Schubert //
106057e22627SCy Schubert // If this is a "terminate the
106157e22627SCy Schubert // server" signal, exit the loop,
106257e22627SCy Schubert // otherwise just keep trying.
106357e22627SCy Schubert //
106457e22627SCy Schubert if (shutdown_server)
106557e22627SCy Schubert {
106657e22627SCy Schubert //
106757e22627SCy Schubert // Time to quit. Exit the loop.
106857e22627SCy Schubert //
106957e22627SCy Schubert break;
107057e22627SCy Schubert }
107157e22627SCy Schubert if (reread_config)
107257e22627SCy Schubert {
107357e22627SCy Schubert //
107457e22627SCy Schubert // We should re-read the configuration
107557e22627SCy Schubert // file.
107657e22627SCy Schubert //
107757e22627SCy Schubert reread_config = 0; // clear the indicator
107857e22627SCy Schubert fileconf_read();
107957e22627SCy Schubert }
108057e22627SCy Schubert
108157e22627SCy Schubert //
108257e22627SCy Schubert // Go back and wait again.
108357e22627SCy Schubert //
108457e22627SCy Schubert continue;
108557e22627SCy Schubert }
108657e22627SCy Schubert else
108757e22627SCy Schubert {
108857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
108957e22627SCy Schubert strerror(errno));
109057e22627SCy Schubert exit(2);
109157e22627SCy Schubert }
109257e22627SCy Schubert }
109357e22627SCy Schubert
109457e22627SCy Schubert //
109557e22627SCy Schubert // Check each socket.
109657e22627SCy Schubert //
109757e22627SCy Schubert for (sock_info = listen_socks; sock_info;
109857e22627SCy Schubert sock_info = sock_info->next)
109957e22627SCy Schubert {
110057e22627SCy Schubert if (FD_ISSET(sock_info->sock, &sock_fds))
110157e22627SCy Schubert {
110257e22627SCy Schubert //
110357e22627SCy Schubert // Accept the connection.
110457e22627SCy Schubert //
110557e22627SCy Schubert accept_connection(sock_info->sock);
110657e22627SCy Schubert }
110757e22627SCy Schubert }
110857e22627SCy Schubert }
110957e22627SCy Schubert #endif
111057e22627SCy Schubert
111157e22627SCy Schubert //
111257e22627SCy Schubert // Close all the listen sockets.
111357e22627SCy Schubert //
111457e22627SCy Schubert for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
111557e22627SCy Schubert {
111657e22627SCy Schubert closesocket(sock_info->sock);
111757e22627SCy Schubert }
111857e22627SCy Schubert sock_cleanup();
111957e22627SCy Schubert }
112057e22627SCy Schubert
112157e22627SCy Schubert #ifdef _WIN32
112257e22627SCy Schubert //
112357e22627SCy Schubert // A structure to hold the parameters to the daemon service loop
112457e22627SCy Schubert // thread on Windows.
112557e22627SCy Schubert //
112657e22627SCy Schubert // (On UN*X, there is no need for this explicit copy since the
112757e22627SCy Schubert // fork "inherits" the parent stack.)
112857e22627SCy Schubert //
112957e22627SCy Schubert struct params_copy {
1130*afdbf109SJoseph Mingrone PCAP_SOCKET sockctrl;
113157e22627SCy Schubert char *hostlist;
113257e22627SCy Schubert };
113357e22627SCy Schubert #endif
113457e22627SCy Schubert
113557e22627SCy Schubert //
113657e22627SCy Schubert // Accept a connection and start a worker thread, on Windows, or a
113757e22627SCy Schubert // worker process, on UN*X, to handle the connection.
113857e22627SCy Schubert //
113957e22627SCy Schubert static void
accept_connection(PCAP_SOCKET listen_sock)1140*afdbf109SJoseph Mingrone accept_connection(PCAP_SOCKET listen_sock)
114157e22627SCy Schubert {
114257e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1143*afdbf109SJoseph Mingrone PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
114457e22627SCy Schubert struct sockaddr_storage from; // generic sockaddr_storage variable
114557e22627SCy Schubert socklen_t fromlen; // keeps the length of the sockaddr_storage variable
114657e22627SCy Schubert
114757e22627SCy Schubert #ifdef _WIN32
114857e22627SCy Schubert HANDLE threadId; // handle for the subthread
114957e22627SCy Schubert u_long off = 0;
115057e22627SCy Schubert struct params_copy *params_copy = NULL;
115157e22627SCy Schubert #else
115257e22627SCy Schubert pid_t pid;
115357e22627SCy Schubert #endif
115457e22627SCy Schubert
115557e22627SCy Schubert // Initialize errbuf
115657e22627SCy Schubert memset(errbuf, 0, sizeof(errbuf));
115757e22627SCy Schubert
115857e22627SCy Schubert for (;;)
115957e22627SCy Schubert {
116057e22627SCy Schubert // Accept the connection
116157e22627SCy Schubert fromlen = sizeof(struct sockaddr_storage);
116257e22627SCy Schubert
116357e22627SCy Schubert sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
116457e22627SCy Schubert
116557e22627SCy Schubert if (sockctrl != INVALID_SOCKET)
116657e22627SCy Schubert {
116757e22627SCy Schubert // Success.
116857e22627SCy Schubert break;
116957e22627SCy Schubert }
117057e22627SCy Schubert
11716f9cba8fSJoseph Mingrone // The accept() call can return this error when a signal is caught
117257e22627SCy Schubert // In this case, we have simply to ignore this error code
117357e22627SCy Schubert // Stevens, pg 124
117457e22627SCy Schubert #ifdef _WIN32
117557e22627SCy Schubert if (WSAGetLastError() == WSAEINTR)
117657e22627SCy Schubert #else
117757e22627SCy Schubert if (errno == EINTR)
117857e22627SCy Schubert #endif
117957e22627SCy Schubert continue;
118057e22627SCy Schubert
118157e22627SCy Schubert // Don't check for errors here, since the error can be due to the fact that the thread
118257e22627SCy Schubert // has been killed
11836f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed");
118457e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
118557e22627SCy Schubert errbuf);
118657e22627SCy Schubert return;
118757e22627SCy Schubert }
118857e22627SCy Schubert
118957e22627SCy Schubert #ifdef _WIN32
119057e22627SCy Schubert //
119157e22627SCy Schubert // Put the socket back into blocking mode; doing WSAEventSelect()
119257e22627SCy Schubert // on the listen socket makes that socket non-blocking, and it
119357e22627SCy Schubert // appears that sockets returned from an accept() on that socket
119457e22627SCy Schubert // are also non-blocking.
119557e22627SCy Schubert //
119657e22627SCy Schubert // First, we have to un-WSAEventSelect() this socket, and then
119757e22627SCy Schubert // we can turn non-blocking mode off.
119857e22627SCy Schubert //
119957e22627SCy Schubert // If this fails, we aren't guaranteed that, for example, any
120057e22627SCy Schubert // of the error message will be sent - if it can't be put in
120157e22627SCy Schubert // the socket queue, the send will just fail.
120257e22627SCy Schubert //
120357e22627SCy Schubert // So we just log the message and close the connection.
120457e22627SCy Schubert //
120557e22627SCy Schubert if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
120657e22627SCy Schubert {
12076f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
12086f9cba8fSJoseph Mingrone "WSAEventSelect() failed");
120957e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
121057e22627SCy Schubert sock_close(sockctrl, NULL, 0);
121157e22627SCy Schubert return;
121257e22627SCy Schubert }
121357e22627SCy Schubert if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
121457e22627SCy Schubert {
12156f9cba8fSJoseph Mingrone sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
12166f9cba8fSJoseph Mingrone "ioctlsocket(FIONBIO) failed");
121757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
121857e22627SCy Schubert sock_close(sockctrl, NULL, 0);
121957e22627SCy Schubert return;
122057e22627SCy Schubert }
122157e22627SCy Schubert
122257e22627SCy Schubert //
122357e22627SCy Schubert // Make a copy of the host list to pass to the new thread, so that
122457e22627SCy Schubert // if we update it in the main thread, it won't catch us in the
122557e22627SCy Schubert // middle of updating it.
122657e22627SCy Schubert //
122757e22627SCy Schubert // daemon_serviceloop() will free it once it's done with it.
122857e22627SCy Schubert //
122957e22627SCy Schubert char *hostlist_copy = strdup(hostlist);
123057e22627SCy Schubert if (hostlist_copy == NULL)
123157e22627SCy Schubert {
123257e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
123357e22627SCy Schubert sock_close(sockctrl, NULL, 0);
123457e22627SCy Schubert return;
123557e22627SCy Schubert }
123657e22627SCy Schubert
123757e22627SCy Schubert //
123857e22627SCy Schubert // Allocate a location to hold the values of sockctrl.
123957e22627SCy Schubert // It will be freed in the newly-created thread once it's
124057e22627SCy Schubert // finished with it.
124157e22627SCy Schubert //
124257e22627SCy Schubert params_copy = malloc(sizeof(*params_copy));
124357e22627SCy Schubert if (params_copy == NULL)
124457e22627SCy Schubert {
124557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
124657e22627SCy Schubert free(hostlist_copy);
124757e22627SCy Schubert sock_close(sockctrl, NULL, 0);
124857e22627SCy Schubert return;
124957e22627SCy Schubert }
125057e22627SCy Schubert params_copy->sockctrl = sockctrl;
125157e22627SCy Schubert params_copy->hostlist = hostlist_copy;
125257e22627SCy Schubert
125357e22627SCy Schubert threadId = (HANDLE)_beginthreadex(NULL, 0,
125457e22627SCy Schubert main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
125557e22627SCy Schubert if (threadId == 0)
125657e22627SCy Schubert {
125757e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
125857e22627SCy Schubert free(params_copy);
125957e22627SCy Schubert free(hostlist_copy);
126057e22627SCy Schubert sock_close(sockctrl, NULL, 0);
126157e22627SCy Schubert return;
126257e22627SCy Schubert }
126357e22627SCy Schubert CloseHandle(threadId);
126457e22627SCy Schubert #else /* _WIN32 */
126557e22627SCy Schubert pid = fork();
126657e22627SCy Schubert if (pid == -1)
126757e22627SCy Schubert {
126857e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
126957e22627SCy Schubert strerror(errno));
127057e22627SCy Schubert sock_close(sockctrl, NULL, 0);
127157e22627SCy Schubert return;
127257e22627SCy Schubert }
127357e22627SCy Schubert if (pid == 0)
127457e22627SCy Schubert {
127557e22627SCy Schubert //
127657e22627SCy Schubert // Child process.
127757e22627SCy Schubert //
127857e22627SCy Schubert // Close the socket on which we're listening (must
127957e22627SCy Schubert // be open only in the parent).
128057e22627SCy Schubert //
128157e22627SCy Schubert closesocket(listen_sock);
128257e22627SCy Schubert
128357e22627SCy Schubert #if 0
128457e22627SCy Schubert //
128557e22627SCy Schubert // Modify thread params so that it can be killed at any time
128657e22627SCy Schubert // XXX - is this necessary? This is the main and, currently,
128757e22627SCy Schubert // only thread in the child process, and nobody tries to
128857e22627SCy Schubert // cancel us, although *we* may cancel the thread that's
128957e22627SCy Schubert // handling the capture loop.
129057e22627SCy Schubert //
129157e22627SCy Schubert if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
129257e22627SCy Schubert goto end;
129357e22627SCy Schubert if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
129457e22627SCy Schubert goto end;
129557e22627SCy Schubert #endif
129657e22627SCy Schubert
129757e22627SCy Schubert //
129857e22627SCy Schubert // Run the service loop.
129957e22627SCy Schubert // This is passive mode, so we don't care whether we were
130057e22627SCy Schubert // told by the client to close.
130157e22627SCy Schubert //
130257e22627SCy Schubert char *hostlist_copy = strdup(hostlist);
130357e22627SCy Schubert if (hostlist_copy == NULL)
130457e22627SCy Schubert {
130557e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
130657e22627SCy Schubert exit(0);
130757e22627SCy Schubert }
130857e22627SCy Schubert (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
13096f9cba8fSJoseph Mingrone nullAuthAllowed, uses_ssl);
131057e22627SCy Schubert
131157e22627SCy Schubert exit(0);
131257e22627SCy Schubert }
131357e22627SCy Schubert
131457e22627SCy Schubert // I am the parent
131557e22627SCy Schubert // Close the socket for this session (must be open only in the child)
131657e22627SCy Schubert closesocket(sockctrl);
131757e22627SCy Schubert #endif /* _WIN32 */
131857e22627SCy Schubert }
131957e22627SCy Schubert
132057e22627SCy Schubert /*!
132157e22627SCy Schubert \brief 'true' main of the program in case the active mode is turned on.
132257e22627SCy Schubert
132357e22627SCy Schubert This function loops forever trying to connect to the remote host, until the
132457e22627SCy Schubert daemon is turned down.
132557e22627SCy Schubert
132657e22627SCy Schubert \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
132757e22627SCy Schubert just because the thread APIs want this format.
132857e22627SCy Schubert */
132957e22627SCy Schubert #ifdef _WIN32
133057e22627SCy Schubert static unsigned __stdcall
133157e22627SCy Schubert #else
133257e22627SCy Schubert static void *
133357e22627SCy Schubert #endif
main_active(void * ptr)133457e22627SCy Schubert main_active(void *ptr)
133557e22627SCy Schubert {
133657e22627SCy Schubert char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1337*afdbf109SJoseph Mingrone PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
133857e22627SCy Schubert struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
133957e22627SCy Schubert struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
134057e22627SCy Schubert struct active_pars *activepars;
134157e22627SCy Schubert
134257e22627SCy Schubert activepars = (struct active_pars *) ptr;
134357e22627SCy Schubert
134457e22627SCy Schubert // Prepare to open a new server socket
134557e22627SCy Schubert memset(&hints, 0, sizeof(struct addrinfo));
134657e22627SCy Schubert // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
134757e22627SCy Schubert hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
134857e22627SCy Schubert hints.ai_socktype = SOCK_STREAM;
134957e22627SCy Schubert hints.ai_family = activepars->ai_family;
135057e22627SCy Schubert
135157e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
135257e22627SCy Schubert activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
135357e22627SCy Schubert (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
135457e22627SCy Schubert
135557e22627SCy Schubert // Initialize errbuf
135657e22627SCy Schubert memset(errbuf, 0, sizeof(errbuf));
135757e22627SCy Schubert
135857e22627SCy Schubert // Do the work
1359*afdbf109SJoseph Mingrone addrinfo = sock_initaddress(activepars->address, activepars->port,
1360*afdbf109SJoseph Mingrone &hints, errbuf, PCAP_ERRBUF_SIZE);
1361*afdbf109SJoseph Mingrone if (addrinfo == NULL)
136257e22627SCy Schubert {
136357e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
136457e22627SCy Schubert return 0;
136557e22627SCy Schubert }
136657e22627SCy Schubert
136757e22627SCy Schubert for (;;)
136857e22627SCy Schubert {
136957e22627SCy Schubert int activeclose;
137057e22627SCy Schubert
13716f9cba8fSJoseph Mingrone if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
137257e22627SCy Schubert {
137357e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
137457e22627SCy Schubert
13756f9cba8fSJoseph Mingrone DIAG_OFF_FORMAT_TRUNCATION
13766f9cba8fSJoseph Mingrone snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
137757e22627SCy Schubert activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
137857e22627SCy Schubert (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
13796f9cba8fSJoseph Mingrone DIAG_ON_FORMAT_TRUNCATION
138057e22627SCy Schubert
138157e22627SCy Schubert rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
138257e22627SCy Schubert
138357e22627SCy Schubert sleep_secs(RPCAP_ACTIVE_WAIT);
138457e22627SCy Schubert
138557e22627SCy Schubert continue;
138657e22627SCy Schubert }
138757e22627SCy Schubert
138857e22627SCy Schubert char *hostlist_copy = strdup(hostlist);
138957e22627SCy Schubert if (hostlist_copy == NULL)
139057e22627SCy Schubert {
139157e22627SCy Schubert rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
139257e22627SCy Schubert activeclose = 0;
139357e22627SCy Schubert sock_close(sockctrl, NULL, 0);
139457e22627SCy Schubert }
139557e22627SCy Schubert else
139657e22627SCy Schubert {
139757e22627SCy Schubert //
139857e22627SCy Schubert // daemon_serviceloop() will free the copy.
139957e22627SCy Schubert //
140057e22627SCy Schubert activeclose = daemon_serviceloop(sockctrl, 1,
14016f9cba8fSJoseph Mingrone hostlist_copy, nullAuthAllowed, uses_ssl);
140257e22627SCy Schubert }
140357e22627SCy Schubert
14046f9cba8fSJoseph Mingrone // If the connection is closed by the user explicitly, don't try to connect to it again
140557e22627SCy Schubert // just exit the program
140657e22627SCy Schubert if (activeclose == 1)
140757e22627SCy Schubert break;
140857e22627SCy Schubert }
140957e22627SCy Schubert
141057e22627SCy Schubert freeaddrinfo(addrinfo);
141157e22627SCy Schubert return 0;
141257e22627SCy Schubert }
141357e22627SCy Schubert
141457e22627SCy Schubert #ifdef _WIN32
141557e22627SCy Schubert //
141657e22627SCy Schubert // Main routine of a passive-mode service thread.
141757e22627SCy Schubert //
main_passive_serviceloop_thread(void * ptr)141857e22627SCy Schubert unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
141957e22627SCy Schubert {
142057e22627SCy Schubert struct params_copy params = *(struct params_copy *)ptr;
142157e22627SCy Schubert free(ptr);
142257e22627SCy Schubert
142357e22627SCy Schubert //
142457e22627SCy Schubert // Handle this client.
142557e22627SCy Schubert // This is passive mode, so we don't care whether we were
142657e22627SCy Schubert // told by the client to close.
142757e22627SCy Schubert //
142857e22627SCy Schubert (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
14296f9cba8fSJoseph Mingrone nullAuthAllowed, uses_ssl);
143057e22627SCy Schubert
143157e22627SCy Schubert return 0;
143257e22627SCy Schubert }
143357e22627SCy Schubert #endif
1434