]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add the rpcap daemon source and build instructions.
authorGuy Harris <[email protected]>
Fri, 10 Mar 2017 23:48:58 +0000 (15:48 -0800)
committerGuy Harris <[email protected]>
Fri, 10 Mar 2017 23:48:58 +0000 (15:48 -0800)
16 files changed:
Makefile.in
configure
configure.ac
pcap.c
pcap/pcap.h
rpcap/.gitignore [new file with mode: 0644]
rpcap/Makefile.in [new file with mode: 0644]
rpcap/daemon.c [new file with mode: 0755]
rpcap/daemon.h [new file with mode: 0755]
rpcap/fileconf.c [new file with mode: 0755]
rpcap/fileconf.h [new file with mode: 0755]
rpcap/rpcapd.c [new file with mode: 0755]
rpcap/rpcapd.h [new file with mode: 0755]
rpcap/utils.c [new file with mode: 0755]
rpcap/utils.h [new file with mode: 0755]
rpcap/win32-svc.c [new file with mode: 0755]

index 5ba6b122859641e7649d4975e72b869249ac3ca2..8f2a12c0b7a06a2cc917d9f2d6ae5a32d29e79b5 100644 (file)
@@ -60,6 +60,7 @@ DYEXT = @DYEXT@
 V_RPATH_OPT = @V_RPATH_OPT@
 DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
 PROG=libpcap
+RPCAPD=@RPCAPD@
 
 # Standard CFLAGS
 FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
@@ -125,7 +126,11 @@ HDR = $(PUBHDR) \
        pcap-stdinc.h \
        portability.h \
        ppp.h \
+       rpcap/daemon.c \
+       rpcap/fileconf.c \
        rpcap/rpcap-protocol.h \
+       rpcap/rpcapd.c \
+       rpcap/utils.c \
        sf-pcap.h \
        sf-pcap-ng.h \
        sunatmpos.h
@@ -359,7 +364,7 @@ EXTRA_DIST = \
        Win32/Prj/wpcap.vcxproj \
        Win32/Prj/wpcap.vcxproj.filters
 
-all: libpcap.a shared pcap-config
+all: libpcap.a shared $(RPCAPD) pcap-config
 
 libpcap.a: $(OBJ)
        @rm -f $@
@@ -522,6 +527,12 @@ pcap-config: $(srcdir)/pcap-config.in ./config.status
        mv [email protected] $@
        chmod a+x $@
 
+#
+# Remote pcap daemon.
+#
+rpcapd: libpcap.a
+       cd rpcap; $(MAKE)
+
 #
 # Test programs - not built by default, and not installed.
 #
@@ -751,3 +762,5 @@ releasetar:
 
 depend:        $(GENSRC) $(GENHDR) bpf_filter.c
        $(MKDEP) -c $(CC) -m $(CFLAGS) $(DEPENDENCY_CFLAG) $(DEFS) $(INCLS) $(SRC)
+       cd rpcap; $(MAKE) depend
+
index f0d2fa241e530267ccbe862f7a6f61e3c7ef5361..3e552c504aca35a12a75f7f89c20c09513d72e00 100755 (executable)
--- a/configure
+++ b/configure
@@ -634,6 +634,7 @@ NETFILTER_SRC
 PCAP_SUPPORT_NETFILTER
 USB_SRC
 PCAP_SUPPORT_USB
+RPCAPD
 MAN_USERMOD_SECTION
 MAN_MISC_INFO
 MAN_FILE_FORMATS
@@ -7265,6 +7266,7 @@ $as_echo "$as_me: WARNING: to attacks by malicious remote capture servers!" >&2;
 $as_echo "#define HAVE_REMOTE /**/" >>confdefs.h
 
        SSRC="$SSRC pcap-new.c pcap-rpcap.c sockutils.c"
+       RPCAPD=rpcapd
        ;;
 *)     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
@@ -8447,6 +8449,7 @@ ln -s ${srcdir}/bpf/net net
 
 
 
+
 
 # Check whether --enable-usb was given.
 if test "${enable_usb+set}" = set; then :
@@ -9084,7 +9087,7 @@ ac_config_headers="$ac_config_headers config.h"
 
 ac_config_commands="$ac_config_commands default-1"
 
-ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap"
+ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcap/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -9803,6 +9806,7 @@ do
     "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;;
     "pcap_set_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_precision.3pcap" ;;
     "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;;
+    "rpcap/Makefile") CONFIG_FILES="$CONFIG_FILES rpcap/Makefile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
index 51c672456c2e189bd5d890d8a86a5a3d4aba0d98..7c5f0c6f1378e0119b3fc2cb371abf8a2d9bbb35 100644 (file)
@@ -1204,6 +1204,7 @@ yes)      AC_MSG_RESULT(yes)
        AC_DEFINE(HAVE_REMOTE,,
            [Define to 1 if remote packet capture is to be supported])
        SSRC="$SSRC pcap-new.c pcap-rpcap.c sockutils.c"
+       RPCAPD=rpcapd
        ;;
 *)     AC_MSG_RESULT(no)
        ;;
@@ -1509,6 +1510,7 @@ AC_SUBST(DYEXT)
 AC_SUBST(MAN_FILE_FORMATS)
 AC_SUBST(MAN_MISC_INFO)
 AC_SUBST(MAN_USERMOD_SECTION)
+AC_SUBST(RPCAPD)
 
 AC_ARG_ENABLE([usb],
 [AC_HELP_STRING([--enable-usb],[enable nusb support @<:@default=yes, if support available@:>@])],
@@ -1854,5 +1856,5 @@ AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc
        pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap
        pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap
        pcap_open_offline.3pcap pcap_set_tstamp_precision.3pcap
-       pcap_set_tstamp_type.3pcap)
+       pcap_set_tstamp_type.3pcap rpcap/Makefile)
 exit 0
diff --git a/pcap.c b/pcap.c
index 12637f27e538ecfa4de816ec25fdea9ecd2171bc..53151724d7d10ab01972b36c7d2c797905ab018e 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -2209,6 +2209,14 @@ pcap_minor_version(pcap_t *p)
        return (p->version_minor);
 }
 
