]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add support for running rpcapd from inetd and inetd-alikes.
authorGuy Harris <[email protected]>
Mon, 2 Apr 2018 03:05:34 +0000 (20:05 -0700)
committerGuy Harris <[email protected]>
Mon, 2 Apr 2018 03:05:34 +0000 (20:05 -0700)
When run from inetd and programs that support inetd-style program
launching (xinetd, launchd, systemd, ...), we don't do a
connection-accept loop; we're handed the input side of the connection as
the standard input and the output side of the connection as the standard
output, and should dive right into the service loop.

We extract the initial connection initialization and cleanup stuff from
daemon_serviceloop() and put it into the code that calls the service
loop, in rpcapd.c; it's different in the four cases where we start a
service loop (accepted connection on UN*X, accepted connection on
Windows, run from inetd, active mode), so that cleans up
daemon_serviceloop() a bit.

Supply a sample launchd plist; we could also supply examples of inetd
and xinetd config file entries, and systemd units.

Makefile.in
org.tcpdump.rpcapd.plist [new file with mode: 0644]
rpcapd/config_params.h [new file with mode: 0644]
rpcapd/daemon.c
rpcapd/daemon.h
rpcapd/fileconf.c
rpcapd/rpcapd.c
rpcapd/rpcapd.h

index 0659a5843985fc32a8bed7840119f48c69c48d86..84f7053017a70e9a6593528c89efd15ed7bcc908 100644 (file)
@@ -303,6 +303,7 @@ EXTRA_DIST = \
        msdos/readme.dos \
        nomkdep \
        org.tcpdump.chmod_bpf.plist \
+       org.tcpdump.rpcapd.plist \
        pcap-bpf.c \
        pcap-bt-linux.c \
        pcap-bt-linux.h \
@@ -351,6 +352,7 @@ EXTRA_DIST = \
        rpcap-protocol.c \
        rpcapd/CMakeLists.txt \
        rpcapd/Makefile.in \
+       rpcapd/config_params.h \
        rpcapd/daemon.h \
        rpcapd/daemon.c \
        rpcapd/fileconf.c \
diff --git a/org.tcpdump.rpcapd.plist b/org.tcpdump.rpcapd.plist
new file mode 100644 (file)
index 0000000..db3223a
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Disabled</key>
+       <false/>
+       <key>Label</key>
+       <string>com.tcpdump.rpcapd</string>
+       <key>Program</key>
+       <string>/usr/local/libexec/rpcapd</string>
+       <key>ProgramArguments</key>
+       <array>
+               <string>/usr/local/libexec/rpcapd</string>
+               <string>-i</string>
+       </array>
+       <key>Sockets</key>
+       <dict>
+               <key>Listeners</key>
+               <dict>
+                       <key>SockServiceName</key>
+                       <string>2002</string>
+               </dict>
+       </dict>
+       <key>inetdCompatibility</key>
+       <dict>
+               <key>Wait</key>
+               <false/>
+       </dict>
+</dict>
+</plist>
diff --git a/rpcapd/config_params.h b/rpcapd/config_params.h
new file mode 100644 (file)
index 0000000..c219ce1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __CONFIG_PARAMS_H__
+#define __CONFIG_PARAMS_H__
+
+//
+// Parameters set from the configuration file.
+//
+
+#define MAX_LINE 2048          /* Maximum chars allowed for the host list (in passive mode) */
+#define MAX_HOST_LIST 64000
+#define MAX_ACTIVE_LIST 10
+
+struct active_pars
+{
+       char address[MAX_LINE + 1];     // keeps the network address (either numeric or literal) to of the active client
+       char port[MAX_LINE + 1];        // keeps the network port to bind to
+       int ai_family;                  // address faimly to use
+};
+
+extern char hostlist[MAX_HOST_LIST + 1];       //!< Keeps the list of the hosts that are allowed to connect to this server
+extern struct active_pars activelist[MAX_ACTIVE_LIST];         //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
+extern int nullAuthAllowed;                    //!< '1' if we permit NULL authentication, '0' otherwise
+extern char loadfile[MAX_LINE + 1];            //!< Name of the file from which we have to load the configuration
+
+#endif
index bbe4dd1a0e307e2d4d3ff11c33c8de41d00488db..a0acd4af036abcefaef26398241be7c6545ee103 100755 (executable)
 #define RPCAP_TIMEOUT_RUNTIME 180      /* Run-time timeout for RPCAP connections (default: 3 min) */
 #define RPCAP_SUSPEND_WRONGAUTH 1      /* If the authentication is wrong, stops 1 sec before accepting a new auth message */
 
+// Parameters for the service loop.
+struct daemon_slpars
+{
+       SOCKET sockctrl_in;     //!< SOCKET ID of the input side of the control connection
+       SOCKET sockctrl_out;    //!< SOCKET ID of the output side of the control connection
+       uint8 protocol_version; //!< negotiated protocol version
+       int isactive;           //!< Not null if the daemon has to run in active mode
+       int nullAuthAllowed;    //!< '1' if we permit NULL authentication, '0' otherwise
+};
+
 /*
  * Data for a session managed by a thread.
  */
 struct session {
-       SOCKET sockctrl;
+       SOCKET sockctrl_out;
        SOCKET sockdata;
        uint8 protocol_version;
        pcap_t *fp;
@@ -78,8 +88,8 @@ struct session {
 };
 
 // Locally defined functions
-static int daemon_msg_err(SOCKET sockctrl, uint32 plen);
-static int daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed);
+static int daemon_msg_err(SOCKET sockctrl_in, uint32 plen);
+static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen);
 static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
 
 static int daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen);
@@ -94,7 +104,7 @@ static int daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *ses
 #endif
 
 static int daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session, uint32 plen);
-static int daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errbuf);
+static int daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errbuf);
 
 static int daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32 plen, struct pcap_stat *stats, unsigned int svrcapt);
 
@@ -111,24 +121,10 @@ static int rpcapd_recv_msg_header(SOCKET sock, struct rpcap_header *headerp);
 static int rpcapd_recv(SOCKET sock, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf);
 static int rpcapd_discard(SOCKET sock, uint32 len);
 
-/*!
-       \brief Main serving function
-       This function is the one which does the job. It is the main() of the child
-       thread, which is created as soon as a new connection is accepted.
-
-       \param ptr: a void pointer that keeps the reference of the 'pthread_chain'
-       value corresponding to this thread. This variable is casted into a 'pthread_chain'
-       value in order to retrieve the socket we're currently using, the thread ID, and
-       some pointers to the previous and next elements into this struct.
-
-       \return None.
-*/
-#ifdef _WIN32
-unsigned __stdcall daemon_serviceloop(void *ptr)
-#else
-void *daemon_serviceloop(void *ptr)
-#endif
+int
+daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive, int nullAuthAllowed)
 {
+       struct daemon_slpars pars;              // service loop parameters
        char errbuf[PCAP_ERRBUF_SIZE + 1];      // keeps the error string, prior to be printed
        char errmsgbuf[PCAP_ERRBUF_SIZE + 1];   // buffer for errors to send to the client
        int nrecv;
@@ -138,8 +134,8 @@ void *daemon_serviceloop(void *ptr)
        char source[PCAP_BUF_SIZE+1];           // keeps the string that contains the interface to open
        int got_source = 0;                     // 1 if we've gotten the source from an open request
        struct session *session = NULL;         // struct session main variable
-       struct daemon_slpars *pars;             // parameters related to the present daemon loop
        const char *msg_type_string;            // string for message type
+       int client_told_us_to_close = 0;        // 1 if the client told us to close the capture
 
        int have_thread = 0;                    // 1 if threaddata refers to a thread we've created
 #ifdef _WIN32
@@ -159,22 +155,15 @@ void *daemon_serviceloop(void *ptr)
        struct timeval tv;                      // maximum time the select() can block waiting for data
        int retval;                             // select() return value
 
-       pars = (struct daemon_slpars *) ptr;
+       // Set parameters structure
+       pars.sockctrl_in = sockctrl_in;
+       pars.sockctrl_out = sockctrl_out;
+       pars.protocol_version = 0;              // not yet known
+       pars.isactive = isactive;               // active mode
+       pars.nullAuthAllowed = nullAuthAllowed;
 
        *errbuf = 0;    // Initialize errbuf
 
-#ifndef _WIN32
-       // If we're in active mode, this is not a separate thread
-       if (! pars->isactive)
-       {
-               // Modify thread params so that it can be killed at any time
-               if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
-                       goto end;
-               if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
-                       goto end;
-       }
-#endif
-
        //
        // The client must first authenticate; loop until they send us a
        // message with a version we support and credentials we accept,
@@ -189,20 +178,20 @@ void *daemon_serviceloop(void *ptr)
                //
                // XXX - do this on *every* trip through the loop?
                //
-               if (!pars->isactive)
+               if (!pars.isactive)
                {
                        FD_ZERO(&rfds);
                        // We do not have to block here
                        tv.tv_sec = RPCAP_TIMEOUT_INIT;
                        tv.tv_usec = 0;
 
-                       FD_SET(pars->sockctrl, &rfds);
+                       FD_SET(pars.sockctrl_in, &rfds);
 
-                       retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
+                       retval = select(pars.sockctrl_in + 1, &rfds, NULL, NULL, &tv);
                        if (retval == -1)
                        {
                                sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE);
-                               if (rpcap_senderror(pars->sockctrl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
+                               if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1)
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                goto end;
                        }
@@ -211,7 +200,7 @@ void *daemon_serviceloop(void *ptr)
                        // So, this was a fake connection. Drop it down
                        if (retval == 0)
                        {
-                               if (rpcap_senderror(pars->sockctrl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
+                               if (rpcap_senderror(pars.sockctrl_out, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1)
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                goto end;
                        }
@@ -220,7 +209,7 @@ void *daemon_serviceloop(void *ptr)
                //
                // Read the message header from the client.
                //
-               nrecv = rpcapd_recv_msg_header(pars->sockctrl, &header);
+               nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header);
                if (nrecv == -1)
                {
                        // Fatal error.
@@ -276,7 +265,7 @@ void *daemon_serviceloop(void *ptr)
                                // 
                                reply_version = RPCAP_MAX_VERSION;
                        }
-                       if (rpcap_senderror(pars->sockctrl, reply_version,
+                       if (rpcap_senderror(pars.sockctrl_out, reply_version,
                            PCAP_ERR_WRONGVER, "RPCAP version number mismatch",
                            errbuf) == -1)
                        {
@@ -286,7 +275,7 @@ void *daemon_serviceloop(void *ptr)
                        }
 
                        // Discard the rest of the message.
-                       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                       if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                        {
                                // Network error.
                                goto end;
@@ -299,12 +288,12 @@ void *daemon_serviceloop(void *ptr)
                //
                // OK, we use the version the client specified.
                //
-               pars->protocol_version = header.ver;
+               pars.protocol_version = header.ver;
 
                switch (header.type)
                {
                        case RPCAP_MSG_AUTH_REQ:
-                               retval = daemon_msg_auth_req(pars->sockctrl, pars->protocol_version, plen, pars->nullAuthAllowed);
+                               retval = daemon_msg_auth_req(&pars, plen);
                                if (retval == -1)
                                {
                                        // Fatal error; a message has
@@ -330,7 +319,7 @@ void *daemon_serviceloop(void *ptr)
                                // Discard the rest of the message, if
                                // there is anything more.
                                //
-                               (void)rpcapd_discard(pars->sockctrl, plen);
+                               (void)rpcapd_discard(pars.sockctrl_in, plen);
                                // We're done with this client.
                                goto end;
 
@@ -342,7 +331,7 @@ void *daemon_serviceloop(void *ptr)
                                // an error message rather than a "let
                                // me log in" message, indicating that
                                // we're not allowed to connect to them?
-                               (void)daemon_msg_err(pars->sockctrl, plen);
+                               (void)daemon_msg_err(pars.sockctrl_in, plen);
                                goto end;
 
                        case RPCAP_MSG_FINDALLIF_REQ:
@@ -365,15 +354,15 @@ void *daemon_serviceloop(void *ptr)
                                {
                                        pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type);
                                }
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_WRONGMSG,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_WRONGMSG,
                                    errmsgbuf, errbuf) == -1)
                                {
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Network error.
                                        goto end;
@@ -401,15 +390,15 @@ void *daemon_serviceloop(void *ptr)
                                {
                                        pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
                                }
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_WRONGMSG,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_WRONGMSG,
                                    errmsgbuf, errbuf) == -1)
                                {
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Fatal error.
                                        goto end;
@@ -421,15 +410,15 @@ void *daemon_serviceloop(void *ptr)
                                // Unknown message type.
                                //
                                pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_WRONGMSG,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_WRONGMSG,
                                    errmsgbuf, errbuf) == -1)
                                {
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Fatal error.
                                        goto end;
@@ -467,7 +456,7 @@ void *daemon_serviceloop(void *ptr)
                //
                // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
                //  sockdata is 0
-               if ((!pars->isactive) &&  ((session == NULL) || ((session != NULL) && (session->sockdata == 0))))
+               if ((!pars.isactive) &&  ((session == NULL) || ((session != NULL) && (session->sockdata == 0))))
                {
                        // Check for the initial timeout
                        FD_ZERO(&rfds);
@@ -475,14 +464,14 @@ void *daemon_serviceloop(void *ptr)
                        tv.tv_sec = RPCAP_TIMEOUT_RUNTIME;
                        tv.tv_usec = 0;
 
-                       FD_SET(pars->sockctrl, &rfds);
+                       FD_SET(pars.sockctrl_in, &rfds);
 
-                       retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
+                       retval = select(pars.sockctrl_in + 1, &rfds, NULL, NULL, &tv);
                        if (retval == -1)
                        {
                                sock_geterror("select failed: ", errmsgbuf, PCAP_ERRBUF_SIZE);
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_NETW,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_NETW,
                                    errmsgbuf, errbuf) == -1)
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                goto end;
@@ -492,8 +481,8 @@ void *daemon_serviceloop(void *ptr)
                        // So, this was a fake connection. Drop it down
                        if (retval == 0)
                        {
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version,
                                    PCAP_ERR_INITTIMEOUT,
                                    "The RPCAP initial timeout has expired",
                                    errbuf) == -1)
@@ -505,7 +494,7 @@ void *daemon_serviceloop(void *ptr)
                //
                // Read the message header from the client.
                //
-               nrecv = rpcapd_recv_msg_header(pars->sockctrl, &header);
+               nrecv = rpcapd_recv_msg_header(pars.sockctrl_in, &header);
                if (nrecv == -1)
                {
                        // Fatal error.
@@ -524,7 +513,7 @@ void *daemon_serviceloop(void *ptr)
                //
                // For now, there's only one version.
                //
-               if (header.ver != pars->protocol_version)
+               if (header.ver != pars.protocol_version)
                {
                        //
                        // Tell them it's not the negotiated version.
@@ -532,7 +521,7 @@ void *daemon_serviceloop(void *ptr)
                        // so they don't reject it as having the wrong
                        // version.
                        //
-                       if (rpcap_senderror(pars->sockctrl,
+                       if (rpcap_senderror(pars.sockctrl_out,
                            header.ver, PCAP_ERR_WRONGVER,
                            "RPCAP version in message isn't the negotiated version",
                            errbuf) == -1)
@@ -543,7 +532,7 @@ void *daemon_serviceloop(void *ptr)
                        }
 
                        // Discard the rest of the message.
-                       (void)rpcapd_discard(pars->sockctrl, plen);
+                       (void)rpcapd_discard(pars.sockctrl_in, plen);
                        // Give up on them.
                        goto end;
                }
@@ -552,7 +541,7 @@ void *daemon_serviceloop(void *ptr)
                {
                        case RPCAP_MSG_ERROR:           // The other endpoint reported an error
                        {
-                               (void)daemon_msg_err(pars->sockctrl, plen);
+                               (void)daemon_msg_err(pars.sockctrl_in, plen);
                                // Do nothing; just exit; the error code is already into the errbuf
                                // XXX - actually exit....
                                break;
@@ -560,7 +549,7 @@ void *daemon_serviceloop(void *ptr)
 
                        case RPCAP_MSG_FINDALLIF_REQ:
                        {
-                               if (daemon_msg_findallif_req(pars, plen) == -1)
+                               if (daemon_msg_findallif_req(&pars, plen) == -1)
                                {
                                        // Fatal error; a message has
                                        // been logged, so just give up.
@@ -580,7 +569,7 @@ void *daemon_serviceloop(void *ptr)
                                // us multiple open requests, the last
                                // one wins.
                                //
-                               retval = daemon_msg_open_req(pars, plen, source, sizeof(source));
+                               retval = daemon_msg_open_req(&pars, plen, source, sizeof(source));
                                if (retval == -1)
                                {
                                        // Fatal error; a message has
@@ -597,8 +586,8 @@ void *daemon_serviceloop(void *ptr)
                                {
                                        // They never told us what device
                                        // to capture on!
-                                       if (rpcap_senderror(pars->sockctrl,
-                                           pars->protocol_version,
+                                       if (rpcap_senderror(pars.sockctrl_out,
+                                           pars.protocol_version,
                                            PCAP_ERR_STARTCAPTURE,
                                            "No capture device was specified",
                                            errbuf) == -1)
@@ -608,14 +597,14 @@ void *daemon_serviceloop(void *ptr)
                                                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                                goto end;
                                        }
-                                       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                                       if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                        {
                                                goto end;
                                        }
                                        break;
                                }
 
-                               if (daemon_msg_startcap_req(pars, plen, &have_thread, &threaddata, source, &session, &samp_param) == -1)
+                               if (daemon_msg_startcap_req(&pars, plen, &have_thread, &threaddata, source, &session, &samp_param) == -1)
                                {
                                        // Fatal error; a message has
                                        // been logged, so just give up.
@@ -628,7 +617,7 @@ void *daemon_serviceloop(void *ptr)
                        {
                                if (session)
                                {
-                                       if (daemon_msg_updatefilter_req(pars, session, plen) == -1)
+                                       if (daemon_msg_updatefilter_req(&pars, session, plen) == -1)
                                        {
                                                // Fatal error; a message has
                                                // been logged, so just give up.
@@ -637,8 +626,8 @@ void *daemon_serviceloop(void *ptr)
                                }
                                else
                                {
-                                       if (rpcap_senderror(pars->sockctrl,
-                                           pars->protocol_version,
+                                       if (rpcap_senderror(pars.sockctrl_out,
+                                           pars.protocol_version,
                                            PCAP_ERR_UPDATEFILTER,
                                            "Device not opened. Cannot update filter",
                                            errbuf) == -1)
@@ -653,16 +642,19 @@ void *daemon_serviceloop(void *ptr)
 
                        case RPCAP_MSG_CLOSE:           // The other endpoint close the pcap session
                        {
-                               // signal to the main that the user closed the control connection
-                               // This is used only in case of active mode
-                               pars->activeclose = 1;
+                               //
+                               // Indicate to our caller that the client
+                               // closed the control connection.
+                               // This is used only in case of active mode.
+                               //
+                               client_told_us_to_close = 1;
                                SOCK_MESSAGE("The other end system asked to close the connection.");
                                goto end;
                        }
 
                        case RPCAP_MSG_STATS_REQ:
                        {
-                               if (daemon_msg_stats_req(pars, session, plen, &stats, svrcapt) == -1)
+                               if (daemon_msg_stats_req(&pars, session, plen, &stats, svrcapt) == -1)
                                {
                                        // Fatal error; a message has
                                        // been logged, so just give up.
@@ -688,7 +680,7 @@ void *daemon_serviceloop(void *ptr)
                                                svrcapt = 0;
                                        }
 
-                                       if (daemon_msg_endcap_req(pars, session, &have_thread, threaddata) == -1)
+                                       if (daemon_msg_endcap_req(&pars, session, &have_thread, threaddata) == -1)
                                        {
                                                free(session);
                                                session = NULL;
@@ -701,8 +693,8 @@ void *daemon_serviceloop(void *ptr)
                                }
                                else
                                {
-                                       rpcap_senderror(pars->sockctrl,
-                                           pars->protocol_version,
+                                       rpcap_senderror(pars.sockctrl_out,
+                                           pars.protocol_version,
                                            PCAP_ERR_ENDCAPTURE,
                                            "Device not opened. Cannot close the capture",
                                            errbuf);
@@ -712,7 +704,7 @@ void *daemon_serviceloop(void *ptr)
 
                        case RPCAP_MSG_SETSAMPLING_REQ:
                        {
-                               if (daemon_msg_setsampling_req(pars, plen, &samp_param) == -1)
+                               if (daemon_msg_setsampling_req(&pars, plen, &samp_param) == -1)
                                {
                                        // Fatal error; a message has
                                        // been logged, so just give up.
@@ -728,8 +720,8 @@ void *daemon_serviceloop(void *ptr)
                                // get to reauthenticate.
                                //
                                rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed");
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version,
                                    PCAP_ERR_WRONGMSG,
                                    "RPCAP_MSG_AUTH_REQ request sent after authentication was completed",
                                    errbuf) == -1)
@@ -738,7 +730,7 @@ void *daemon_serviceloop(void *ptr)
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Fatal error.
                                        goto end;
@@ -768,15 +760,15 @@ void *daemon_serviceloop(void *ptr)
                                        rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type);
                                        pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type);
                                }
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_WRONGMSG,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_WRONGMSG,
                                    errmsgbuf, errbuf) == -1)
                                {
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Fatal error.
                                        goto end;
@@ -789,15 +781,15 @@ void *daemon_serviceloop(void *ptr)
                                //
                                rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type);
                                pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type);
-                               if (rpcap_senderror(pars->sockctrl,
-                                   pars->protocol_version, PCAP_ERR_WRONGMSG,
+                               if (rpcap_senderror(pars.sockctrl_out,
+                                   pars.protocol_version, PCAP_ERR_WRONGMSG,
                                    errbuf, errmsgbuf) == -1)
                                {
                                        rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                                        goto end;
                                }
                                // Discard the rest of the message.
-                               if (rpcapd_discard(pars->sockctrl, plen) == -1)
+                               if (rpcapd_discard(pars.sockctrl_in, plen) == -1)
                                {
                                        // Fatal error.
                                        goto end;
@@ -857,25 +849,18 @@ end:
                session = NULL;
        }
 
-       // Print message and exit
+       // Print message and return
        SOCK_MESSAGE("I'm exiting from the child loop");
        SOCK_MESSAGE(errbuf);
 
-       if (!pars->isactive)
-       {
-               if (pars->sockctrl)
-                       sock_close(pars->sockctrl, NULL, 0);
-
-               free(pars);
-       }
-       return 0;
+       return client_told_us_to_close;
 }
 
 /*
  * This handles the RPCAP_MSG_ERR message.
  */
 static int
-daemon_msg_err(SOCKET sockctrl, uint32 plen)
+daemon_msg_err(SOCKET sockctrl_in, uint32 plen)
 {
        char errbuf[PCAP_ERRBUF_SIZE];
        char remote_errbuf[PCAP_ERRBUF_SIZE];
@@ -886,7 +871,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
                 * Message is too long; just read as much of it as we
                 * can into the buffer provided, and discard the rest.
                 */
-               if (sock_recv(sockctrl, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
+               if (sock_recv(sockctrl_in, remote_errbuf, PCAP_ERRBUF_SIZE - 1,
                    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
                    PCAP_ERRBUF_SIZE) == -1)
                {
@@ -894,7 +879,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
                        rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf);
                        return -1;
                }
-               if (rpcapd_discard(sockctrl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
+               if (rpcapd_discard(sockctrl_in, plen - (PCAP_ERRBUF_SIZE - 1)) == -1)
                {
                        // Network error.
                        return -1;
@@ -912,7 +897,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
        }
        else
        {
-               if (sock_recv(sockctrl, remote_errbuf, plen,
+               if (sock_recv(sockctrl_in, remote_errbuf, plen,
                    SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf,
                    PCAP_ERRBUF_SIZE) == -1)
                {
@@ -954,7 +939,7 @@ daemon_msg_err(SOCKET sockctrl, uint32 plen)
  * unrecoverable error or for the authentication failure.
  */
 static int
-daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed)
+daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen)
 {
        char errbuf[PCAP_ERRBUF_SIZE];          // buffer for network errors
        char errmsgbuf[PCAP_ERRBUF_SIZE];       // buffer for errors to send to the client
@@ -962,7 +947,7 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
        int status;
        struct rpcap_auth auth;                 // RPCAP authentication header
 
-       status = rpcapd_recv(sockctrl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
+       status = rpcapd_recv(pars->sockctrl_in, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf);
        if (status == -1)
        {
                return -1;
@@ -976,7 +961,7 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
        {
                case RPCAP_RMTAUTH_NULL:
                {
-                       if (!nullAuthAllowed)
+                       if (!pars->nullAuthAllowed)
                        {
                                // Send the client an error reply.
                                pcap_snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Authentication failed; NULL authentication not permitted.");
@@ -998,7 +983,7 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
                                    PCAP_ERRBUF_SIZE, errno, "malloc() failed");
                                goto error;
                        }
-                       status = rpcapd_recv(sockctrl, username, usernamelen, &plen, errmsgbuf);
+                       status = rpcapd_recv(pars->sockctrl_in, username, usernamelen, &plen, errmsgbuf);
                        if (status == -1)
                        {
                                free(username);
@@ -1020,7 +1005,7 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
                                free(username);
                                goto error;
                        }
-                       status = rpcapd_recv(sockctrl, passwd, passwdlen, &plen, errmsgbuf);
+                       status = rpcapd_recv(pars->sockctrl_in, passwd, passwdlen, &plen, errmsgbuf);
                        if (status == -1)
                        {
                                free(username);
@@ -1043,7 +1028,8 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
                                //
                                free(username);
                                free(passwd);
-                               if (rpcap_senderror(sockctrl, ver,
+                               if (rpcap_senderror(pars->sockctrl_out,
+                                   pars->protocol_version,
                                    PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
                                {
                                        // That failed; log a message and give up.
@@ -1076,10 +1062,10 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
        }
 
        // The authentication succeeded; let the client know.
-       rpcap_createhdr(&header, ver, RPCAP_MSG_AUTH_REPLY, 0, 0);
+       rpcap_createhdr(&header, pars->protocol_version, RPCAP_MSG_AUTH_REPLY, 0, 0);
 
        // Send the ok message back
-       if (sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                // That failed; log a messsage and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1087,7 +1073,7 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
        }
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
@@ -1095,8 +1081,8 @@ daemon_msg_auth_req(SOCKET sockctrl, uint8 ver, uint32 plen, int nullAuthAllowed
        return 0;
 
 error:
-       if (rpcap_senderror(sockctrl, ver, PCAP_ERR_AUTH, errmsgbuf,
-           errbuf) == -1)
+       if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
+           PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
        {
                // That failed; log a message and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1105,7 +1091,7 @@ error:
 
 error_noreply:
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
@@ -1250,7 +1236,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
        uint16 nif = 0;                         // counts the number of interface listed
 
        // Discard the rest of the message; there shouldn't be any payload.
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                // Network error.
                return -1;
@@ -1262,7 +1248,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
 
        if (alldevs == NULL)
        {
-               if (rpcap_senderror(pars->sockctrl, pars->protocol_version,
+               if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
                        PCAP_ERR_NOREMOTEIF,
                        "No interfaces found! Make sure libpcap/WinPcap is properly installed"
                        " and you have the right to access to the remote device.",
@@ -1416,7 +1402,7 @@ daemon_msg_findallif_req(struct daemon_slpars *pars, uint32 plen)
        pcap_freealldevs(alldevs);
 
        // Send a final command that says "now send it!"
-       if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                return -1;
@@ -1428,7 +1414,7 @@ error:
        if (alldevs)
                pcap_freealldevs(alldevs);
        
-       if (rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1)
        {
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1458,7 +1444,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
                goto error;
        }
 
-       nread = sock_recv(pars->sockctrl, source, plen,
+       nread = sock_recv(pars->sockctrl_in, source, plen,
            SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE);
        if (nread == -1)
        {
@@ -1502,7 +1488,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
        pcap_close(fp);
 
        // Send the reply.
-       if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                return -1;
@@ -1510,7 +1496,7 @@ daemon_msg_open_req(struct daemon_slpars *pars, uint32 plen, char *source, size_
        return 0;
 
 error:
-       if (rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_OPEN, errmsgbuf, errbuf) == -1)
        {
                // That failed; log a message and give up.
@@ -1519,7 +1505,7 @@ error:
        }
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
@@ -1566,7 +1552,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, int *have_threa
 
        addrinfo = NULL;
 
-       status = rpcapd_recv(pars->sockctrl, (char *) &startcapreq,
+       status = rpcapd_recv(pars->sockctrl_in, (char *) &startcapreq,
            sizeof(struct rpcap_startcapreq), &plen, errmsgbuf);
        if (status == -1)
        {
@@ -1618,7 +1604,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, int *have_threa
        we want to connect to
        */
        saddrlen = sizeof(struct sockaddr_storage);
-       if (getpeername(pars->sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
+       if (getpeername(pars->sockctrl_in, (struct sockaddr *) &saddr, &saddrlen) == -1)
        {
                sock_geterror("getpeername(): ", errmsgbuf, PCAP_ERRBUF_SIZE);
                goto error;
@@ -1680,11 +1666,11 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, int *have_threa
        addrinfo = NULL;
 
        // Needed to send an error on the ctrl connection
-       session->sockctrl = pars->sockctrl;
+       session->sockctrl_out = pars->sockctrl_out;
        session->protocol_version = pars->protocol_version;
 
        // Now I can set the filter
-       ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+       ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf);
        if (ret == -1)
        {
                // Fatal error.  A message has been logged; just give up.
@@ -1719,7 +1705,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, int *have_threa
                startcapreply->portdata = htons(port);
        }
 
-       if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                // That failed; log a message and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1778,7 +1764,7 @@ daemon_msg_startcap_req(struct daemon_slpars *pars, uint32 plen, int *have_threa
        *have_thread = 1;
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
                goto fatal_error;
 
        *sessionp = session;
@@ -1819,7 +1805,7 @@ error:
                free(session);
        }
 
-       if (rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1)
        {
                // That failed; log a message and give up.
@@ -1828,7 +1814,7 @@ error:
        }
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                // Network error.
                return -1;
@@ -1949,7 +1935,7 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, int *
        rpcap_createhdr(&header, pars->protocol_version,
            RPCAP_MSG_ENDCAP_REPLY, 0, 0);
 
-       if (sock_send(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                // That failed; log a message and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -1960,7 +1946,7 @@ daemon_msg_endcap_req(struct daemon_slpars *pars, struct session *session, int *
 }
 
 static int
-daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp, char *errmsgbuf)
+daemon_unpackapplyfilter(SOCKET sockctrl_in, struct session *session, uint32 *plenp, char *errmsgbuf)
 {
        int status;
        struct rpcap_filter filter;
@@ -1969,7 +1955,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
        struct bpf_program bf_prog;
        unsigned int i;
 
-       status = rpcapd_recv(sockctrl, (char *) &filter,
+       status = rpcapd_recv(sockctrl_in, (char *) &filter,
            sizeof(struct rpcap_filter), plenp, errmsgbuf);
        if (status == -1)
        {
@@ -2000,7 +1986,7 @@ daemon_unpackapplyfilter(SOCKET sockctrl, struct session *session, uint32 *plenp
 
        for (i = 0; i < bf_prog.bf_len; i++)
        {
-               status = rpcapd_recv(sockctrl, (char *) &insn,
+               status = rpcapd_recv(sockctrl_in, (char *) &insn,
                    sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf);
                if (status == -1)
                {
@@ -2042,7 +2028,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
        int ret;                                // status of daemon_unpackapplyfilter()
        struct rpcap_header header;             // keeps the answer to the updatefilter command
 
-       ret = daemon_unpackapplyfilter(pars->sockctrl, session, &plen, errmsgbuf);
+       ret = daemon_unpackapplyfilter(pars->sockctrl_in, session, &plen, errmsgbuf);
        if (ret == -1)
        {
                // Fatal error.  A message has been logged; just give up.
@@ -2055,7 +2041,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
        }
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                // Network error.
                return -1;
@@ -2065,7 +2051,7 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
        rpcap_createhdr(&header, pars->protocol_version,
            RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
 
-       if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
+       if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
        {
                // That failed; log a messsage and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
@@ -2075,11 +2061,11 @@ daemon_msg_updatefilter_req(struct daemon_slpars *pars, struct session *session,
        return 0;
 
 error:
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
-       rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_UPDATEFILTER, errmsgbuf, NULL);
 
        return 0;
@@ -2097,7 +2083,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
        struct rpcap_sampling rpcap_samp;
        int status;
 
-       status = rpcapd_recv(pars->sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
+       status = rpcapd_recv(pars->sockctrl_in, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf);
        if (status == -1)
        {
                return -1;
@@ -2115,14 +2101,14 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
        rpcap_createhdr(&header, pars->protocol_version,
            RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
 
-       if (sock_send(pars->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                // That failed; log a messsage and give up.
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                return -1;
        }
 
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
@@ -2130,7 +2116,7 @@ daemon_msg_setsampling_req(struct daemon_slpars *pars, uint32 plen, struct rpcap
        return 0;
 
 error:
-       if (rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       if (rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_AUTH, errmsgbuf, errbuf) == -1)
        {
                // That failed; log a message and give up.
@@ -2139,7 +2125,7 @@ error:
        }
 
        // Check if all the data has been read; if not, discard the data in excess
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                return -1;
        }
@@ -2157,7 +2143,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
        struct rpcap_stats *netstats;           // statistics sent on the network
 
        // Checks that the header does not contain other data; if so, discard it
-       if (rpcapd_discard(pars->sockctrl, plen) == -1)
+       if (rpcapd_discard(pars->sockctrl_in, plen) == -1)
        {
                // Network error.
                return -1;
@@ -2201,7 +2187,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
        }
 
        // Send the packet
-       if (sock_send(pars->sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+       if (sock_send(pars->sockctrl_out, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
        {
                rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf);
                return -1;
@@ -2210,7 +2196,7 @@ daemon_msg_stats_req(struct daemon_slpars *pars, struct session *session, uint32
        return 0;
 
 error:
-       rpcap_senderror(pars->sockctrl, pars->protocol_version,
+       rpcap_senderror(pars->sockctrl_out, pars->protocol_version,
            PCAP_ERR_GETSTATS, errmsgbuf, NULL);
        return 0;
 }
@@ -2356,7 +2342,7 @@ daemon_thrdatamain(void *ptr)
        if (retval == -1)
        {
                pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
-               rpcap_senderror(session->sockctrl, session->protocol_version,
+               rpcap_senderror(session->sockctrl_out, session->protocol_version,
                    PCAP_ERR_READEX, errbuf, NULL);
                goto error;
        }
index ffbd2bce89a682b75491f0cac2d24334699d1e29..bd240b8055d1fa7a35b496957f8c93ba6eb6a7fd 100755 (executable)
 #ifndef __DAEMON_H__
 #define __DAEMON_H__
 
-//! Structure that keeps the parameters needed by the daemon_serviceloop()
-// function
-struct daemon_slpars
-{
-       SOCKET sockctrl;        //!< SOCKET ID of the control connection
-       uint8 protocol_version; //!< negotiated protocol version
-       int isactive;           //!< Not null if the daemon has to run in active mode
-       int nullAuthAllowed;    //!< '1' if we permit NULL authentication, '0' otherwise
-       int activeclose;        //!< '1' if the client closed the control connection explicitely; used in active mode only
-};
-
-#ifdef _WIN32
-unsigned __stdcall daemon_serviceloop(void *ptr);
-#else
-void *daemon_serviceloop(void *ptr);
-#endif
+//
+// Returns 1 if the client closed the control connection explicitly, 0
+// otherwise; used in active mode only.
+//
+int daemon_serviceloop(SOCKET sockctrl_in, SOCKET sockctrl_out, int isactive,
+    int nullAuthAllowed);
 
 void sleep_secs(int secs);
 
index 46b6dceb595b2e8be6eea774268f286371642315..099cdf37db69fddeae6729cdfc040924e247157c 100755 (executable)
@@ -45,6 +45,7 @@
 #include "sockutils.h"         // for SOCK_MESSAGE
 #include "portability.h"
 #include "rpcapd.h"
+#include "config_params.h"     // configuration file parameters
 #include "fileconf.h"
 #include "rpcap-protocol.h"
 
index 2a148c4af5a450234262380e9927de415c483087..7ea0ba90c21dbf5fa457d3e0b9ced9ca8c4b7024 100755 (executable)
@@ -46,6 +46,7 @@
 #include "sockutils.h"         // for socket calls
 #include "portability.h"
 #include "rpcapd.h"
+#include "config_params.h"     // configuration file parameters
 #include "fileconf.h"          // for the configuration file management
 #include "rpcap-protocol.h"
 #include "daemon.h"            // the true main() method of this daemon
@@ -56,6 +57,7 @@
   #include "win32-svc.h"       // for Win32 service stuff
   #include "getopt.h"          // for getopt()-for-Windows
 #else
+  #include <fcntl.h>           // for open()
   #include <unistd.h>          // for exit()
   #include <sys/wait.h>                // waitpid()
 #endif
@@ -100,6 +102,9 @@ static void accept_connection(SOCKET listen_sock);
 #ifndef _WIN32
 static void main_reap_children(int sign);
 #endif
+#ifdef _WIN32
+static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
+#endif
 
 #define RPCAP_ACTIVE_WAIT 30           /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
 
@@ -111,7 +116,11 @@ static void printusage(void)
        char *usagetext =
        "USAGE:"
        " "  PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
-       "              [-n] [-v] [-d] [-s <file>] [-f <file>]\n\n"
+       "              [-n] [-v] [-d] "
+#ifndef _WIN32
+       "[-i] "
+#endif
+       "[-s <file>] [-f <file>]\n\n"
        "  -b <address>    the address to bind to (either numeric or literal).\n"
        "                  Default: binds to all local IPv4 and IPv6 addresses\n\n"
        "  -p <port>       the port to bind to.\n"
@@ -119,17 +128,21 @@ static void printusage(void)
        "  -4              use only IPv4.\n"
        "                  Default: use both IPv4 and IPv6 waiting sockets\n\n"
        "  -l <host_list>  a file that contains a list of hosts that are allowed\n"
-       "                  to connect to this server (if more than one, list them one per line).\n"
-       "                  We suggest to use literal names (instead of numeric ones) in\n"
-       "                  order to avoid problems with different address families.\n\n"
+       "                  to connect to this server (if more than one, list them one\n"
+       "                  per line).\n"
+       "                  We suggest to use literal names (instead of numeric ones)\n"
+       "                  in order to avoid problems with different address families.\n\n"
        "  -n              permit NULL authentication (usually used with '-l')\n\n"
        "  -a <host,port>  run in active mode when connecting to 'host' on port 'port'\n"
        "                  In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
-       "  -v              run in active mode only (default: if '-a' is specified, it accepts\n"
-       "                  passive connections as well\n\n"
+       "  -v              run in active mode only (default: if '-a' is specified, it\n"
+       "                  accepts passive connections as well)\n\n"
        "  -d              run in daemon mode (UNIX only) or as a service (Win32 only)\n"
-       "                  Warning (Win32): this switch is provided automatically when the service\n"
-       "                  is started from the control panel\n\n"
+       "                  Warning (Win32): this switch is provided automatically when\n"
+       "                  the service is started from the control panel\n\n"
+#ifndef _WIN32
+       "  -i              run in inetd mode (UNIX only)\n\n"
+#endif
        "  -s <file>       save the current configuration to file\n\n"
        "  -f <file>       load the current configuration from file; all switches\n"
        "                  specified from the command line are ignored\n\n"
@@ -146,7 +159,10 @@ static void printusage(void)
 int main(int argc, char *argv[])
 {
        char savefile[MAX_LINE + 1];            // name of the file on which we have to save the configuration
-       int isdaemon = 0;                       // Not null if the user wants to run this program as a daemon
+       int isdaemon = 0;                       // Non-zero if the user wants to run this program as a daemon
+#ifndef _WIN32
+       int isrunbyinetd = 0;                   // Non-zero if this is being run by inetd or something inetd-like
+#endif
        int retval;                             // keeps the returning value from several functions
        char errbuf[PCAP_ERRBUF_SIZE + 1];      // keeps the error string, prior to be printed
 #ifndef _WIN32
@@ -177,7 +193,7 @@ int main(int argc, char *argv[])
        mainhints.ai_socktype = SOCK_STREAM;
 
        // Getting the proper command line options
-       while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1)
+       while ((retval = getopt(argc, argv, "b:dhip:4l:na:s:f:v")) != -1)
        {
                switch (retval)
                {
@@ -193,6 +209,14 @@ int main(int argc, char *argv[])
                        case 'd':
                                isdaemon = 1;
                                break;
+                       case 'i':
+#ifdef _WIN32
+                               printusage();
+                               exit(1);
+#else
+                               isrunbyinetd = 1;
+#endif
+                               break;
                        case 'n':
                                nullAuthAllowed = 1;
                                break;
@@ -244,13 +268,23 @@ int main(int argc, char *argv[])
                        case 'h':
                                printusage();
                                exit(0);
+                               break;
                        default:
+                               exit(1);
                                break;
                }
        }
 
+#ifndef _WIN32
+       if (isdaemon && isrunbyinetd)
+       {
+               fprintf(stderr, "rpcapd: -d and -i can't be used together\n");
+               exit(1);
+       }
+#endif
+
        if (savefile[0] && fileconf_save(savefile))
-                       SOCK_MESSAGE("Error when saving the configuration to file");
+               SOCK_MESSAGE("Error when saving the configuration to file");
 
        // If the file does not exist, it keeps the settings provided by the command line
        if (loadfile[0])
@@ -296,13 +330,86 @@ int main(int argc, char *argv[])
        signal(SIGPIPE, SIG_IGN);
 #endif
 
-       // forking a daemon, if it is needed
+#ifndef _WIN32
+       if (isrunbyinetd)
+       {
+               //
+               // -i was specified, indicating that this is being run
+               // by inetd or something that can run network daemons
+               // as if it were inetd (xinetd, launchd, systemd, etc.).
+               //
+               // Our standard input is the input side of a connection,
+               // and our standard output is the output side of a
+               // connection.
+               //
+               int sockctrl_in, sockctrl_out;
+               int devnull_fd;
+
+               //
+               // Duplicate the standard input and output, making them
+               // the input and output side of the control connection.
+               //
+               sockctrl_in = dup(0);
+               if (sockctrl_in == -1)
+               {
+                       sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE);
+                       rpcapd_log(LOGPRIO_ERROR, "Can't dup standard input: %s",
+                           errbuf);
+                       exit(2);
+               }
+               sockctrl_out = dup(1);
+               if (sockctrl_out == -1)
+               {
+                       sock_geterror(NULL, errbuf, PCAP_ERRBUF_SIZE);
+                       rpcapd_log(LOGPRIO_ERROR, "Can't dup standard output: %s",
+                           errbuf);
+                       exit(2);
+               }
+
+               //
+               // Try to set the standard input and output to /dev/null.
+               //
+               devnull_fd = open("/dev/null", O_RDWR);
+               if (devnull_fd != -1)
+               {
+                       //
+                       // If this fails, just drive on.
+                       //
+                       (void)dup2(devnull_fd, 0);
+                       (void)dup2(devnull_fd, 1);
+                       close(devnull_fd);
+               }
+
+               //
+               // Handle this client.
+               // This is passive mode, so we don't care whether we were
+               // told by the client to close.
+               //
+               (void)daemon_serviceloop(sockctrl_in, sockctrl_out, 0,
+                   nullAuthAllowed);
+
+               //
+               // Nothing more to do.
+               //
+               exit(0);
+       }
+#endif
+
        if (isdaemon)
        {
+               //
+               // This is being run as a daemon.
+               // On UN*X, it might be manually run, or run from an
+               // rc file.
+               //
 #ifndef _WIN32
                int pid;
 
+               //
+               // Daemonize ourselves.
+               //
                // Unix Network Programming, pg 336
+               //
                if ((pid = fork()) != 0)
                        exit(0);                // Parent terminates
 
@@ -329,7 +436,11 @@ int main(int argc, char *argv[])
 //             umask(0);
 //             chdir("/");
 #else
+               //
+               // This is being run as a service on Windows.
+               //
                // If this call succeeds, it is blocking on Win32
+               //
                if (svc_start() != 1)
                        SOCK_MESSAGE("Unable to start the service");
 
@@ -896,10 +1007,10 @@ accept_connection(SOCKET listen_sock)
 #ifdef _WIN32
        HANDLE threadId;                        // handle for the subthread
        u_long off = 0;
+       SOCKET *sockctrl_temp;
 #else
        pid_t pid;
 #endif
-       struct daemon_slpars *pars;     // parameters needed by the daemon_serviceloop()
 
        // Initialize errbuf
        memset(errbuf, 0, sizeof(errbuf));
@@ -971,9 +1082,15 @@ accept_connection(SOCKET listen_sock)
                return;
        }
 
-       // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
-       pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
-       if (pars == NULL)
+       //
+       // Allocate a location to hold the value of sockctrl.
+       // It will be freed in the newly-created thread once it's
+       // finished with it.
+       // I guess we *could* just cast sockctrl to a void *, but that's
+       // a bit ugly.
+       //
+       sockctrl_temp = (SOCKET *)malloc(sizeof (SOCKET));
+       if (sockctrl_temp == NULL)
        {
                pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
                    errno, "malloc() failed");
@@ -981,19 +1098,16 @@ accept_connection(SOCKET listen_sock)
                sock_close(sockctrl, NULL, 0);
                return;
        }
+       *sockctrl_temp = sockctrl;
 
-       pars->sockctrl = sockctrl;
-       pars->activeclose = 0;          // useless in passive mode
-       pars->isactive = 0;
-       pars->nullAuthAllowed = nullAuthAllowed;
-
-       threadId = (HANDLE)_beginthreadex(NULL, 0, daemon_serviceloop,
-           (void *) pars, 0, NULL);
+       threadId = (HANDLE)_beginthreadex(NULL, 0,
+           main_passive_serviceloop_thread, (void *) sockctrl_temp, 0, NULL);
        if (threadId == 0)
        {
                pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child thread");
                rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
                sock_close(sockctrl, NULL, 0);
+               free(sockctrl_temp);
                return;
        }
        CloseHandle(threadId);
@@ -1010,33 +1124,36 @@ accept_connection(SOCKET listen_sock)
        {
                //
                // Child process.
-               // This is passive mode, so this variable is deallocated
-               // by the daemon_serviceloop().
-               //
-               pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
-               if (pars == NULL)
-               {
-                       pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Can't allocate memory for the child process");
-                       rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
-                       sock_close(sockctrl, NULL, 0);
-                       return;
-               }
-
-               pars->sockctrl = sockctrl;
-               pars->activeclose = 0;          // useless in passive mode
-               pars->isactive = 0;
-               pars->nullAuthAllowed = nullAuthAllowed;
-
                //
                // Close the socket on which we're listening (must
                // be open only in the parent).
                //
                closesocket(listen_sock);
 
+#if 0
+               //
+               // Modify thread params so that it can be killed at any time
+               // XXX - is this necessary?  This is the main and, currently,
+               // only thread in the child process, and nobody tries to
+               // cancel us, although *we* may cancel the thread that's
+               // handling the capture loop.
+               //
+               if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
+                       goto end;
+               if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
+                       goto end;
+#endif
+
                //
                // Run the service loop.
+               // This is passive mode, so we don't care whether we were
+               // told by the client to close.
                //
-               daemon_serviceloop((void *) pars);
+               (void)daemon_serviceloop(sockctrl, sockctrl, 0,
+                   nullAuthAllowed);
+
+               close(sockctrl);
+
                exit(0);
        }
 
@@ -1067,7 +1184,6 @@ main_active(void *ptr)
        struct addrinfo hints;                  // temporary struct to keep settings needed to open the new socket
        struct addrinfo *addrinfo;              // keeps the addrinfo chain; required to open a new socket
        struct active_pars *activepars;
-       struct daemon_slpars *pars;             // parameters needed by the daemon_serviceloop()
 
        activepars = (struct active_pars *) ptr;
 
@@ -1112,24 +1228,10 @@ main_active(void *ptr)
                        continue;
                }
 
-               pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
-               if (pars == NULL)
-               {
-                       pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
-                           errno, "malloc() failed");
-                       continue;
-               }
-
-               pars->sockctrl = sockctrl;
-               pars->activeclose = 0;
-               pars->isactive = 1;
-               pars->nullAuthAllowed = nullAuthAllowed;
-
-               daemon_serviceloop((void *) pars);
-
-               activeclose = pars->activeclose;
+               activeclose = daemon_serviceloop(sockctrl, sockctrl, 1,
+                   nullAuthAllowed);
 
-               free(pars);
+               sock_close(sockctrl, NULL, 0);
 
                // If the connection is closed by the user explicitely, don't try to connect to it again
                // just exit the program
@@ -1140,3 +1242,27 @@ main_active(void *ptr)
        freeaddrinfo(addrinfo);
        return 0;
 }
+
+#ifdef _WIN32
+//
+// Main routine of a passive-mode service thread.
+//
+unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
+{
+       SOCKET sockctrl;
+
+       sockctrl = *((SOCKET *)ptr);
+       free(ptr);
+
+       //
+       // Handle this client.
+       // This is passive mode, so we don't care whether we were
+       // told by the client to close.
+       //
+       (void)daemon_serviceloop(sockctrl, sockctrl, 0, nullAuthAllowed);
+
+       sock_close(sockctrl, NULL, 0);
+
+       return 0;
+}
+#endif
index 4ef9c7e951ef2410ac6d992e82c11880855cdd5b..90ba7ffa712daab941d07acc0cc9727c2d587730 100755 (executable)
 #define __RPCAPD_H__
 
 #define PROGRAM_NAME "rpcapd"
-#define MAX_LINE 2048          /* Maximum chars allowed for the host list (in passive mode) */
 #define SOCKET_MAXCONN 10      /* Maximum number of connections queued into the accept() */
-#define MAX_HOST_LIST 64000
-#define MAX_ACTIVE_LIST 10
-
-struct active_pars
-{
-       char address[MAX_LINE + 1];     // keeps the network address (either numeric or literal) to of the active client
-       char port[MAX_LINE + 1];        // keeps the network port to bind to
-       int ai_family;                  // address faimly to use
-};
-
-extern char hostlist[MAX_HOST_LIST + 1];       //!< Keeps the list of the hosts that are allowed to connect to this server
-extern struct active_pars activelist[MAX_ACTIVE_LIST];         //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
-extern int nullAuthAllowed;                    //!< '1' if we permit NULL authentication, '0' otherwise
-extern char loadfile[MAX_LINE + 1];            //!< Name of the file from which we have to load the configuration
-
 #ifdef _WIN32
 void send_shutdown_notification(void); // Send notification to shut down the daemon
 void send_reread_configuration_notification(void);     // Send notification to re-read the configuration file