+int
+pcap_bufsize(pcap_t *p)
+{
+       if (!p->activated)
+               return (PCAP_ERROR_NOT_ACTIVATED);
+       return (p->bufsize);
+}
+
 FILE *
 pcap_file(pcap_t *p)
 {
index 36606acc829e640b3d2710fddde53c96aa13b89a..29899bc0ffe5c99eb9f00c082fd23d4e10746194 100644 (file)
@@ -409,6 +409,7 @@ PCAP_API int        pcap_snapshot(pcap_t *);
 PCAP_API int   pcap_is_swapped(pcap_t *);
 PCAP_API int   pcap_major_version(pcap_t *);
 PCAP_API int   pcap_minor_version(pcap_t *);
+PCAP_API int   pcap_bufsize(pcap_t *);
 
 /* XXX */
 PCAP_API FILE  *pcap_file(pcap_t *);
diff --git a/rpcap/.gitignore b/rpcap/.gitignore
new file mode 100644 (file)
index 0000000..42eca57
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+*~
+*.o
+rpcapd
diff --git a/rpcap/Makefile.in b/rpcap/Makefile.in
new file mode 100644 (file)
index 0000000..6b785ff
--- /dev/null
@@ -0,0 +1,116 @@
+#  Copyright (c) 1993, 1994, 1995, 1996
+#      The Regents of the University of California.  All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that: (1) source code distributions
+#  retain the above copyright notice and this paragraph in its entirety, (2)
+#  distributions including binary code include the above copyright notice and
+#  this paragraph in its entirety in the documentation or other materials
+#  provided with the distribution, and (3) all advertising materials mentioning
+#  features or use of this software display the following acknowledgement:
+#  ``This product includes software developed by the University of California,
+#  Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+#  the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+#
+# Various configurable paths (remember to edit Makefile.in, not Makefile)
+#
+
+# Top level hierarchy
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
+# Pathname of directory to install the configure program
+bindir = @bindir@
+# Pathname of directory to install the include files
+includedir = @includedir@
+# Pathname of directory to install the library
+libdir =  @libdir@
+# Pathname of directory to install the man pages
+mandir = @mandir@
+
+# VPATH
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+#
+# You shouldn't need to edit anything below.
+#
+
+LD = /usr/bin/ld
+CC = @CC@
+AR = @AR@
+LN_S = @LN_S@
+MKDEP = @MKDEP@
+CCOPT = @V_CCOPT@
+INCLS = -I. -I.. @V_INCLS@
+DEFS = -DBUILDING_PCAP @DEFS@ @V_DEFS@
+ADDLOBJS = @ADDLOBJS@
+ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@
+LIBS = @LIBS@
+CROSSFLAGS=
+CFLAGS = @CFLAGS@   ${CROSSFLAGS}
+LDFLAGS = @LDFLAGS@ ${CROSSFLAGS}
+DYEXT = @DYEXT@
+V_RPATH_OPT = @V_RPATH_OPT@
+DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@
+PROG=libpcap
+
+# Standard CFLAGS
+FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS)
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+# Explicitly define compilation rule since SunOS 4's make doesn't like gcc.
+# Also, gcc does not remove the .o before forking 'as', which can be a
+# problem if you don't own the file but can write to the directory.
+.c.o:
+       @rm -f $@
+       $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
+
+SRC =  daemon.c \
+       fileconf.c \
+       rpcapd.c \
+       utils.c
+
+OBJ =  $(SRC:.c=.o)
+PUBHDR =
+
+HDR = $(PUBHDR)
+
+TAGFILES = \
+       $(SRC) $(HDR)
+
+CLEANFILES = $(OBJ) rpcapd
+
+MAN8 =
+
+
+EXTRA_DIST = \
+       CMakeLists.txt \
+       Makefile.in \
+       Makefile-devel-adds
+
+rpcapd: $(OBJ)
+       $(CC) -o $@ $(OBJ) ../libpcap.a
+clean:
+       rm -f $(CLEANFILES)
+
+distclean: clean
+       rm -f Makefile config.cache config.log config.status \
+           config.h gnuc.h net os-proto.h bpf_filter.c pcap-config \
+           stamp-h stamp-h.in
+       rm -rf autom4te.cache
+
+tags: $(TAGFILES)
+       ctags -wtd $(TAGFILES)
+
+depend:
+       ../$(MKDEP) -c $(CC) -m $(CFLAGS) $(DEPENDENCY_CFLAG) $(DEFS) $(INCLS) $(SRC)
diff --git a/rpcap/daemon.c b/rpcap/daemon.c
new file mode 100755 (executable)
index 0000000..8b6be0a
--- /dev/null
@@ -0,0 +1,1603 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <pcap.h>              // for libpcap/WinPcap calls
+#include <errno.h>             // for the errno variable
+#include <stdlib.h>            // for malloc(), free(), ...
+#include <string.h>            // for strlen(), ...
+#include <pthread.h>
+#include "sockutils.h"         // for socket calls
+#include "rpcap-protocol.h"
+#include "pcap-rpcap.h"
+#include "daemon.h"
+
+#ifndef _WIN32                 // for select() and such
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pwd.h>               // for password management
+#endif
+
+#ifdef linux
+#include <shadow.h>            // for password management
+#endif
+
+#define RPCAP_TIMEOUT_INIT 90          /* Initial timeout for RPCAP connections (default: 90 sec) */
+#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 */
+
+/*
+ * Data for a session managed by a thread.
+ */
+struct session {
+       SOCKET sockctrl;
+       SOCKET sockdata;
+       pcap_t *fp;
+       unsigned int TotCapt;
+};
+
+// Locally defined functions
+static int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf);
+static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
+
+static int daemon_findalldevs(SOCKET sockctrl, char *errbuf);
+
+static int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf);
+static struct session *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active, 
+    struct rpcap_sampling *samp_param, uint32 plen, char *errbuf);
+static int daemon_endcapture(struct session *session, pthread_t *threaddata, char *errbuf);
+
+static int daemon_updatefilter(struct session *session, uint32 plen);
+static int daemon_unpackapplyfilter(struct session *session, uint32 *totread, uint32 *plen, char *errbuf);
+
+static int daemon_getstats(struct session *session);
+static int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv, 
+                                                 unsigned int krnldrop, unsigned int svrcapt, char *errbuf);
+
+static int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf);
+
+static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage *sockaddrout);
+static void *daemon_thrdatamain(void *ptr);
+
+/*!
+       \brief Main serving funtion
+       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 corrisponding to this thread. This variable is casted into a 'pthread_chain'
+       value in order to retrieve the socket we're currently using, the therad ID, and 
+       some pointers to the previous and next elements into this struct.
+
+       \return None.
+*/
+void daemon_serviceloop( void *ptr )
+{
+       char errbuf[PCAP_ERRBUF_SIZE + 1];              // keeps the error string, prior to be printed
+       char source[PCAP_BUF_SIZE];                             // keeps the string that contains the interface to open
+       struct rpcap_header header;                             // RPCAP message general header
+       struct session *session = NULL;                         // struct session main variable
+       struct daemon_slpars *pars;                             // parameters related to the present daemon loop
+
+       pthread_t threaddata= 0;                                // handle to the 'read from daemon and send to client' thread
+
+       unsigned int ifdrops, ifrecv, krnldrop, svrcapt;        // needed to save the values of the statistics
+
+       struct rpcap_sampling samp_param;               // in case sampling has been requested
+
+       // Structures needed for the select() call
+       fd_set rfds;                                            // set of socket descriptors we have to check
+       struct timeval tv;                                      // maximum time the select() can block waiting for data
+       int retval;                                                     // select() return value
+
+
+       pars= (struct daemon_slpars *) ptr;
+       
+       *errbuf= 0;     // Initialize errbuf
+
+       // 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;
+       }
+
+auth_again:
+       // If we're in active mode, we have to check for the initial timeout
+       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);
+
+               retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
+               if (retval == -1)
+               {
+                       sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, NULL);
+                       goto end;
+               }
+
+               // The timeout has expired
+               // So, this was a fake connection. Drop it down
+               if (retval == 0)
+               {
+                       rpcap_senderror(pars->sockctrl, "The RPCAP initial timeout has expired", PCAP_ERR_INITTIMEOUT, NULL);
+                       goto end;
+               }
+       }
+
+
+       retval= daemon_checkauth(pars->sockctrl, pars->nullAuthAllowed, errbuf);
+
+       if (retval)
+       {
+               // the other user requested to close the connection
+               // It can be also the case of 'active mode', in which this host is not
+               // allowed to connect to the other peer; in that case, it drops down the connection
+               if (retval == -3) 
+                       goto end;
+
+               // It can be an authentication failure or an unrecoverable error
+               rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_AUTH, NULL);
+
+               // authentication error
+               if (retval == -2)
+               {
+                       // suspend for 1 sec
+                       // WARNING: this day is inserted only in this point; if the user drops down the connection
+                       // and it connects again, this suspension time does not have any effects.
+                       pthread_suspend(RPCAP_SUSPEND_WRONGAUTH*1000);
+                       goto auth_again;
+               }
+
+                // Unrecoverable error
+               if (retval == -1)
+                       goto end;
+       }
+
+       while (1)
+       {
+               errbuf[0]= 0;   // clear errbuf
+
+               // Avoid zombies connections; check if the connection is opens but no commands are performed
+               // from more than RPCAP_TIMEOUT_RUNTIME
+               // Conditions:
+               // - I have to be in normal mode (no active mode)
+               // - if the device is open, I don't have to be in the middle of a capture (session->sockdata)
+               // - if the device is closed, I have always to check if a new command arrives
+               //
+               // 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) ) ))
+               {
+                       // Check for the initial timeout
+                       FD_ZERO(&rfds);
+                       // We do not have to block here
+                       tv.tv_sec = RPCAP_TIMEOUT_RUNTIME;
+                       tv.tv_usec = 0;
+                       
+                       FD_SET(pars->sockctrl, &rfds);
+
+                       retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
+                       if (retval == -1)
+                       {
+                               sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE);
+                               rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, NULL);
+                               goto end;
+                       }
+
+                       // The timeout has expired
+                       // So, this was a fake connection. Drop it down
+                       if (retval == 0)
+                       {
+                               SOCK_ASSERT("The RPCAP runtime timeout has expired", 1);
+                               rpcap_senderror(pars->sockctrl, "The RPCAP runtime timeout has expired", PCAP_ERR_RUNTIMETIMEOUT, NULL);
+                               goto end;
+                       }
+               }
+
+               if (sock_recv(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto end;
+
+               // Checks if the message is correct
+               // In case it is wrong, it discard the data
+               retval= rpcap_checkmsg(errbuf, pars->sockctrl, &header,
+                       RPCAP_MSG_FINDALLIF_REQ,
+                       RPCAP_MSG_OPEN_REQ,
+                       RPCAP_MSG_STARTCAP_REQ,
+                       RPCAP_MSG_UPDATEFILTER_REQ,
+                       RPCAP_MSG_STATS_REQ,
+                       RPCAP_MSG_ENDCAP_REQ,
+                       RPCAP_MSG_SETSAMPLING_REQ,
+                       RPCAP_MSG_CLOSE,
+                       RPCAP_MSG_ERROR,
+                       0);
+
+               switch (retval)
+               {
+                       case -3:        // Unrecoverable network error
+                               goto end;       // Do nothing; just exit from findalldevs; the error code is already into the errbuf
+
+                       case -2:        // The other endpoint send a message that is not allowed here
+                       {
+                               rpcap_senderror(pars->sockctrl, "The RPCAP daemon received a message that is not valid", PCAP_ERR_WRONGMSG, errbuf);
+                       }
+                       case -1:        // The other endpoint has a version number that is not compatible with our
+                       {
+                               rpcap_senderror(pars->sockctrl, "RPCAP version number mismatch", PCAP_ERR_WRONGVER, errbuf);
+                       }
+                       break;
+
+                       case RPCAP_MSG_FINDALLIF_REQ:
+                       {
+                               // Checks that the header does not contain other data; if so, discard it
+                               if (ntohl(header.plen))
+                                       sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE);
+
+                               if (daemon_findalldevs(pars->sockctrl, errbuf) )
+                                       SOCK_ASSERT(errbuf, 1);
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_OPEN_REQ:
+                       {
+                               retval= daemon_opensource(pars->sockctrl, source, sizeof(source), ntohl(header.plen), errbuf);
+
+                               if (retval == -1)
+                                       SOCK_ASSERT(errbuf, 1);
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_SETSAMPLING_REQ:
+                       {
+                               retval= daemon_setsampling(pars->sockctrl, &samp_param, ntohl(header.plen), errbuf);
+
+                               if (retval == -1)
+                                       SOCK_ASSERT(errbuf, 1);
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_STARTCAP_REQ:
+                       {
+                               session = daemon_startcapture(pars->sockctrl, &threaddata, source, pars->isactive, &samp_param, ntohl(header.plen), errbuf);
+
+                               if (session == NULL)
+                                       SOCK_ASSERT(errbuf, 1);
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_UPDATEFILTER_REQ:
+                       {
+                               if (session)
+                               {
+                                       if (daemon_updatefilter(session, ntohl(header.plen)) )
+                                               SOCK_ASSERT(pcap_geterr(session->fp), 1);
+                               }
+                               else
+                               {
+                                       rpcap_senderror(pars->sockctrl, "Device not opened. Cannot update filter", PCAP_ERR_UPDATEFILTER, errbuf);
+                               }
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_STATS_REQ:
+                       {
+                               // Checks that the header does not contain other data; if so, discard it
+                               if (ntohl(header.plen))
+                                       sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE);
+
+                               if (session && session->fp)
+                               {
+                                       if (daemon_getstats(session) )
+                                               SOCK_ASSERT(pcap_geterr(session->fp), 1);
+                               }
+                               else
+                               {
+                                       SOCK_ASSERT("GetStats: this call should't be allowed here", 1);
+
+                                       if (daemon_getstatsnopcap(pars->sockctrl, ifdrops, ifrecv, krnldrop, svrcapt, errbuf) )
+                                               SOCK_ASSERT(errbuf, 1);
+                                       // we have to keep compatibility with old applications, which ask for statistics
+                                       // also when the capture has already stopped
+
+//                                     rpcap_senderror(pars->sockctrl, "Device not opened. Cannot get statistics", PCAP_ERR_GETSTATS, errbuf);
+                               }
+
+                               break;
+                       };
+
+                       case RPCAP_MSG_ENDCAP_REQ:              // The other endpoint close the current capture session
+                       {
+                               if (session && session->fp)
+                               {
+                                       struct pcap_stat stats;
+
+                                       // Save statistics (we can need them in the future)
+                                       if (pcap_stats(session->fp, &stats) )
+                                       {
+                                               ifdrops= stats.ps_ifdrop;
+                                               ifrecv= stats.ps_recv;
+                                               krnldrop= stats.ps_drop;
+                                               svrcapt= session->TotCapt;
+                                       }
+                                       else
+                                               ifdrops= ifrecv= krnldrop= svrcapt= 0;
+
+                                       if ( daemon_endcapture(session, &threaddata, errbuf) )
+                                               SOCK_ASSERT(pcap_geterr(session->fp), 1);
+                                       free(session);
+                                       session = NULL;
+                               }
+                               else
+                               {
+                                       rpcap_senderror(pars->sockctrl, "Device not opened. Cannot close the capture", PCAP_ERR_ENDCAPTURE, errbuf);
+                               }
+                               break;
+                       };
+
+                       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;   
+                               SOCK_ASSERT("The other end system asked to close the connection.", 1);
+                               goto end;
+                               break;
+                       };
+
+                       case RPCAP_MSG_ERROR:           // The other endpoint reported an error
+                       {
+                               // Do nothing; just exit; the error code is already into the errbuf
+                               SOCK_ASSERT(errbuf, 1);
+                               break;
+                       };
+
+                       default:
+                       {
+                               SOCK_ASSERT("Internal error.", 1);
+                               break;
+                       };
+               }
+       }
+
+end:
+       // The child thread is about to end
+
+       // perform pcap_t cleanup, in case it has not been done
+       if (session)
+       {
+               if (threaddata)
+               {
+                       pthread_cancel(threaddata);
+                       threaddata= 0;
+               }
+               if (session->sockdata)
+               {
+                       sock_close(session->sockdata, NULL, 0);
+                       session->sockdata= 0;
+               }
+               pcap_close(session->fp);
+               free(session);
+               session = NULL;
+       }
+
+       // Print message and exit
+       SOCK_ASSERT("I'm exiting from the child loop", 1);
+       SOCK_ASSERT(errbuf, 1);
+
+       if (!pars->isactive)
+       {
+               if (pars->sockctrl)
+                       sock_close(pars->sockctrl, NULL, 0);
+               
+               free(pars);
+#ifdef _WIN32
+               pthread_exit(0);
+#endif
+       }
+}
+
+/*!
+       \brief It checks if the authentication credentials supplied by the user are valid.
+
+       This function is called each time the rpcap daemon starts a new serving thread.
+       It reads the authentication message from the network and it checks that the 
+       user information are valid.
+
+       \param sockctrl: the socket if of the control connection.
+       
+       \param nullAuthAllowed: '1' if the NULL authentication is allowed.
+
+       \param errbuf: a user-allocated buffer in which the error message (if one) has to be written.
+
+       \return '0' if everything is fine, '-1' if an unrecoverable error occurred.
+       The error message is returned in the 'errbuf' variable.
+       '-2' is returned in case the authentication failed or in case of a recoverable error (like
+       wrong version). In that case, 'errbuf' keeps the reason of the failure. This provides
+       a way to know that the connection does not have to be closed.
+
+       In case the message is a 'CLOSE' or an 'ERROR', it returns -3. The error can be due to a
+       connection refusal in active mode, since this host cannot be allowed to connect to the remote
+       peer.
+*/
+int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf)
+{
+       struct rpcap_header header;     // RPCAP message general header
+       int retval;                     // generic return value
+       uint32 totread = 0;             // number of bytes of the payload read from the socket
+       ssize_t nread;
+       struct rpcap_auth auth;         // RPCAP authentication header
+       char *string1, *string2;        // two strings exchanged by the authentication message
+       unsigned int plen;              // length of the payload
+       int retcode;                    // the value we have to return to the caller
+
+       if (sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               return -1;
+
+       plen= ntohl(header.plen);
+
+       retval= rpcap_checkmsg(errbuf, sockctrl, &header,
+               RPCAP_MSG_AUTH_REQ,
+               RPCAP_MSG_CLOSE,
+               0);
+
+       if (retval != RPCAP_MSG_AUTH_REQ)
+       {
+               switch (retval)
+               {
+                       case -3:        // Unrecoverable network error
+                               return -1;      // Do nothing; just exit; the error code is already into the errbuf
+
+                       case -2:        // The other endpoint send a message that is not allowed here
+                       case -1:        // The other endpoint has a version number that is not compatible with our
+                               return -2;
+
+                       case RPCAP_MSG_CLOSE:
+                       {
+                               // Check if all the data has been read; if not, discard the data in excess
+                               if (ntohl(header.plen) )
+                               {
+                                       if (sock_discard(sockctrl, ntohl(header.plen), NULL, 0) )
+                                               return -1;
+                               }               
+                               return -3;
+                       };
+
+                       case RPCAP_MSG_ERROR:
+                               return -3;
+
+                       default:
+                       {
+                               SOCK_ASSERT("Internal error.", 1);
+                               retcode= -2;
+                               goto error;
+                       };
+               }
+       }
+
+       // If it comes here, it means that we have an authentication request message
+       nread = sock_recv(sockctrl, (char *) &auth, sizeof(struct rpcap_auth),
+           SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
+       if (nread == -1)
+       {
+               retcode= -1;
+               goto error;
+       }
+       totread += nread;
+
+       switch (ntohs(auth.type) )
+       {
+               case RPCAP_RMTAUTH_NULL:
+               {
+                       if (!nullAuthAllowed)
+                       {
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed; NULL autentication not permitted.");
+                               retcode= -2;
+                               goto error;
+                       }
+                       break;
+               }
+
+               case RPCAP_RMTAUTH_PWD:
+               {
+               int len1, len2;
+
+                       len1= ntohs(auth.slen1);
+                       len2= ntohs(auth.slen2);
+
+                       string1= (char *) malloc (len1 + 1);
+                       string2= (char *) malloc (len2 + 1);
+
+                       if ( (string1 == NULL) || (string2 == NULL) )
+                       {
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
+                               retcode= -1;
+                               goto error;
+                       }
+
+                       nread = sock_recv(sockctrl, string1, len1,
+                           SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
+                       if (nread == -1)
+                       {
+                               retcode= -1;
+                               goto error;
+                       }
+                       totread = nread;
+                       nread = sock_recv(sockctrl, string2, len2,
+                           SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
+                       if (nread == -1)
+                       {
+                               retcode= -1;
+                               goto error;
+                       }
+                       totread += nread;
+
+                       string1[len1]= 0;
+                       string2[len2]= 0;
+
+                       if (daemon_AuthUserPwd(string1, string2, errbuf) )
+                       {
+                               retcode= -2;
+                               goto error;
+                       }
+
+                       break;
+                       }
+
+               default:
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
+                       retcode= -2;
+                       goto error;
+       }
+
+
+       // Check if all the data has been read; if not, discard the data in excess
+       if (totread != plen)
+       {
+               if (sock_discard(sockctrl, plen - totread, NULL, 0) )
+               {
+                       retcode= -1;
+                       goto error;
+               }
+       }
+
+       rpcap_createhdr(&header, 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)
+       {
+               retcode= -1;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       // Check if all the data has been read; if not, discard the data in excess
+       if (totread != plen)
+               sock_discard(sockctrl, plen - totread, NULL, 0);
+
+       return retcode;
+}
+
+int daemon_AuthUserPwd(char *username, char *password, char *errbuf)
+{
+#ifdef _WIN32
+       /*
+               Warning: the user which launches the process must have the SE_TCB_NAME right.
+               This corresponds to have the "Act as part of the Operating System" turined on
+               (administrative tools, local security settings, local policies, user right assignment)
+               However, it seems to me that if you run it as a service, this right should be
+               provided by default.
+       */
+       HANDLE Token;
+       if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
+       {
+       int error;
+
+               error = GetLastError();
+               FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
+                       PCAP_ERRBUF_SIZE, NULL);
+
+               return -1;
+       }
+
+       // This call should change the current thread to the selected user.
+       // I didn't test it.
+       if (ImpersonateLoggedOnUser(Token) == 0)
+       {
+       int error;
+
+               error = GetLastError();
+               FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
+                       PCAP_ERRBUF_SIZE, NULL);
+
+               CloseHandle(Token);
+               return -1;
+       }
+
+       CloseHandle(Token);
+       return 0;
+
+#else
+/*     Standard user authentication:
+               http://www.unixpapa.com/incnote/passwd.html
+       Problem: it is not able to merge the standard pwd file with the shadow one
+
+       Shadow user authentication:
+               http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
+       Problem: the program must either (1) run as root, or (2) run as user, but it
+       must be owned by root and must be SUID root (chmod u+s rpcapd)
+*/
+
+       struct passwd *user;
+#ifdef linux
+       struct spwd *usersp;
+#endif
+
+       // This call is needed to get the uid
+       if ((user= getpwnam(username)) == NULL)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
+               return -1;
+       }
+
+#ifdef linux
+       // This call is needed to get the password; otherwise 'x' is returned
+       if ((usersp= getspnam(username)) == NULL)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
+               return -1;
+       }
+       
+       if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp) ) != 0)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
+               return -1;
+       }
+#endif
+
+#ifdef bsd
+       if (strcmp(user->pw_passwd, (char *) crypt(password, user->pw_passwd) ) != 0)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
+               return -1;
+       }
+#endif
+
+       if (setuid(user->pw_uid) )
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
+               return -1;
+       }
+
+/*     if (setgid(user->pw_gid) )
+       {
+               SOCK_ASSERT("setgid failed", 1);
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
+               return -1;
+       }
+*/
+       return 0;
+
+#endif
+
+}
+
+// PORTING WARNING We assume u_int is a 32bit value
+int daemon_findalldevs(SOCKET sockctrl, char *errbuf)
+{
+       char sendbuf[RPCAP_NETBUF_SIZE];                        // temporary buffer in which data to be sent is buffered
+       int sendbufidx= 0;                                                      // index which keeps the number of bytes currently buffered
+       pcap_if_t *alldevs;                                                     // pointer to the heade of the interface chain
+       pcap_if_t *d;                                                           // temp pointer neede to scan the interface chain
+       uint16 plen= 0;                                                         // length of the payload of this message
+       struct pcap_addr *address;                                      // pcap structure that keeps a network address of an interface
+       struct rpcap_findalldevs_if *findalldevs_if;// rpcap structure that packet all the data of an interface together
+       uint16 nif= 0;                                                          // counts the number of interface listed
+
+       // Retrieve the device list
+       if (pcap_findalldevs(&alldevs, errbuf) == -1)
+       {
+               rpcap_senderror(sockctrl, errbuf, PCAP_ERR_FINDALLIF, NULL);
+               return -1;
+       }
+
+       if (alldevs == NULL)
+       {
+               rpcap_senderror(sockctrl,
+                       "No interfaces found! Make sure libpcap/WinPcap is properly installed"
+                       " and you have the right to access to the remote device.",
+                       PCAP_ERR_NOREMOTEIF, 
+                       errbuf);
+               return -1;
+       }
+
+       // checks the number of interfaces and it computes the total length of the payload
+       for (d= alldevs; d != NULL; d= d->next)
+       {
+               nif++;
+
+               if (d->description)
+                       plen+= strlen(d->description);
+               if (d->name)
+                       plen+= strlen(d->name);
+
+               plen+= sizeof(struct rpcap_findalldevs_if);
+
+               for (address= d->addresses; address != NULL; address= address->next)
+                       plen+= ( sizeof(struct sockaddr_storage) * 4);
+       }
+
+       // RPCAP findalldevs command
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, 
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               return -1;
+
+       rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_FINDALLIF_REPLY, nif, plen);
+
+       // send the interface list
+       for (d= alldevs; d != NULL; d= d->next)
+       {
+       uint16 lname, ldescr;
+
+               findalldevs_if= (struct rpcap_findalldevs_if *) &sendbuf[sendbufidx];
+
+               if ( sock_bufferize(NULL, sizeof(struct rpcap_findalldevs_if), NULL,
+                       &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       return -1;
+
+               memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if) );
+
+               if (d->description) ldescr= (short) strlen(d->description);
+               else ldescr= 0;
+               if (d->name) lname= (short) strlen(d->name);
+               else lname= 0;
+
+               findalldevs_if->desclen= htons(ldescr);
+               findalldevs_if->namelen= htons(lname);
+               findalldevs_if->flags= htonl(d->flags);
+
+               for (address= d->addresses; address != NULL; address= address->next)
+                       findalldevs_if->naddr++;
+
+               findalldevs_if->naddr= htons(findalldevs_if->naddr);
+
+               if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx, 
+                       RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       return -1;
+
+               if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx,
+                       RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       return -1;
+
+               // send all addresses
+               for (address= d->addresses; address != NULL; address= address->next)
+               {
+               struct sockaddr_storage *sockaddr;
+
+                       sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx];
+                       if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 
+                               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                               return -1;
+                       daemon_seraddr( (struct sockaddr_storage *) address->addr, sockaddr);
+
+                       sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx];
+                       if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 
+                               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                               return -1;
+                       daemon_seraddr( (struct sockaddr_storage *) address->netmask, sockaddr);
+
+                       sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx];
+                       if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL,
+                               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                               return -1;
+                       daemon_seraddr( (struct sockaddr_storage *) address->broadaddr, sockaddr);
+
+                       sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx];
+                       if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL,
+                               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                               return -1;
+                       daemon_seraddr( (struct sockaddr_storage *) address->dstaddr, sockaddr);
+               }
+       }
+
+       // Send a final command that says "now send it!"
+       if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               return -1;
+
+       // We do no longer need the device list. Free it
+       pcap_freealldevs(alldevs);
+
+       // everything is fine
+       return 0;
+}
+
+/*
+       \param plen: the length of the current message (needed in order to be able
+       to discard excess data in the message, if present)
+*/
+static int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf)
+{
+       pcap_t *fp= NULL;                       // pcap_t main variable
+       uint32 totread;                         // number of bytes of the payload read from the socket
+       ssize_t nread;
+       char sendbuf[RPCAP_NETBUF_SIZE];        // temporary buffer in which data to be sent is buffered
+       int sendbufidx= 0;                      // index which keeps the number of bytes currently buffered
+       struct rpcap_openreply *openreply;      // open reply message
+
+       strcpy(source, PCAP_SRC_IF_STRING);
+
+       if (srclen <= (int) (strlen(PCAP_SRC_IF_STRING) + plen) )
+       {
+               rpcap_senderror(sockctrl, "Source string too long", PCAP_ERR_OPEN, NULL);
+               return -1;
+       }
+
+       nread = sock_recv(sockctrl, &source[strlen(PCAP_SRC_IF_STRING)], plen,
+           SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
+       if (nread == -1)
+               return -1;
+       totread = nread;
+
+       // Check if all the data has been read; if not, discard the data in excess
+       if (totread != plen)
+               sock_discard(sockctrl, plen - totread, NULL, 0);
+
+       // Puts a '0' to terminate the source string
+       source[strlen(PCAP_SRC_IF_STRING) + plen]= 0;
+
+       // Open the selected device
+       // This is a fake open, since we do that only to get the needed parameters, then we close the device again
+       if ( (fp= pcap_open_live(source, 
+                       1500 /* fake snaplen */,
+                       0 /* no promis */, 
+                       1000 /* fake timeout */,
+                       errbuf)) == NULL)
+       {
+               rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, NULL);
+               return -1;
+       }
+
+
+       // Now, I can send a RPCAP open reply message
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
+               RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply) );
+
+       openreply= (struct rpcap_openreply *) &sendbuf[sendbufidx];
+       
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx, 
+               RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       memset(openreply, 0, sizeof(struct rpcap_openreply) );
+       openreply->linktype = htonl(pcap_datalink(fp));
+       openreply->tzoff = 0; /* This is always 0 for live captures */
+
+       if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       // I have to close the device again, since it has been opened with wrong parameters
+       pcap_close(fp);
+       fp= NULL;
+
+       return 0;
+
+error:
+       if (fp)
+       {
+               pcap_close(fp);
+               fp= NULL;
+       }
+
+       return -1;
+}
+
+/*
+       \param plen: the length of the current message (needed in order to be able
+       to discard excess data in the message, if present)
+*/
+static struct session *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active, struct rpcap_sampling *samp_param, uint32 plen, char *errbuf)
+{
+       char portdata[PCAP_BUF_SIZE];           // temp variable needed to derive the data port
+       char peerhost[PCAP_BUF_SIZE];           // temp variable needed to derive the host name of our peer
+       struct session *session;                // saves state of session
+       uint32 totread;                         // number of bytes of the payload read from the socket
+       ssize_t nread;
+       char sendbuf[RPCAP_NETBUF_SIZE];        // temporary buffer in which data to be sent is buffered
+       int sendbufidx= 0;                                      // index which keeps the number of bytes currently buffered
+
+       // socket-related variables
+       SOCKET sockdata= 0;                                     // socket descriptor of the data connection
+       struct addrinfo hints;                          // temp, needed to open a socket connection
+       struct addrinfo *addrinfo;                      // temp, needed to open a socket connection
+       struct sockaddr_storage saddr;          // temp, needed to retrieve the network data port chosen on the local machine
+       socklen_t saddrlen;                                     // temp, needed to retrieve the network data port chosen on the local machine
+
+       pthread_attr_t detachedAttribute;       // temp, needed to set the created thread as detached
+
+       // RPCAP-related variables
+       struct rpcap_startcapreq startcapreq;           // start capture request message
+       struct rpcap_startcapreply *startcapreply;      // start capture reply message
+       int serveropen_dp;                                                      // keeps who is going to open the data connection
+
+       addrinfo= NULL;
+
+       nread = sock_recv(sockctrl, (char *) &startcapreq,
+           sizeof(struct rpcap_startcapreq), SOCK_RECEIVEALL_YES,
+           errbuf, PCAP_ERRBUF_SIZE);
+       if (nread == -1)
+               return NULL;
+       totread = nread;
+
+       startcapreq.flags= ntohs(startcapreq.flags);
+
+       // Create a session structure
+       session = malloc(sizeof(struct session));
+       if (session == NULL) {
+               rpcap_senderror(sockctrl, "Can't allocate session structure",
+                   PCAP_ERR_OPEN, NULL);
+               return NULL;
+       }
+
+       // Open the selected device
+       if ( (session->fp= pcap_open(source, 
+                       ntohl(startcapreq.snaplen),
+                       (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? PCAP_OPENFLAG_PROMISCUOUS : 0 /* local device, other flags not needed */, 
+                       ntohl(startcapreq.read_timeout),
+                       NULL /* local device, so no auth */,
+                       errbuf)) == NULL)
+       {
+               rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, NULL);
+               return NULL;
+       }
+
+#if 0
+       // Apply sampling parameters
+       fp->rmt_samp.method= samp_param->method;
+       fp->rmt_samp.value= samp_param->value;
+#endif
+
+       /*
+       We're in active mode if:
+       - we're using TCP, and the user wants us to be in active mode
+       - we're using UDP
+       */
+       serveropen_dp= (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || active;
+
+       /*
+       Gets the sockaddr structure referred to the other peer in the ctrl connection
+
+       We need that because:
+       - if we're in passive mode, we need to know the address family we want to use 
+       (the same used for the ctrl socket)
+       - if we're in active mode, we need to know the network address of the other host 
+       we want to connect to
+       */
+       saddrlen = sizeof(struct sockaddr_storage);
+       if (getpeername(sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
+       {
+               sock_geterror("getpeername(): ", errbuf, PCAP_ERRBUF_SIZE);
+               goto error;
+       }
+
+       memset(&hints, 0, sizeof(struct addrinfo) );
+       hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
+       hints.ai_family = saddr.ss_family;
+
+       // Now we have to create a new socket to send packets
+       if (serveropen_dp)              // Data connection is opened by the server toward the client
+       {
+               sprintf(portdata, "%d", ntohs(startcapreq.portdata) );
+
+               // Get the name of the other peer (needed to connect to that specific network address)
+               if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, peerhost, 
+                               sizeof(peerhost), NULL, 0, NI_NUMERICHOST) )
+               {
+                       sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       goto error;
+               }
+
+               if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+               if ( (sockdata= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1)
+                       goto error;
+       }
+       else            // Data connection is opened by the client toward the server
+       {
+               hints.ai_flags = AI_PASSIVE;
+
+               // Let's the server socket pick up a free network port for us
+               if (sock_initaddress(NULL, "0", &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+               if ( (sockdata= sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errbuf, PCAP_ERRBUF_SIZE)) == -1)
+                       goto error;
+
+               // get the complete sockaddr structure used in the data connection
+               saddrlen = sizeof(struct sockaddr_storage);
+               if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
+               {
+                       sock_geterror("getsockname(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       goto error;
+               }
+
+               // Get the local port the system picked up
+               if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, NULL, 
+                               0, portdata, sizeof(portdata), NI_NUMERICSERV) )
+               {
+                       sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       goto error;
+               }
+       }
+
+       // addrinfo is no longer used
+       freeaddrinfo(addrinfo);
+       addrinfo= NULL;
+
+       session->sockctrl = sockctrl;   // Needed to send an error on the ctrl connection
+
+       // Now I can set the filter
+       if ( daemon_unpackapplyfilter(session, &totread, &plen, errbuf) )
+               goto error;
+
+
+       // Now, I can send a RPCAP start capture reply message
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
+               RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply) );
+
+       startcapreply= (struct rpcap_startcapreply *) &sendbuf[sendbufidx];
+       
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL,
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       memset(startcapreply, 0, sizeof(struct rpcap_startcapreply) );
+       startcapreply->bufsize= htonl(pcap_bufsize(session->fp));
+
+       if (!serveropen_dp)
+       {
+               unsigned short port = (unsigned short)strtoul(portdata,NULL,10);
+               startcapreply->portdata= htons(port);
+       }
+
+       if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       if (!serveropen_dp)
+       {
+               SOCKET socktemp;        // We need another socket, since we're going to accept() a connection
+
+               // Connection creation
+               saddrlen = sizeof(struct sockaddr_storage);
+
+               socktemp= accept(sockdata, (struct sockaddr *) &saddr, &saddrlen);
+               
+               if (socktemp == -1)
+               {
+                       sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       goto error;
+               }
+
+               // Now that I accepted the connection, the server socket is no longer needed
+               sock_close(sockdata, errbuf, PCAP_ERRBUF_SIZE);
+               sockdata= socktemp;
+       }
+
+       session->sockdata = sockdata;
+
+       /* GV we need this to create the thread as detached. */
+       /* GV otherwise, the thread handle is not destroyed  */
+       pthread_attr_init(&detachedAttribute); 
+       pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
+       
+       // Now we have to create a new thread to receive packets
+       if ( pthread_create(threaddata, &detachedAttribute, (void *) daemon_thrdatamain, (void *) session) )
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
+               pthread_attr_destroy(&detachedAttribute);
+               goto error;
+       }
+
+       pthread_attr_destroy(&detachedAttribute);
+       // Check if all the data has been read; if not, discard the data in excess
+       if (totread != plen)
+               sock_discard(sockctrl, plen - totread, NULL, 0);
+
+       return session;
+
+error:
+       rpcap_senderror(sockctrl, errbuf, PCAP_ERR_STARTCAPTURE, NULL);
+
+       if (addrinfo)
+               freeaddrinfo(addrinfo);
+
+       if (threaddata)
+               pthread_cancel(*threaddata);
+
+       if (sockdata)
+               sock_close(sockdata, NULL, 0);
+
+       // Check if all the data has been read; if not, discard the data in excess
+       if (totread != plen)
+               sock_discard(sockctrl, plen - totread, NULL, 0);
+
+       if (session->fp)
+       {
+               pcap_close(session->fp);
+       }
+       free(session);
+
+       return NULL;
+}
+
+static int daemon_endcapture(struct session *session, pthread_t *threaddata, char *errbuf)
+{
+       struct rpcap_header header;
+
+       if (threaddata)
+       {
+               pthread_cancel(*threaddata);
+               threaddata= 0;
+       }
+       if (session->sockdata)
+       {
+               sock_close(session->sockdata, NULL, 0);
+               session->sockdata= 0;
+       }
+
+       pcap_close(session->fp);
+
+       rpcap_createhdr( &header, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
+
+       if ( sock_send(session->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
+               return -1;
+       
+       return 0;
+}
+
+static int daemon_unpackapplyfilter(struct session *session, uint32 *totread, uint32 *plen, char *errbuf)
+{
+       ssize_t nread;
+       struct rpcap_filter filter;
+       struct rpcap_filterbpf_insn insn;
+       struct bpf_insn *bf_insn;
+       struct bpf_program bf_prog;
+       unsigned int i;
+
+       nread = sock_recv(session->sockctrl, (char *) &filter,
+           sizeof(struct rpcap_filter), SOCK_RECEIVEALL_YES,
+           errbuf, PCAP_ERRBUF_SIZE);
+       if (nread == -1)
+       {
+               // to avoid blocking on the sock_discard()
+               *plen = *totread;
+               return -1;
+       }
+       *totread += nread;
+
+       bf_prog.bf_len= ntohl(filter.nitems);
+
+       if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
+               return -1;
+       }
+
+       bf_insn= (struct bpf_insn *) malloc ( sizeof(struct bpf_insn) * bf_prog.bf_len);
+       if (bf_insn == NULL)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
+               return -1;
+       }
+
+       bf_prog.bf_insns= bf_insn;
+
+       for (i= 0; i < bf_prog.bf_len; i++)
+       {
+               nread = sock_recv(session->sockctrl, (char *) &insn, 
+                   sizeof(struct rpcap_filterbpf_insn), SOCK_RECEIVEALL_YES,
+                   errbuf, PCAP_ERRBUF_SIZE);
+               if (nread == -1)
+                       return -1;
+               *totread += nread;
+
+               bf_insn->code= ntohs(insn.code);
+               bf_insn->jf= insn.jf;
+               bf_insn->jt= insn.jt;
+               bf_insn->k= ntohl(insn.k);
+
+               bf_insn++;
+       }
+
+       if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
+               return -1;
+       }
+
+       if (pcap_setfilter(session->fp, &bf_prog) )
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
+               return -1;
+       }
+
+       return 0;
+}
+
+int daemon_updatefilter(struct session *session, uint32 plen)
+{
+       struct rpcap_header header;                     // keeps the answer to the updatefilter command
+       unsigned int nread;
+
+       nread= 0;
+
+       if ( daemon_unpackapplyfilter(session, &nread, &plen, pcap_geterr(session->fp)) )
+               goto error;
+
+       // Check if all the data has been read; if not, discard the data in excess
+       if (nread != plen)
+       {
+               if (sock_discard(session->sockctrl, plen - nread, NULL, 0) )
+               {
+                       nread= plen;            // just to avoid to call discard again in the 'error' section
+                       goto error;
+               }
+       }
+
+       // A response is needed, otherwise the other host does not know that everything went well
+       rpcap_createhdr( &header, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
+
+       if ( sock_send(session->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) )
+               goto error;
+
+       return 0;
+
+
+error:
+       if (nread != plen)
+               sock_discard(session->sockctrl, plen - nread, NULL, 0);
+
+       rpcap_senderror(session->sockctrl, pcap_geterr(session->fp), PCAP_ERR_UPDATEFILTER, NULL);
+
+       return -1;
+}
+
+/*!
+       \brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
+*/
+int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf)
+{
+       struct rpcap_header header;
+       struct rpcap_sampling rpcap_samp;
+       int nread;                                      // number of bytes of the payload read from the socket
+
+       if ( ( nread= sock_recv(sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), 
+                       SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1)
+               goto error;
+
+
+       // Save these settings in the pcap_t 
+       samp_param->method= rpcap_samp.method;
+       samp_param->value= ntohl(rpcap_samp.value);
+
+
+       // A response is needed, otherwise the other host does not know that everything went well
+       rpcap_createhdr( &header, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
+
+       if ( sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) )
+               goto error;
+
+       if (nread != plen)
+               sock_discard(sockctrl, plen - nread, NULL, 0);
+
+       return 0;
+
+error:
+       if (nread != plen)
+               sock_discard(sockctrl, plen - nread, NULL, 0);
+
+       rpcap_senderror(sockctrl, errbuf, PCAP_ERR_SETSAMPLING, NULL);
+
+       return -1;
+}
+
+int daemon_getstats(struct session *session)
+{
+       char sendbuf[RPCAP_NETBUF_SIZE];        // temporary buffer in which data to be sent is buffered
+       int sendbufidx= 0;                                      // index which keeps the number of bytes currently buffered
+       struct pcap_stat stats;                         // local statistics
+       struct rpcap_stats *netstats;           // statistics sent on the network
+
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, 
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
+
+       netstats= (struct rpcap_stats *) &sendbuf[sendbufidx];
+
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL,
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       if (pcap_stats(session->fp, &stats) )
+               goto error;
+
+       netstats->ifdrop= htonl(stats.ps_ifdrop);
+       netstats->ifrecv= htonl(stats.ps_recv);
+       netstats->krnldrop= htonl(stats.ps_drop);
+       netstats->svrcapt= htonl(session->TotCapt);
+
+       // Send the packet
+       if ( sock_send(session->sockctrl, sendbuf, sendbufidx, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       return 0;
+
+error:
+       rpcap_senderror(session->sockctrl, pcap_geterr(session->fp), PCAP_ERR_GETSTATS, NULL);
+       return -1;
+}
+
+int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv, 
+                                                 unsigned int krnldrop, unsigned int svrcapt, char *errbuf)
+{
+       char sendbuf[RPCAP_NETBUF_SIZE];        // temporary buffer in which data to be sent is buffered
+       int sendbufidx= 0;                                      // index which keeps the number of bytes currently buffered
+       struct rpcap_stats *netstats;           // statistics sent on the network
+
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
+
+       netstats= (struct rpcap_stats *) &sendbuf[sendbufidx];
+
+       if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL,
+               &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       netstats->ifdrop= htonl(ifdrops);
+       netstats->ifrecv= htonl(ifrecv);
+       netstats->krnldrop= htonl(krnldrop);
+       netstats->svrcapt= htonl(svrcapt);
+
+       // Send the packet
+       if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               goto error;
+
+       return 0;
+
+error:
+       rpcap_senderror(sockctrl, errbuf, PCAP_ERR_GETSTATS, NULL);
+       return -1;
+}
+
+void *daemon_thrdatamain(void *ptr)
+{
+       char errbuf[PCAP_ERRBUF_SIZE + 1];      // error buffer
+       struct session *session;                // pointer to the struct session for this session
+       int retval;                                                     // general variable used to keep the return value of other functions
+       struct rpcap_pkthdr *net_pkt_header;// header of the packet
+       struct pcap_pkthdr *pkt_header;         // pointer to the buffer that contains the header of the current packet
+       u_char *pkt_data;                                       // pointer to the buffer that contains the current packet
+       char *sendbuf;                                          // temporary buffer in which data to be sent is buffered
+       int sendbufidx;                                         // index which keeps the number of bytes currently buffered
+
+       session = (struct session *) ptr;
+
+       session->TotCapt= 0;                    // counter which is incremented each time a packet is received
+
+       // Initialize errbuf
+       memset(errbuf, 0, sizeof(errbuf) );
+
+       // Some platforms (e.g. Win32) allow creating a static variable with this size
+       // However, others (e.g. BSD) do not, so we're forced to allocate this buffer dynamically
+       sendbuf= (char *) malloc (sizeof(char) * RPCAP_NETBUF_SIZE);
+       if (sendbuf == NULL)
+       {
+               snprintf(errbuf, sizeof(errbuf) - 1, "Unable to create the buffer for this child thread");
+               goto error;
+       }
+
+       // Modify thread params so that it can be killed at any time
+       if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) )
+               goto error;
+       if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) )
+               goto error;
+
+       // Retrieve the packets
+       while ((retval = pcap_next_ex(session->fp, &pkt_header, (const u_char **) &pkt_data)) >= 0)     // cast to avoid a compiler warning
+       {
+               if (retval == 0)        // Read timeout elapsed
+                       continue;
+
+               sendbufidx= 0;
+
+               // Bufferize the general header
+               if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
+                       RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+               rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_PACKET, 0,
+                       (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen) );
+
+               net_pkt_header= (struct rpcap_pkthdr *) &sendbuf[sendbufidx];
+
+               // Bufferize the pkt header
+               if ( sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, &sendbufidx,
+                       RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+               net_pkt_header->caplen= htonl(pkt_header->caplen);
+               net_pkt_header->len= htonl(pkt_header->len);
+               net_pkt_header->npkt= htonl( ++(session->TotCapt) );
+               net_pkt_header->timestamp_sec= htonl(pkt_header->ts.tv_sec);
+               net_pkt_header->timestamp_usec= htonl(pkt_header->ts.tv_usec);
+
+               // Bufferize the pkt data
+               if ( sock_bufferize((char *) pkt_data, pkt_header->caplen, sendbuf, &sendbufidx,
+                       RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+               // Send the packet
+               if ( sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
+                       goto error;
+
+       }
+
+       if (retval == -1)
+       {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp) );
+               rpcap_senderror(session->sockctrl, errbuf, PCAP_ERR_READEX, NULL);
+               goto error;
+       }
+
+error:
+
+       SOCK_ASSERT(errbuf, 1);
+       closesocket(session->sockdata);
+       session->sockdata = 0;
+
+       free(sendbuf);
+
+       return NULL;
+}
+
+/*!
+       \brief It serializes a network address.
+
+       It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format
+       that can be used to be sent on the network. Basically, it applies all the hton()
+       conversion required to the input variable.
+
+       \param sockaddrin: a 'sockaddr_storage' pointer to the variable that has to be
+       serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'.
+
+       \param sockaddrout: a 'sockaddr_storage' pointer to the variable that will contain
+       the serialized data. This variable has to be allocated by the user.
+
+       \return None
+
+       \warning This function supports only AF_INET and AF_INET6 address families.
+*/
+void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage *sockaddrout)
+{
+       memset(sockaddrout, 0, sizeof(struct sockaddr_storage) );
+
+       // There can be the case in which the sockaddrin is not available
+       if (sockaddrin == NULL) return;
+
+       // Warning: we support only AF_INET and AF_INET6
+       if (sockaddrin->ss_family == AF_INET)
+       {
+       struct sockaddr_in *sockaddr;
+
+               sockaddr= (struct sockaddr_in *) sockaddrin;
+               sockaddr->sin_family= htons(sockaddr->sin_family);
+               sockaddr->sin_port= htons(sockaddr->sin_port);
+               memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in) );
+       }
+       else
+       {
+       struct sockaddr_in6 *sockaddr;
+       
+               sockaddr= (struct sockaddr_in6 *) sockaddrin;
+               sockaddr->sin6_family= htons(sockaddr->sin6_family);
+               sockaddr->sin6_port= htons(sockaddr->sin6_port);
+               sockaddr->sin6_flowinfo= htonl(sockaddr->sin6_flowinfo);
+               sockaddr->sin6_scope_id= htonl(sockaddr->sin6_scope_id);
+               memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in6) );
+       }
+}
+
+/*!
+       \brief Suspends a pthread for msec milliseconds.
+
+       This function is provided since pthreads do not have a suspend() call.
+*/
+void pthread_suspend(int msec)
+{
+#ifdef _WIN32
+       Sleep(msec);
+#else
+       struct timespec abstime;
+       struct timeval now;
+
+       pthread_cond_t cond;
+       pthread_mutex_t mutex;
+       pthread_mutexattr_t attr;
+
+       pthread_mutexattr_init(&attr);
+       pthread_mutex_init(&mutex, &attr);
+       pthread_mutex_lock(&mutex);
+
+       pthread_cond_init(&cond, NULL);
+
+       gettimeofday(&now, NULL);
+       
+       abstime.tv_sec = now.tv_sec + msec/1000;
+       abstime.tv_nsec = now.tv_usec * 1000 + (msec%1000) * 1000 * 1000;
+
+       pthread_cond_timedwait(&cond, &mutex, &abstime);
+
+       pthread_mutex_destroy(&mutex);
+       pthread_cond_destroy(&cond);
+#endif
+}
+
+
+
diff --git a/rpcap/daemon.h b/rpcap/daemon.h
new file mode 100755 (executable)
index 0000000..1706d4d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 __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
+       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
+};
+
+
+void daemon_serviceloop( void *ptr );
+
+void pthread_suspend(int msec);
+
+#endif
+
diff --git a/rpcap/fileconf.c b/rpcap/fileconf.c
new file mode 100755 (executable)
index 0000000..28f1535
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *      The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <pcap.h>              // for PCAP_ERRBUF_SIZE
+
+#include "portability.h"
+#include "rpcapd.h"
+#include "fileconf.h"
+#include "sockutils.h"         // for SOCK_ASSERT
+#include "rpcap-protocol.h"
+
+static int strrem(char *string, char chr);
+
+void fileconf_read(int sign)
+{
+       FILE *fp;
+       char msg[PCAP_ERRBUF_SIZE + 1];
+       int i;
+
+#ifndef _WIN32
+       signal(SIGHUP, fileconf_read);
+#endif
+
+       if ((fp= fopen(loadfile, "r") ) != NULL)
+       {
+               char line[MAX_LINE + 1];
+               char *ptr;
+
+               hostlist[0]= 0;
+               i= 0;
+
+               while ( fgets(line, MAX_LINE, fp) != NULL )
+               {
+                       if (line[0] == '\n') continue;  // Blank line
+                       if (line[0] == '\r') continue;  // Blank line
+                       if (line[0] == '#') continue;   // Comment
+
+                       if ( (ptr = strstr(line, "ActiveClient")) )
+                       {
+                               char *address, *port;
+                               char *lasts;
+
+                               ptr = strchr(ptr, '=') + 1;
+                               address = pcap_strtok_r(ptr, RPCAP_HOSTLIST_SEP, &lasts);
+
+                               if ( (address != NULL) && (i < MAX_ACTIVE_LIST) )
+                               {
+                                       port = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
+                                       strlcpy(activelist[i].address, address, MAX_LINE);
+
+                                       if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port
+                                               strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
+                                       else
+                                               strlcpy(activelist[i].port, port, MAX_LINE);
+
+                                       activelist[i].address[MAX_LINE] = 0;
+                                       activelist[i].port[MAX_LINE] = 0;
+                               }
+                               else
+                                       SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
+
+                               i++;
+                               continue;
+                       }
+
+                       if ( (ptr= strstr(line, "PassiveClient")) )
+                       {
+                               ptr= strchr(ptr, '=') + 1;
+                               strlcat(hostlist, ptr, MAX_HOST_LIST);
+                               strlcat(hostlist, ",", MAX_HOST_LIST);
+                               continue;
+                       }
+
+                       if ( (ptr= strstr(line, "NullAuthPermit")) )
+                       {
+                               ptr= strstr(ptr, "YES");
+                               if (ptr)
+                                       nullAuthAllowed= 1;
+                               else
+                                       nullAuthAllowed= 0;
+                               continue;
+                       }
+               }
+
+               // clear the remaining fields of the active list 
+               while (i < MAX_ACTIVE_LIST)
+               {
+                       activelist[i].address[0] = 0;
+                       activelist[i].port[0] = 0;
+                       i++;
+               }
+
+               // Remove all '\n' and '\r' from the strings
+               strrem(hostlist, '\r');
+               strrem(hostlist, '\n');
+
+               pcap_snprintf(msg, PCAP_ERRBUF_SIZE, "New passive host list: %s\n\n", hostlist);
+               SOCK_ASSERT(msg, 1);
+               fclose(fp);
+       }
+}
+
+int fileconf_save(const char *savefile)
+{
+       FILE *fp;
+
+       if ((fp= fopen(savefile, "w") ) != NULL)
+       {
+               char *token; /*, *port;*/                                       // temp, needed to separate items into the hostlist
+               char temphostlist[MAX_HOST_LIST + 1];
+               int i = 0;
+               char *lasts;
+
+               fprintf(fp, "# Configuration file help.\n\n");
+
+               // Save list of clients which are allowed to connect to us in passive mode
+               fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n");
+               fprintf(fp, "# Format: PassiveClient = <name or address>\n\n");
+
+               strncpy(temphostlist, hostlist, MAX_HOST_LIST);
+               temphostlist[MAX_HOST_LIST]= 0;
+       
+               token = pcap_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts);
+               while( token != NULL )
+               {
+                       fprintf(fp, "PassiveClient = %s\n", token);
+                       token = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
+               }
+
+
+               // Save list of clients which are allowed to connect to us in active mode
+               fprintf(fp, "\n\n");
+               fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n");
+               fprintf(fp, "# Format: ActiveClient = <name or address>, <port | DEFAULT>\n\n");
+
+
+               while ( (activelist[i].address[0] != 0) && (i < MAX_ACTIVE_LIST) )
+               {
+                       fprintf(fp, "ActiveClient = %s, %s\n", activelist[i].address, activelist[i].port);
+                       i++;
+               }
+
+               // Save if we want to permit NULL authentication
+               fprintf(fp, "\n\n");
+               fprintf(fp, "# Permit NULL authentication: YES or NOT\n\n");
+
+               if (nullAuthAllowed)
+                       fprintf(fp, "NullAuthPermit = YES\n");
+               else
+                       fprintf(fp, "NullAuthPermit = NO\n");
+
+               fclose(fp);
+               return 0;
+       }
+       else
+       {
+               return -1;
+       }
+
+}
+
+static int strrem(char *string, char chr)
+{
+       char *pos;
+       int num= 0;
+       int len, i;
+
+       while ( (pos= strchr(string, chr) ) != NULL)
+       {
+               num++;
+               len= strlen(pos);
+               for (i=0; i<len; i++)
+                       pos[i]= pos[i+1];
+       }
+
+       return num;
+}
diff --git a/rpcap/fileconf.h b/rpcap/fileconf.h
new file mode 100755 (executable)
index 0000000..6ede57d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 __FILECONF_H__
+#define __FILECONF_H__
+
+
+void fileconf_read(int sign);
+int fileconf_save(const char *savefile);
+
+
+#endif
+
diff --git a/rpcap/rpcapd.c b/rpcap/rpcapd.c
new file mode 100755 (executable)
index 0000000..cd37eb1
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * 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.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>             // for the errno variable
+#include <string.h>            // for strtok, etc
+#include <stdlib.h>            // for malloc(), free(), ...
+#include <pcap.h>              // for PCAP_ERRBUF_SIZE
+#include <signal.h>            // for signal()
+#include <pthread.h>
+
+#include "portability.h"
+#include "rpcapd.h"
+#include "fileconf.h"  // for the configuration file management
+#include "sockutils.h"         // for socket calls
+#include "rpcap-protocol.h"
+#include "pcap-rpcap.h"
+#include "daemon.h"            // the true main() method of this daemon
+#include "utils.h"             // Missing calls and such
+
+#ifndef WIN32
+#include <unistd.h>            // for exit()
+#include <sys/wait.h>  // waitpid()
+#else
+#include "win32-svc.h" // for Win32 service stuff
+#endif
+
+
+// Global variables
+char hostlist[MAX_HOST_LIST + 1];              //!< Keeps the list of the hosts that are allowed to connect to this server
+struct active_pars activelist[MAX_ACTIVE_LIST];                //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
+int nullAuthAllowed;                                   //!< '1' if we permit NULL authentication, '0' otherwise
+static SOCKET sockmain;                                                //!< keeps the main socket identifier
+char loadfile[MAX_LINE + 1];                   //!< Name of the file from which we have to load the configuration
+int passivemode= 1;                                            //!< '1' if we want to run in passive mode as well
+struct addrinfo mainhints;                             //!< temporary struct to keep settings needed to open the new socket
+char address[MAX_LINE + 1];                            //!< keeps the network address (either numeric or literal) to bind to
+char port[MAX_LINE + 1];                               //!< keeps the network port to bind to
+
+extern char *optarg;   // for getopt()
+
+
+
+// Function definition
+void main_passive(void *ptr);
+void main_active(void *ptr);
+
+
+#ifndef WIN32
+void main_cleanup_childs(int sign);
+#endif
+
+#define RPCAP_ACTIVE_WAIT 30           /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
+
+
+/*!
+       \brief Prints the usage screen if it is launched in console mode.
+*/
+static void printusage(void)
+{
+       char *usagetext =
+       "USAGE:\n"
+       " "  PROGRAM_NAME " [-b <address>] [-p <port>] [-6] [-l <host_list>] [-a <host,port>]\n"
+       "        [-n] [-v] [-d] [-s <file>] [-f <file>]\n"
+       "  -b <address>: the address to bind to (either numeric or literal).\n"
+    "      Default: it binds to all local IPv4 addresses\n"
+       "  -p <port>: the port to bind to. Default: it binds to port " RPCAP_DEFAULT_NETPORT "\n"
+       "  -4: use only IPv4 (default both IPv4 and IPv6 waiting sockets are used)\n"
+       "  -l <host_list>: a file that keeps the list of the hosts which 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 order to\n"
+       "      avoid problems with different address families\n"
+       "  -n: permit NULL authentication (usually used with '-l')\n"
+       "  -a <host,port>: run in active mode when connecting to 'host' on port 'port'\n"
+       "      In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n"
+       "  -v: run in active mode only (default: if '-a' is specified, it accepts\n"
+       "      passive connections as well\n"
+       "  -d: run in daemon mode (UNIX only) or as a service (Win32 only)\n"
+       "      Warning (Win32): this switch is provided automatically when the service\n"
+       "      is started from the control panel\n"
+       "  -s <file>: save the current configuration to file\n"
+       "  -f <file>: load the current configuration from file; all the switches\n"
+       "      specified from the command line are ignored\n"
+    "  -h: print this help screen\n\n";
+
+       printf("%s", usagetext);
+}
+
+
+
+//! Program main
+int main(int argc, char *argv[], char *envp[])
+{
+char savefile[MAX_LINE + 1];           // name of the file on which we have to save the configuration
+int isdaemon= 0;                                       // Not null if the user wants to run this program as a daemon
+int retval;                                                    // keeps the returning value from several functions
+char errbuf[PCAP_ERRBUF_SIZE + 1];     // keeps the error string, prior to be printed
+
+
+       savefile[0]= 0;
+       loadfile[0]= 0;
+       hostlist[0]= 0;
+
+       // Initialize errbuf
+       memset(errbuf, 0, sizeof(errbuf) );
+
+       if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
+       {
+               SOCK_ASSERT(errbuf, 1);
+               exit(-1);
+       }
+
+       strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
+       strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
+
+       // Prepare to open a new server socket
+       memset(&mainhints, 0, sizeof(struct addrinfo));
+
+       mainhints.ai_family = PF_UNSPEC;
+       mainhints.ai_flags = AI_PASSIVE;        // Ready to a bind() socket
+       mainhints.ai_socktype = SOCK_STREAM;
+
+       // Getting the proper command line options
+       while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1)
+       {
+               switch (retval)
+               {
+                       case 'b':
+                               strncpy(address, optarg, MAX_LINE);
+                               break;
+                       case 'p':
+                               strncpy(port, optarg, MAX_LINE);
+                               break;
+                       case '4':
+                               mainhints.ai_family = PF_INET;          // IPv4 server only
+                               break;
+                       case 'd':
+                               isdaemon= 1;
+                               break;
+                       case 'n':
+                               nullAuthAllowed= 1;
+                               break;
+                       case 'v':
+                               passivemode= 0;
+                               break;
+                       case 'l':
+                       {
+                               strncpy(hostlist, optarg, sizeof(hostlist) );
+                               break;
+                       }
+                       case 'a':
+                       {
+                               char *tmpaddress, *tmpport;
+                               char *lasts;
+                               int i = 0;
+
+                               tmpaddress= pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
+
+                               while ( (tmpaddress != NULL) && (i < MAX_ACTIVE_LIST) )
+                               {
+                                       tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
+
+                                       strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
+                                       
+                                       if ( (tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0) ) // the user choose a custom port
+                                               strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
+                                       else
+                                               strlcpy(activelist[i].port, tmpport, MAX_LINE);
+
+                                       tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
+
+                                       i++;
+                               }
+                               
+                               if (i > MAX_ACTIVE_LIST)
+                                       SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
+
+                               // I don't initialize the remaining part of the structure, since
+                               // it is already zeroed (it is a global var)
+                               break;
+                       }
+                       case 'f':
+                               strlcpy(loadfile, optarg, MAX_LINE);
+                               break;
+                       case 's':
+                               strlcpy(savefile, optarg, MAX_LINE);
+                               break;
+                       case 'h':
+                               printusage();
+                               exit(0);
+                       default:
+                               break;
+               }
+       }
+
+       if (savefile[0])
+       {
+               if (fileconf_save(savefile) )
+                       SOCK_ASSERT("Error when saving the configuration to file", 1);
+       }
+
+       // If the file does not exist, it keeps the settings provided by the command line
+       if (loadfile[0])
+               fileconf_read(0);
+
+#ifdef linux
+       // SIGTERM (i.e. kill -15) is not generated in WIN32, although it is included for ANSI compatibility
+       signal(SIGTERM, main_cleanup);
+       signal(SIGCHLD, main_cleanup_childs);
+#endif
+
+       // forking a daemon, if it is needed
+       if (isdaemon)
+       {
+       #ifndef WIN32
+       int pid;
+
+               // Unix Network Programming, pg 336
+               if ( (pid = fork() ) != 0)
+                       exit(0);                // Parent terminates
+
+               // First child continues
+               // Set daemon mode
+               setsid();
+               
+               // generated under unix with 'kill -HUP', needed to reload the configuration
+               signal(SIGHUP, fileconf_read);
+
+               if ( (pid = fork() ) != 0)
+                       exit(0);                // First child terminates
+
+               // LINUX WARNING: the current linux implementation of pthreads requires a management thread
+               // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
+               // created. Fom this point on, the number of threads active are always one more compared
+               // to the number you're expecting
+
+               // Second child continues
+//             umask(0);
+//             chdir("/");
+       #else
+               // We use the SIGABRT signal to kill the Win32 service
+               signal(SIGABRT, main_cleanup);
+
+               // If this call succeeds, it is blocking on Win32
+               if ( svc_start() != 1)
+                       SOCK_ASSERT(1, "Unable to start the service");
+
+               // When the previous call returns, the entire application has to be stopped.
+               exit(0);
+       #endif
+       }
+       else    // Console mode
+       {
+               // Enable the catching of Ctrl+C
+               signal(SIGINT, main_cleanup);
+
+#ifndef WIN32
+               // generated under unix with 'kill -HUP', needed to reload the configuration
+               // We do not have this kind of signal in Win32
+               signal(SIGHUP, fileconf_read);
+#endif
+
+               printf("Press CTRL + C to stop the server...\n");
+       }
+
+       // If we're a Win32 service, we have already called this function in the service_main
+       main_startup();
+
+       // The code should never arrive here (since the main_startup is blocking)
+       //  however this avoids a compiler warning
+       exit(0);
+}
+
+
+
+void main_startup(void)
+{
+char errbuf[PCAP_ERRBUF_SIZE + 1];     // keeps the error string, prior to be printed
+struct addrinfo *addrinfo;                             // keeps the addrinfo chain; required to open a new socket
+int i;
+#ifdef WIN32
+       pthread_t threadId;                                     // Pthread variable that keeps the thread structures
+       pthread_attr_t detachedAttribute;       // PThread attribute needed to create the thread as detached
+#else
+       pid_t pid;
+#endif
+
+       i= 0;
+       addrinfo= NULL;
+       memset(errbuf, 0, sizeof(errbuf) );
+
+       // Starts all the active threads
+       while ( (activelist[i].address[0] != 0) && (i < MAX_ACTIVE_LIST) )
+       {
+               activelist[i].ai_family= mainhints.ai_family;
+               
+#ifdef WIN32
+               /* GV we need this to create the thread as detached. */
+               /* GV otherwise, the thread handle is not destroyed  */
+               pthread_attr_init(&detachedAttribute); 
+               pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
+
+               if ( pthread_create( &threadId, &detachedAttribute, (void *) &main_active, (void *) &activelist[i]) )
+               {
+                       SOCK_ASSERT("Error creating the active child thread", 1);
+                       pthread_attr_destroy(&detachedAttribute);
+                       continue;
+               }
+               pthread_attr_destroy(&detachedAttribute);
+#else
+               if ( (pid= fork() ) == 0)       // I am the child
+               {
+                       main_active( (void *) &activelist[i]);
+                       exit(0);
+               }
+#endif
+               i++;
+       }
+
+       /*
+               The code that manages the active connections is not blocking; 
+               vice versa, the code that manages the passive connection is blocking.
+               So, if the user do not want to run in passive mode, we have to block
+               the main thread here, otherwise the program ends and all threads
+               are stopped.
+
+               WARNING: this means that in case we have only active mode, the program does
+               not terminate even if all the child thread terminates. The user has always to
+               press Ctrl+C (or send a SIGTERM) to terminate the program.
+       */
+
+       if (passivemode)
+       {
+       struct addrinfo *tempaddrinfo;
+
+               // Do the work
+               if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
+               {
+                       SOCK_ASSERT(errbuf, 1);
+                       return;
+               }
+
+               tempaddrinfo= addrinfo;
+
+               while (tempaddrinfo)
+               {
+               SOCKET *socktemp;
+
+                       if ( (sockmain= sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == -1)
+                       {
+                               SOCK_ASSERT(errbuf, 1);
+                               tempaddrinfo= tempaddrinfo->ai_next;
+                               continue;
+                       }
+
+                       // This trick is needed in order to allow the child thread to save the 'sockmain' variable
+                       // withouth getting it overwritten by the sock_open, in case we want to open more than one waiting sockets
+                       // For instance, the pthread_create() will accept the socktemp variable, and it will deallocate immediately that variable
+                       socktemp= (SOCKET *) malloc (sizeof (SOCKET));
+                       if (socktemp == NULL)
+                               exit(0);
+
+                       *socktemp= sockmain;
+
+#ifdef WIN32
+                       /* GV we need this to create the thread as detached. */
+                       /* GV otherwise, the thread handle is not destroyed  */
+                       pthread_attr_init(&detachedAttribute); 
+                       pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
+
+                       if ( pthread_create( &threadId, &detachedAttribute, (void *) &main_passive, (void *) socktemp ) )
+                       {
+                               SOCK_ASSERT("Error creating the passive child thread", 1);
+                               pthread_attr_destroy(&detachedAttribute);
+                               continue;
+                       }
+
+                       pthread_attr_destroy(&detachedAttribute);
+#else
+                       if ( (pid= fork() ) == 0)       // I am the child
+                       {
+                               main_passive( (void *) socktemp);
+                               return;
+                       }
+#endif
+                       tempaddrinfo= tempaddrinfo->ai_next;
+               }
+
+               freeaddrinfo(addrinfo);
+       }
+
+       // All the previous calls are no blocking, so the main line of execution goes here
+       // and I have to avoid that the program terminates
+       while (1)
+               pthread_suspend(10*60*1000); // it wakes up every 10 minutes; it seems to me reasonable
+}
+
+
+/*
+       \brief Closes gracefully (more or less) the program.
+
+       This function is called:
+       - when we're running in console
+       - when we're running as a Win32 service (in case we press STOP)
+
+       It is not called when we are running as a daemon on UNIX, since
+       we do not define a signal in order to terminate gracefully the daemon.
+
+       This function makes a fast cleanup (it does not clean everything, as 
+       you can see from the fact that it uses kill() on UNIX), closes
+       the main socket, free winsock resources (on Win32) and exits the
+       program.
+*/
+void main_cleanup(int sign)
+{
+#ifndef WIN32
+       // Sends a KILL signal to all the processes
+       // that share the same process group (i.e. kills all the childs)
+       kill(0, SIGKILL);
+#endif
+
+       SOCK_ASSERT(PROGRAM_NAME " is closing.\n", 1);
+
+       // FULVIO (bug)
+       // Here we close only the latest 'sockmain' created; if we opened more than one waiting sockets, 
+       // only the latest one is closed correctly.
+       if (sockmain)
+               closesocket(sockmain);
+       sock_cleanup();
+
+       /*
+               This code is executed under the following conditions:
+               - SIGTERM: we're under UNIX, and the user kills us with 'kill -15' 
+               (no matter is we're a daemon or in a console mode)
+               - SIGINT: we're in console mode and the user sends us a Ctrl+C 
+               (SIGINT signal), no matter if we're UNIX or Win32
+
+               In all these cases, we have to terminate the program.
+               The case that still remains is if we're a Win32 service: in this case,
+               we're a child thread, and we want just to terminate ourself. This is because
+               the exit(0) will be invoked by the main thread, which is blocked waiting that
+               all childs terminates. We are forced to call exit from the main thread otherwise
+               the Win32 service control manager (SCM) does not work well.
+       */
+       if ( (sign == SIGTERM) || (sign == SIGINT) )
+               exit(0);
+       else
+               return;
+}
+
+
+
+#ifdef linux
+
+void main_cleanup_childs(int sign)
+{
+pid_t pid;
+int stat;
+
+       // For reference, Stevens, pg 128
+
+       while ( (pid= waitpid(-1, &stat, WNOHANG) ) > 0)
+               SOCK_ASSERT("Child terminated", 1);
+
+       return;
+}
+
+#endif
+
+
+
+
+
+/*!
+       \brief 'true' main of the program.
+
+       It must be in a separate function because:
+       - if we're in 'console' mode, we have to put the main thread waiting for a Ctrl+C
+       (in order to be able to stop everything)
+       - if we're in daemon mode, the main program must terminate and a new child must be 
+       created in order to create the daemon
+
+       \param ptr: it keeps the main socket handler (what's called 'sockmain' in the main() ), that
+       represents the socket used in the main connection. It is a 'void *' just because pthreads
+       want this format.
+*/
+void main_passive(void *ptr)
+{
+char errbuf[PCAP_ERRBUF_SIZE + 1];     // keeps the error string, prior to be printed
+SOCKET sockctrl;                               // keeps the socket ID for this control connection
+struct sockaddr_storage from;  // generic sockaddr_storage variable
+socklen_t fromlen;                             // keeps the length of the sockaddr_storage variable
+SOCKET sockmain;
+
+#ifndef WIN32
+       pid_t pid;
+#endif
+
+       sockmain= *((SOCKET *) ptr);
+
+       // Delete the pointer (which has been allocated in the main)
+       free(ptr);
+
+       // Initialize errbuf
+       memset(errbuf, 0, sizeof(errbuf) );
+
+       // main thread loop
+       while (1)
+       {
+#ifdef WIN32
+       pthread_t threadId;                                     // Pthread variable that keeps the thread structures
+       pthread_attr_t detachedAttribute;
+#endif
+       struct daemon_slpars *pars;                     // parameters needed by the daemon_serviceloop()
+
+               // Connection creation
+               fromlen = sizeof(struct sockaddr_storage);
+
+               sockctrl= accept(sockmain, (struct sockaddr *) &from, &fromlen);
+               
+               if (sockctrl == -1)
+               {
+                       // The accept() call can return this error when a signal is catched
+                       // In this case, we have simply to ignore this error code
+                       // Stevens, pg 124
+#ifdef WIN32
+                       if (WSAGetLastError() == WSAEINTR)
+#else
+                       if (errno == EINTR)
+#endif
+                               continue;
+
+                       // Don't check for errors here, since the error can be due to the fact that the thread 
+                       // has been killed
+                       sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
+                       SOCK_ASSERT(errbuf, 1);
+                       continue;
+               }
+
+               // checks if the connecting host is among the ones allowed
+               if (sock_check_hostlist(hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0 )
+               {
+                       rpcap_senderror(sockctrl, errbuf, PCAP_ERR_HOSTNOAUTH, NULL);
+                       sock_close(sockctrl, NULL, 0);
+                       continue;
+               }
+
+
+#ifdef WIN32
+               // 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)
+               {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
+                       continue;
+               }
+
+               pars->sockctrl= sockctrl;
+               pars->activeclose= 0;           // useless in passive mode
+               pars->isactive= 0;
+               pars->nullAuthAllowed= nullAuthAllowed;
+
+               /* GV we need this to create the thread as detached. */
+               /* GV otherwise, the thread handle is not destroyed  */
+               pthread_attr_init(&detachedAttribute); 
+               pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
+               if ( pthread_create( &threadId, &detachedAttribute, (void *) &daemon_serviceloop, (void *) pars) )
+               {
+                       SOCK_ASSERT("Error creating the child thread", 1);
+                       pthread_attr_destroy(&detachedAttribute);
+                       continue;
+               }
+               pthread_attr_destroy(&detachedAttribute);
+
+#else
+               if ( (pid= fork() ) == 0)       // I am the child
+               {
+                       // 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)
+                       {
+                               snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
+                               exit(0);
+                       }
+
+                       pars->sockctrl= sockctrl;
+                       pars->activeclose= 0;           // useless in passive mode
+                       pars->isactive= 0;
+                       pars->nullAuthAllowed= nullAuthAllowed;
+
+                       // Close the main socket (must be open only in the parent)
+                       closesocket(sockmain);
+
+                       daemon_serviceloop( (void *) pars);
+                       exit(0);
+               }
+
+               // I am the parent
+               // Close the childsocket (must be open only in the child)
+               closesocket(sockctrl);
+#endif
+
+               // loop forever, until interrupted
+       }
+}
+
+
+
+
+/*!
+       \brief 'true' main of the program in case the active mode is turned on.
+
+       It does not have any return value nor parameters.
+       This function loops forever trying to connect to the remote host, until the
+       daemon is turned down.
+
+       \param ptr: it keeps the 'activepars' parameters. It is a 'void *' just because pthreads
+       want this format.
+*/
+void main_active(void *ptr)
+{
+char errbuf[PCAP_ERRBUF_SIZE + 1];     // keeps the error string, prior to be printed
+SOCKET sockctrl;                                       // keeps the socket ID for this control connection
+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;
+
+       // Prepare to open a new server socket
+       memset(&hints, 0, sizeof(struct addrinfo));
+                                                                       // WARNING Currently it supports only ONE socket family among IPv4 and IPv6 
+       hints.ai_family = AF_INET;              // PF_UNSPEC to have both IPv4 and IPv6 server
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_family= activepars->ai_family;
+
+       snprintf(errbuf, PCAP_ERRBUF_SIZE, "Connecting to host %s, port %s, using protocol %s",
+                       activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": 
+                       (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
+       SOCK_ASSERT(errbuf, 1);
+
+       // Initialize errbuf
+       memset(errbuf, 0, sizeof(errbuf) );
+
+       // Do the work
+       if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
+       {
+               SOCK_ASSERT(errbuf, 1);
+               return;
+       }
+
+       while (1)
+       {
+       int activeclose;
+
+               if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1)
+               {
+                       SOCK_ASSERT(errbuf, 1);
+
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
+                                       activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": 
+                                       (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified" );
+
+                       SOCK_ASSERT(errbuf, 1);
+
+                       pthread_suspend(RPCAP_ACTIVE_WAIT * 1000);
+
+                       continue;
+               }
+
+               pars= (struct daemon_slpars *) malloc ( sizeof(struct daemon_slpars) );
+               if (pars == NULL)
+               {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
+                       continue;
+               }
+
+               pars->sockctrl= sockctrl;
+               pars->activeclose= 0;
+               pars->isactive= 1;
+               pars->nullAuthAllowed= nullAuthAllowed;
+
+               daemon_serviceloop( (void *) pars);
+
+               activeclose= pars->activeclose;
+
+               free(pars);
+
+               // If the connection is closed by the user explicitely, don't try to connect to it again
+               // just exit the program
+               if (activeclose == 1)
+                       break;
+       }
+}
+
diff --git a/rpcap/rpcapd.h b/rpcap/rpcapd.h
new file mode 100755 (executable)
index 0000000..1f5996c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 __RPCAPD_H__
+#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
+
+void main_startup(void);
+void main_cleanup(int sign);
+
+#endif
+
diff --git a/rpcap/utils.c b/rpcap/utils.c
new file mode 100755 (executable)
index 0000000..e3149d7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *      The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+// getopt() is not present in Win32
+
+#ifdef WIN32
+#include <stdio.h>
+#include <string.h>                            // for getc()
+
+int     opterr = 1,             /* if error message should be printed */
+        optind = 1,             /* index into parent argv vector */
+        optopt,                 /* character checked for validity */
+        optreset;               /* reset getopt */
+char    *optarg;                /* argument associated with option */
+
+#define BADCH   (int)'?'
+#define BADARG  (int)':'
+#define EMSG    ""
+
+#ifdef WIN32
+char *__progname = "rpcapd";
+#endif
+
+/*
+ * getopt --
+ *      Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+        int nargc;
+        char * const *nargv;
+        const char *ostr;
+{
+// WIN32        extern char *__progname;
+        static char *place = EMSG;              /* option letter processing */
+        char *oli;                              /* option letter list index */
+        int ret;
+
+        if (optreset || !*place) {              /* update scanning pointer */
+                optreset = 0;
+                if (optind >= nargc || *(place = nargv[optind]) != '-') {
+                        place = EMSG;
+                        return (-1);
+                }
+                if (place[1] && *++place == '-') {      /* found "--" */
+                        ++optind;
+                        place = EMSG;
+                        return (-1);
+                }
+        }                                       /* option letter okay? */
+        if ((optopt = (int)*place++) == (int)':' ||
+            !(oli = strchr(ostr, optopt))) {
+                /*
+                 * if the user didn't specify '-' as an option,
+                 * assume it means -1.
+                 */
+                if (optopt == (int)'-')
+                        return (-1);
+                if (!*place)
+                        ++optind;
+                if (opterr && *ostr != ':' && optopt != BADCH)
+                        (void)fprintf(stderr,
+                            "%s: illegal option -- %c\n", __progname, optopt);
+                return (BADCH);
+        }
+        if (*++oli != ':') {                    /* don't need argument */
+                optarg = NULL;
+                if (!*place)
+                        ++optind;
+        }
+        else {                                  /* need an argument */
+                if (*place)                     /* no white space */
+                        optarg = place;
+                else if (nargc <= ++optind) {   /* no arg */
+                        place = EMSG;
+                        if (*ostr == ':')
+                                ret = BADARG;
+                        else
+                                ret = BADCH;
+                        if (opterr)
+                                (void)fprintf(stderr,
+                                    "%s: option requires an argument -- %c\n",
+                                    __progname, optopt);
+                        return (ret);
+                }
+                else                            /* white space */
+                        optarg = nargv[optind];
+                place = EMSG;
+                ++optind;
+        }
+        return (optopt);                        /* dump back option letter */
+}
+
+#endif
+
diff --git a/rpcap/utils.h b/rpcap/utils.h
new file mode 100755 (executable)
index 0000000..4d48d18
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 __UTILS_H__
+#define __UTILS_H__
+
+
+// Common functions declaration
+
+#ifdef WIN32
+       int getopt(int nargc, char * const *nargv, const char *ostr);
+#endif
+
+
+#endif
+
diff --git a/rpcap/win32-svc.c b/rpcap/win32-svc.c
new file mode 100755 (executable)
index 0000000..1a60ddc
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ * notice, this list of conditions and the following disclaimer in the 
+ * documentation and/or other materials provided with the distribution. 
+ * 3. Neither the name of the Politecnico di Torino nor the names of its 
+ * contributors may be used to endorse or promote products derived from 
+ * this software without specific prior written permission. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ */
+
+
+#include "rpcapd.h"
+#include <signal.h>
+#define        _WINSOCKAPI_
+#include "windows.h"
+#include <pcap.h>              // for PCAP_ERRBUF_SIZE
+#include "sockutils.h" // for SOCK_ASSERT
+#include "fileconf.h"
+
+
+SERVICE_STATUS_HANDLE service_status_handle;
+SERVICE_STATUS service_status;
+
+
+void svc_geterr(char *str);
+void WINAPI svc_main(DWORD argc, char **argv);
+
+
+
+int svc_start(void)
+{
+       int rc;
+       SERVICE_TABLE_ENTRY ste[] =
+       {
+               { PROGRAM_NAME, svc_main },
+               { NULL, NULL }
+       };
+
+       // This call is blocking. A new thread is created which will launch
+       // the svc_main() function
+       if ( (rc = StartServiceCtrlDispatcher(ste)) == 0)
+               svc_geterr("StartServiceCtrlDispatcher()");
+
+       return rc; // FALSE if this is not started as a service
+}
+
+
+void svc_geterr(char *str)
+{
+char message[PCAP_ERRBUF_SIZE];
+char string[PCAP_ERRBUF_SIZE];
+int val;
+
+       val= GetLastError();
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
+                                 FORMAT_MESSAGE_MAX_WIDTH_MASK,
+                                 NULL, val, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                                 (LPSTR) string, PCAP_ERRBUF_SIZE, NULL);
+
+       snprintf(message, PCAP_ERRBUF_SIZE, "%s failed with error %d: %s", str, val, string);
+
+       SOCK_ASSERT(message, 1);
+}
+
+
+
+void WINAPI svc_control_handler(DWORD Opcode)
+{
+       service_status.dwWin32ExitCode= 0;
+       service_status.dwCheckPoint= 0;
+       service_status.dwWaitHint= 0;
+
+       switch(Opcode)
+       {
+               case SERVICE_CONTROL_STOP:
+                       service_status.dwCurrentState= SERVICE_STOPPED;
+
+                       /*
+                               Uses ABORT to clean up the service. To be really honest, only the main socket and 
+                               such these stuffs are cleared; however the thread which are running are not stopped.
+                               This can be seen by placing a breakpoint at the end of svc_main(), in which you will 
+                               see that is never reached. However, as soon as you set the service status to "stopped",
+                               the StartServiceCtrlDispatcher() returns and the main thread ends. Then, Win32 has a good
+                               authomatic cleanup, so that all the threads which are still running are stopped
+                               when the main thread ends.
+                       */
+                       raise(SIGABRT);
+
+                       SetServiceStatus(service_status_handle, &service_status);
+                       break;
+
+               /*
+                       Pause and Continue have an usual meaning and they are used just to be able
+                       to change the running parameters at run-time. In other words, they act
+                       like the SIGHUP signal on UNIX. All the running threads continue to run and
+                       they are not paused at all.
+                       Particularly,
+                       - PAUSE does nothing
+                       - CONTINUE re-reads the configuration file and creates the new threads that
+                       can be needed according to the new configuration.
+               */
+               case SERVICE_CONTROL_PAUSE:
+                       service_status.dwCurrentState= SERVICE_PAUSED;
+                       SetServiceStatus(service_status_handle, &service_status);
+                       break;
+               
+               case SERVICE_CONTROL_CONTINUE:
+                       service_status.dwCurrentState= SERVICE_RUNNING;
+                       SetServiceStatus(service_status_handle, &service_status);
+                       fileconf_read(0);
+                       break;
+
+               case SERVICE_CONTROL_INTERROGATE:
+                       // Fall through to send current status.
+                       //      WARNING: not implemented
+                       SetServiceStatus(service_status_handle, &service_status);
+                       MessageBox(NULL, "Not implemented", "warning", MB_OK);
+                       break;
+       }
+
+       // Send current status.
+       return;
+}
+
+
+
+void WINAPI svc_main(DWORD argc, char **argv)
+{
+       service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler);
+
+       if (!service_status_handle)
+               return;
+
+       service_status.dwServiceType= SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
+       service_status.dwCurrentState= SERVICE_RUNNING;
+       service_status.dwControlsAccepted= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
+       // | SERVICE_ACCEPT_SHUTDOWN ;
+       service_status.dwWin32ExitCode= 0;
+       service_status.dwServiceSpecificExitCode= 0;
+       service_status.dwCheckPoint= 0;
+       service_status.dwWaitHint= 0;
+
+       SetServiceStatus(service_status_handle, &service_status);
+
+       main_startup();
+}
+
+/*
+sc create rpcapd DisplayName= "Remote Packet Capture Protocol v.0 (experimental)" binpath= "C:\cvsroot\winpcap\wpcap\PRJ\Debug\rpcapd -d -f rpcapd.ini"
+sc description rpcapd "Allows to capture traffic on this host from a remote machine."
+*/
\ No newline at end of file